This commit is contained in:
RedKale
2016-03-31 18:40:13 +08:00
parent 06f182b170
commit e050c7438d
194 changed files with 31002 additions and 0 deletions

View File

@@ -0,0 +1,656 @@
/*
* 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.boot;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.util.AnyValue.DefaultAnyValue;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.xml.parsers.*;
import org.redkale.convert.bson.*;
import org.redkale.convert.json.*;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
import org.redkale.watch.*;
import org.w3c.dom.*;
/**
* 编译时需要加入: -XDignore.symbol.file=true
* <p>
* 进程启动类程序启动后读取application.xml,进行classpath扫描动态加载Service与Servlet
* 优先加载所有SNCP协议的服务 再加载其他协议服务,
* 最后进行Service、Servlet与其他资源之间的依赖注入。
*
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public final class Application {
//当前进程启动的时间, 类型: long
public static final String RESNAME_APP_TIME = "APP_TIME";
//当前进程的根目录, 类型String、File、Path
public static final String RESNAME_APP_HOME = "APP_HOME";
//application.xml 文件中resources节点的内容 类型: AnyValue
public static final String RESNAME_APP_GRES = "APP_GRES";
//当前进程节点的name 类型String
public static final String RESNAME_APP_NODE = "APP_NODE";
//当前进程节点的IP地址 类型InetAddress、String
public static final String RESNAME_APP_ADDR = "APP_ADDR";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
//当前SNCP Server所属的组 类型: String
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
//当前Server的ROOT目录 类型String、File、Path
public static final String RESNAME_SERVER_ROOT = Server.RESNAME_SERVER_ROOT;
final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
final Map<String, Set<InetSocketAddress>> globalGroups = new HashMap<>();
final Map<String, String> globalGroupProtocols = new HashMap<>();
final InetAddress localAddress;
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
final List<DataSource> dataSources = new CopyOnWriteArrayList<>();
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
CountDownLatch servicecdl; //会出现两次赋值
final ObjectPool<ByteBuffer> transportBufferPool;
final ExecutorService transportExecutor;
final AsynchronousChannelGroup transportChannelGroup;
final ResourceFactory resourceFactory = ResourceFactory.root();
//--------------------------------------------------------------------------------------------
private final boolean singletonrun;
private final WatchFactory watchFactory = WatchFactory.root();
private final File home;
private final Logger logger;
private final AnyValue config;
private final long startTime = System.currentTimeMillis();
private final CountDownLatch serversLatch;
private Application(final AnyValue config) {
this(false, config);
}
private Application(final boolean singletonrun, final AnyValue config) {
this.singletonrun = singletonrun;
this.config = config;
final File root = new File(System.getProperty(RESNAME_APP_HOME));
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);
try {
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
this.home = root.getCanonicalFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
String localaddr = config.getValue("address", "").trim();
this.localAddress = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
this.resourceFactory.register(RESNAME_APP_ADDR, this.localAddress.getHostAddress());
this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress);
{
String node = config.getValue("node", "").trim();
if (node.isEmpty()) {
StringBuilder sb = new StringBuilder();
byte[] bs = this.localAddress.getAddress();
int v1 = bs[bs.length - 2] & 0xff;
int v2 = bs[bs.length - 1] & 0xff;
if (v1 <= 0xf) sb.append('0');
sb.append(Integer.toHexString(v1));
if (v2 <= 0xf) sb.append('0');
sb.append(Integer.toHexString(v2));
node = sb.toString();
}
this.resourceFactory.register(RESNAME_APP_NODE, node);
System.setProperty(RESNAME_APP_NODE, node);
}
//以下是初始化日志配置
final File logconf = new File(root, "conf/logging.properties");
if (logconf.isFile() && logconf.canRead()) {
try {
final String rootpath = root.getCanonicalPath().replace('\\', '/');
FileInputStream fin = new FileInputStream(logconf);
Properties properties = new Properties();
properties.load(fin);
fin.close();
properties.entrySet().stream().forEach(x -> {
x.setValue(x.getValue().toString().replace("${APP_HOME}", rootpath));
});
if (properties.getProperty("java.util.logging.FileHandler.formatter") == null) {
properties.setProperty("java.util.logging.FileHandler.formatter", LogFileHandler.LoggingFormater.class.getName());
}
if (properties.getProperty("java.util.logging.ConsoleHandler.formatter") == null) {
properties.setProperty("java.util.logging.ConsoleHandler.formatter", LogFileHandler.LoggingFormater.class.getName());
}
String fileHandlerPattern = properties.getProperty("java.util.logging.FileHandler.pattern");
if (fileHandlerPattern != null && fileHandlerPattern.contains("%d")) {
final String fileHandlerClass = LogFileHandler.class.getName();
Properties prop = new Properties();
final String handlers = properties.getProperty("handlers");
if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler", fileHandlerClass));
}
if (!prop.isEmpty()) {
String prefix = fileHandlerClass + ".";
properties.entrySet().stream().forEach(x -> {
if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) {
prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue());
}
});
prop.entrySet().stream().forEach(x -> {
properties.put(x.getKey(), x.getValue());
});
}
properties.put(SncpClient.class.getSimpleName() + ".handlers", LogFileHandler.SncpLogFileHandler.class.getName());
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out);
properties.forEach((x, y) -> ps.println(x + "=" + y));
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (Exception e) {
Logger.getLogger(this.getClass().getSimpleName()).log(Level.WARNING, "init logger configuration error", e);
}
}
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
//------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null;
AsynchronousChannelGroup transportGroup = null;
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
AnyValue transportConf = resources.getAnyValue("transport");
int groupsize = resources.getAnyValues("group").length;
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
if (transportConf != null) {
//--------------transportBufferPool-----------
AtomicLong createBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watchFactory == null ? new AtomicLong() : watchFactory.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.cycleCounter");
final int bufferCapacity = transportConf.getIntValue("bufferCapacity", 8 * 1024);
final int bufferPoolSize = transportConf.getIntValue("bufferPoolSize", groupsize * Runtime.getRuntime().availableProcessors() * 8);
final int threads = transportConf.getIntValue("threads", groupsize * Runtime.getRuntime().availableProcessors() * 8);
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
e.clear();
return true;
});
//-----------transportChannelGroup--------------
try {
final AtomicInteger counter = new AtomicInteger();
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-Thread-" + counter.incrementAndGet());
return t;
});
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
}
}
this.transportBufferPool = transportPool;
this.transportExecutor = transportExec;
this.transportChannelGroup = transportGroup;
}
public ResourceFactory getResourceFactory() {
return resourceFactory;
}
public WatchFactory getWatchFactory() {
return watchFactory;
}
public File getHome() {
return home;
}
public long getStartTime() {
return startTime;
}
private void initLogging() {
}
public void init() throws Exception {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
System.setProperty("convert.bson.tiny", "true");
System.setProperty("convert.json.tiny", "true");
System.setProperty("convert.bson.pool.size", "128");
System.setProperty("convert.json.pool.size", "128");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
File persist = new File(this.home, "conf/persistence.xml");
final String homepath = this.home.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataDefaultSource.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
Server.loadLib(logger, lib);
initLogging();
//------------------------------------------------------------------------
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources);
final AnyValue properties = resources.getAnyValue("properties");
if (properties != null) {
String dfloads = properties.getValue("load");
if (dfloads != null) {
for (String dfload : dfloads.split(";")) {
if (dfload.trim().isEmpty()) continue;
dfload = dfload.trim().replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
final File df = (dfload.indexOf('/') < 0) ? new File(home, "conf/" + dfload) : new File(dfload);
if (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));
}
}
}
for (AnyValue prop : properties.getAnyValues("property")) {
String name = prop.getValue("name");
String value = prop.getValue("value");
if (name == null || value == null) continue;
if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) {
MimeType.add(name.substring("mimetype.property.".length()), value);
} else {
resourceFactory.register("property." + name, value);
}
}
}
}
if (this.localAddress != null && this.resourceFactory.find("property.datasource.nodeid", String.class) == null) {
byte[] bs = this.localAddress.getAddress();
int v = (0xff & bs[bs.length - 2]) % 10 * 100 + (0xff & bs[bs.length - 1]);
this.resourceFactory.register("property.datasource.nodeid", "" + v);
}
this.resourceFactory.register(BsonFactory.root());
this.resourceFactory.register(JsonFactory.root());
this.resourceFactory.register(BsonFactory.root().getConvert());
this.resourceFactory.register(JsonFactory.root().getConvert());
initResources();
}
private void initResources() throws Exception {
//-------------------------------------------------------------------------
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
//------------------------------------------------------------------------
for (AnyValue conf : resources.getAnyValues("group")) {
final String group = conf.getValue("name", "");
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
}
Set<InetSocketAddress> addrs = globalGroups.get(group);
if (addrs == null) {
addrs = new LinkedHashSet<>();
globalGroupProtocols.put(group, protocol);
globalGroups.put(group, addrs);
}
for (AnyValue node : conf.getAnyValues("node")) {
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
addrs.add(addr);
String oldgroup = globalNodes.get(addr);
if (oldgroup != null) throw new RuntimeException(addr + " had one more group " + (globalNodes.get(addr)));
globalNodes.put(addr, group);
}
}
}
//------------------------------------------------------------------------
}
private void startSelfServer() throws Exception {
final Application application = this;
new Thread() {
{
setName("Application-Control-Thread");
}
@Override
public void run() {
try {
final DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.socket().setSoTimeout(3000);
channel.bind(new InetSocketAddress(config.getValue("host", "127.0.0.1"), config.getIntValue("port")));
boolean loop = true;
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (loop) {
buffer.clear();
SocketAddress address = channel.receive(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
if ("SHUTDOWN".equalsIgnoreCase(new String(bytes))) {
try {
long s = System.currentTimeMillis();
logger.info(application.getClass().getSimpleName() + " shutdowning");
application.shutdown();
buffer.clear();
buffer.put("SHUTDOWN OK".getBytes());
buffer.flip();
channel.send(buffer, address);
long e = System.currentTimeMillis() - s;
logger.info(application.getClass().getSimpleName() + " shutdown in " + e + " ms");
application.serversLatch.countDown();
System.exit(0);
} catch (Exception ex) {
logger.log(Level.INFO, "SHUTDOWN FAIL", ex);
buffer.clear();
buffer.put("SHUTDOWN FAIL".getBytes());
buffer.flip();
channel.send(buffer, address);
}
}
}
} catch (Exception e) {
logger.log(Level.INFO, "Control fail", e);
System.exit(1);
}
}
}.start();
}
private void sendShutDown() throws Exception {
final DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.connect(new InetSocketAddress(config.getValue("host", "127.0.0.1"), config.getIntValue("port")));
ByteBuffer buffer = ByteBuffer.allocate(128);
buffer.put("SHUTDOWN".getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
channel.configureBlocking(false);
channel.read(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
channel.close();
logger.info(new String(bytes));
Thread.sleep(500);
}
public void start() throws Exception {
final AnyValue[] entrys = config.getAnyValues("server");
CountDownLatch timecd = new CountDownLatch(entrys.length);
final List<AnyValue> sncps = new ArrayList<>();
final List<AnyValue> others = new ArrayList<>();
for (final AnyValue entry : entrys) {
if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) {
sncps.add(entry);
} else {
others.add(entry);
}
}
//单向SNCP服务不需要对等group
//if (!sncps.isEmpty() && globalNodes.isEmpty()) throw new RuntimeException("found SNCP Server node but not found <group> node info.");
runServers(timecd, sncps); //必须确保sncp都启动后再启动其他协议
runServers(timecd, others);
timecd.await();
logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms");
if (!singletonrun) this.serversLatch.await();
}
@SuppressWarnings("unchecked")
private void runServers(CountDownLatch timecd, final List<AnyValue> serconfs) throws Exception {
this.servicecdl = new CountDownLatch(serconfs.size());
CountDownLatch sercdl = new CountDownLatch(serconfs.size());
final AtomicBoolean inited = new AtomicBoolean(false);
final Map<String, Class<? extends NodeServer>> nodeClasses = new HashMap<>();
for (final AnyValue serconf : serconfs) {
Thread thread = new Thread() {
{
String host = serconf.getValue("host", "").replace("0.0.0.0", "[0]");
setName(serconf.getValue("protocol", "Server").toUpperCase() + "-" + host + ":" + serconf.getIntValue("port") + "-Thread");
this.setDaemon(true);
}
@Override
public void run() {
try {
//Thread ctd = Thread.currentThread();
//ctd.setContextClassLoader(new URLClassLoader(new URL[0], ctd.getContextClassLoader()));
final String protocol = serconf.getValue("protocol", "").replaceFirst("\\..+", "").toUpperCase();
NodeServer server = null;
if ("SNCP".equals(protocol)) {
server = new NodeSncpServer(Application.this, serconf);
} else if ("HTTP".equals(protocol)) {
server = new NodeHttpServer(Application.this, serconf);
} else {
if (!inited.get()) {
synchronized (nodeClasses) {
if (!inited.get()) {
inited.set(true);
ClassFilter profilter = new ClassFilter(NodeProtocol.class, NodeServer.class);
ClassFilter.Loader.load(home, profilter);
final Set<FilterEntry<NodeServer>> entrys = profilter.getFilterEntrys();
for (FilterEntry<NodeServer> entry : entrys) {
final Class<? extends NodeServer> type = entry.getType();
NodeProtocol pros = type.getAnnotation(NodeProtocol.class);
for (String p : pros.value()) {
p = p.toUpperCase();
if ("SNCP".equals(p) || "HTTP".equals(p)) continue;
final Class<? extends NodeServer> old = nodeClasses.get(p);
if (old != null && old != type) throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")");
nodeClasses.put(p, type);
}
}
}
}
}
Class<? extends NodeServer> nodeClass = nodeClasses.get(protocol);
if (nodeClass != null) server = NodeServer.create(nodeClass, Application.this, serconf);
}
if (server == null) {
logger.log(Level.SEVERE, "Not found Server Class for protocol({0})", serconf.getValue("protocol"));
System.exit(0);
}
servers.add(server);
server.init(serconf);
if (!singletonrun) server.start();
timecd.countDown();
sercdl.countDown();
} catch (Exception ex) {
logger.log(Level.WARNING, serconf + " runServers error", ex);
Application.this.serversLatch.countDown();
}
}
};
thread.start();
}
sercdl.await();
}
public static <T extends Service> T singleton(Class<T> serviceClass) throws Exception {
return singleton("", serviceClass);
}
public static <T extends Service> T singleton(String name, Class<T> serviceClass) throws Exception {
final Application application = Application.create(true);
application.init();
application.start();
for (NodeServer server : application.servers) {
T service = server.resourceFactory.find(name, serviceClass);
if (service != null) return service;
}
return null;
}
private static Application create(final boolean singleton) throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath();
System.setProperty(RESNAME_APP_HOME, home);
File appfile = new File(home, "conf/application.xml");
return new Application(singleton, load(new FileInputStream(appfile)));
}
public static void main(String[] args) throws Exception {
Utility.midnight(); //先初始化一下Utility
//运行主程序
final Application application = Application.create(false);
if (System.getProperty("SHUTDOWN") != null) {
application.sendShutDown();
return;
}
application.init();
application.startSelfServer();
try {
application.start();
} catch (Exception e) {
application.logger.log(Level.SEVERE, "Application start error", e);
System.exit(0);
}
System.exit(0);
}
Set<String> findSncpGroups(Transport sameGroupTransport, Collection<Transport> diffGroupTransports) {
Set<String> gs = new HashSet<>();
if (sameGroupTransport != null) gs.add(sameGroupTransport.getName());
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
gs.add(t.getName());
}
}
return gs;
}
NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) {
for (NodeServer node : servers) {
if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) {
return (NodeSncpServer) node;
}
}
return null;
}
String findGroupProtocol(String group) {
if (group == null) return null;
return globalGroupProtocols.get(group);
}
Set<InetSocketAddress> findGlobalGroup(String group) {
if (group == null) return null;
Set<InetSocketAddress> set = globalGroups.get(group);
return set == null ? null : new LinkedHashSet<>(set);
}
private void shutdown() throws Exception {
servers.stream().forEach((server) -> {
try {
server.shutdown();
} catch (Exception t) {
logger.log(Level.WARNING, " shutdown server(" + server.getSocketAddress() + ") error", t);
} finally {
serversLatch.countDown();
}
});
for (DataSource source : dataSources) {
try {
source.getClass().getMethod("close").invoke(source);
} catch (Exception e) {
logger.log(Level.FINER, "close DataSource erroneous", e);
}
}
for (CacheSource source : cacheSources) {
try {
source.getClass().getMethod("close").invoke(source);
} catch (Exception e) {
logger.log(Level.FINER, "close CacheSource erroneous", e);
}
}
if (this.transportChannelGroup != null) {
try {
this.transportChannelGroup.shutdownNow();
} catch (Exception e) {
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
}
}
}
private static AnyValue load(final InputStream in0) {
final DefaultAnyValue any = new DefaultAnyValue();
try (final InputStream in = in0) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(in);
Element root = doc.getDocumentElement();
load(any, root);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return any;
}
private static void load(final DefaultAnyValue any, final Node root) {
final String home = System.getProperty(RESNAME_APP_HOME);
NamedNodeMap nodes = root.getAttributes();
if (nodes == null) return;
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
any.addValue(node.getNodeName(), node.getNodeValue().replace("${APP_HOME}", home));
}
NodeList children = root.getChildNodes();
if (children == null) return;
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
DefaultAnyValue sub = new DefaultAnyValue();
load(sub, node);
any.addValue(node.getNodeName(), sub);
}
}
}

View File

@@ -0,0 +1,431 @@
/*
* 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.boot;
import java.io.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.jar.*;
import java.util.logging.*;
import java.util.regex.*;
import org.redkale.util.AnyValue;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.AutoLoad;
/**
* class过滤器 符合条件的class会保留下来存入FilterEntry。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 泛型
*/
@SuppressWarnings("unchecked")
public final class ClassFilter<T> {
private final Set<FilterEntry<T>> entrys = new HashSet<>();
private boolean refused;
private Class superClass;
private Class<? extends Annotation> annotationClass;
private Pattern[] includePatterns;
private Pattern[] excludePatterns;
private List<ClassFilter> ors;
private List<ClassFilter> ands;
private AnyValue conf;
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass) {
this(annotationClass, superClass, null);
}
public ClassFilter(Class<? extends Annotation> annotationClass, Class superClass, AnyValue conf) {
this.annotationClass = annotationClass;
this.superClass = superClass;
this.conf = conf;
}
public ClassFilter<T> or(ClassFilter<T> filter) {
if (ors == null) ors = new ArrayList<>();
ors.add(filter);
return this;
}
public ClassFilter<T> and(ClassFilter<T> filter) {
if (ands == null) ands = new ArrayList<>();
ands.add(filter);
return this;
}
/**
* 获取符合条件的class集合
*
* @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/
public final Set<FilterEntry<T>> getFilterEntrys() {
return entrys;
}
/**
* 自动扫描地过滤指定的class
*
* @param property AnyValue
* @param clazzname String
*/
@SuppressWarnings("unchecked")
public final void filter(AnyValue property, String clazzname) {
filter(property, clazzname, true);
}
/**
* 过滤指定的class
*
* @param property application.xml中对应class节点下的property属性项
* @param clazzname class名称
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan) {
boolean r = accept0(property, clazzname);
ClassFilter cf = r ? this : null;
if (r && ands != null) {
for (ClassFilter filter : ands) {
if (!filter.accept(property, clazzname)) return;
}
}
if (!r && ors != null) {
for (ClassFilter filter : ors) {
if (filter.accept(property, clazzname)) {
cf = filter;
break;
}
}
}
if (cf == null) return;
try {
Class clazz = Class.forName(clazzname);
if (!cf.accept(property, clazz, autoscan)) return;
if (cf.conf != null) {
if (property == null) {
property = cf.conf;
} else if (property instanceof DefaultAnyValue) {
((DefaultAnyValue) property).addAll(cf.conf);
} else {
DefaultAnyValue dav = new DefaultAnyValue();
dav.addAll(property);
dav.addAll(cf.conf);
property = dav;
}
}
entrys.add(new FilterEntry(clazz, autoscan, property));
} catch (Throwable cfe) {
}
}
private static Pattern[] toPattern(String[] regs) {
if (regs == null) return null;
int i = 0;
Pattern[] rs = new Pattern[regs.length];
for (String reg : regs) {
if (reg == null || reg.trim().isEmpty()) continue;
rs[i++] = Pattern.compile(reg.trim());
}
if (i == 0) return null;
if (i == rs.length) return rs;
Pattern[] ps = new Pattern[i];
System.arraycopy(rs, 0, ps, 0, i);
return ps;
}
/**
* 判断class是否有效
*
* @param property AnyValue
* @param classname String
* @return boolean
*/
public boolean accept(AnyValue property, String classname) {
boolean r = accept0(property, classname);
if (r && ands != null) {
for (ClassFilter filter : ands) {
if (!filter.accept(property, classname)) return false;
}
}
if (!r && ors != null) {
for (ClassFilter filter : ors) {
if (filter.accept(property, classname)) return true;
}
}
return r;
}
private boolean accept0(AnyValue property, String classname) {
if (this.refused) return false;
if (classname.startsWith("java.") || classname.startsWith("javax.")) return false;
if (excludePatterns != null) {
for (Pattern reg : excludePatterns) {
if (reg.matcher(classname).matches()) return false;
}
}
if (includePatterns != null) {
for (Pattern reg : includePatterns) {
if (reg.matcher(classname).matches()) return true;
}
}
return includePatterns == null;
}
/**
* 判断class是否有效
*
* @param property AnyValue
* @param clazz Class
* @param autoscan boolean
* @return boolean
*/
@SuppressWarnings("unchecked")
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
if (autoscan) {
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
if (auto != null && !auto.value()) return false;
}
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
}
public void setSuperClass(Class superClass) {
this.superClass = superClass;
}
public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
this.annotationClass = annotationClass;
}
public Pattern[] getIncludePatterns() {
return includePatterns;
}
public void setIncludePatterns(String[] includePatterns) {
this.includePatterns = toPattern(includePatterns);
}
public Pattern[] getExcludePatterns() {
return excludePatterns;
}
public void setExcludePatterns(String[] excludePatterns) {
this.excludePatterns = toPattern(excludePatterns);
}
public Class<? extends Annotation> getAnnotationClass() {
return annotationClass;
}
public Class getSuperClass() {
return superClass;
}
public boolean isRefused() {
return refused;
}
public void setRefused(boolean refused) {
this.refused = refused;
}
/**
* 存放符合条件的class与class指定的属性项
*
* @param <T> 泛型
*/
public static final class FilterEntry<T> {
private final HashSet<String> groups = new LinkedHashSet<>();
private final String name;
private final Class<T> type;
private final AnyValue property;
private final boolean autoload;
public FilterEntry(Class<T> type, AnyValue property) {
this(type, false, property);
}
public FilterEntry(Class<T> type, final boolean autoload, AnyValue property) {
this.type = type;
String str = property == null ? null : property.getValue("groups");
if (str != null) {
str = str.trim();
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
}
if (str != null) groups.addAll(Arrays.asList(str.split(";")));
this.property = property;
this.autoload = autoload;
this.name = property == null ? "" : property.getValue("name", "");
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + groups + "]";
}
@Override
public int hashCode() {
return this.type.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
return (this.type == ((FilterEntry<?>) obj).type && this.groups.equals(((FilterEntry<?>) obj).groups) && this.name.equals(((FilterEntry<?>) obj).name));
}
public Class<T> getType() {
return type;
}
public String getName() {
return name;
}
public AnyValue getProperty() {
return property;
}
public boolean isEmptyGroups() {
return groups == null || groups.isEmpty();
}
public HashSet<String> getGroups() {
return groups;
}
public boolean isAutoload() {
return autoload;
}
}
/**
* class加载类
*/
public static class Loader {
protected static final Logger logger = Logger.getLogger(Loader.class.getName());
protected static final ConcurrentMap<URL, Set<String>> cache = new ConcurrentHashMap<>();
public static void close() {
cache.clear();
}
/**
* 加载当前线程的classpath扫描所有class进行过滤
*
* @param exclude 不需要扫描的文件夹, 可以为null
* @param filters 过滤器
* @throws IOException 异常
*/
public static void load(final File exclude, final ClassFilter... filters) throws IOException {
URLClassLoader loader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
List<URL> urlfiles = new ArrayList<>(2);
List<URL> urljares = new ArrayList<>(2);
final URL exurl = exclude != null ? exclude.toURI().toURL() : null;
for (URL url : loader.getURLs()) {
if (exurl != null && exurl.sameFile(url)) continue;
if (url.getPath().endsWith(".jar")) {
urljares.add(url);
} else {
urlfiles.add(url);
}
}
List<File> files = new ArrayList<>();
boolean debug = logger.isLoggable(Level.FINEST);
StringBuilder debugstr = new StringBuilder();
for (final URL url : urljares) {
Set<String> classes = cache.get(url);
if (classes == null) {
classes = new LinkedHashSet<>();
try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), "UTF-8"))) {
Enumeration<JarEntry> it = jar.entries();
while (it.hasMoreElements()) {
String entryname = it.nextElement().getName().replace('/', '.');
if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) {
String classname = entryname.substring(0, entryname.length() - 6);
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
}
}
}
}
cache.put(url, classes);
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
}
}
}
}
for (final URL url : urlfiles) {
Set<String> classes = cache.get(url);
if (classes == null) {
classes = new LinkedHashSet<>();
files.clear();
File root = new File(url.getFile());
String rootpath = root.getPath();
loadClassFiles(exclude, root, files);
for (File f : files) {
String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.');
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
}
}
cache.put(url, classes);
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname);
}
}
}
}
//if (debug) logger.log(Level.INFO, "scan classes: \r\n{0}", debugstr);
}
private static void loadClassFiles(File exclude, File root, List<File> files) {
if (root.isFile() && root.getName().endsWith(".class")) {
files.add(root);
} else if (root.isDirectory()) {
if (exclude != null && exclude.equals(root)) return;
for (File f : root.listFiles()) {
loadClassFiles(exclude, f, files);
}
}
}
}
}

View File

@@ -0,0 +1,276 @@
/*
* 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.boot;
import java.io.*;
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import java.util.logging.Formatter;
/**
* 自定义的日志输出类
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class LogFileHandler extends Handler {
/**
* SNCP的日志输出Handler
*/
public static class SncpLogFileHandler extends LogFileHandler {
@Override
public String getPrefix() {
return "sncp-";
}
}
/**
* 默认的日志时间格式化类
*
*/
public static class LoggingFormater extends Formatter {
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
@Override
public String format(LogRecord record) {
String source;
if (record.getSourceClassName() != null) {
source = record.getSourceClassName();
if (record.getSourceMethodName() != null) {
source += " " + record.getSourceMethodName();
}
} else {
source = record.getLoggerName();
}
String message = formatMessage(record);
String throwable = "";
if (record.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw) {
@Override
public void println() {
super.print("\r\n");
}
};
pw.println();
record.getThrown().printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
return String.format(format,
System.currentTimeMillis(),
source,
record.getLoggerName(),
record.getLevel().getName(),
message,
throwable);
}
}
protected final LinkedBlockingQueue<LogRecord> records = new LinkedBlockingQueue();
private String pattern;
private int limit; //文件大小限制
private final AtomicInteger index = new AtomicInteger();
private int count = 1; //文件限制
private long tomorrow;
private boolean append;
private final AtomicLong length = new AtomicLong();
private File logfile;
private OutputStream stream;
public LogFileHandler() {
updateTomorrow();
configure();
open();
}
private void updateTomorrow() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis();
if (this.tomorrow != t) index.set(0);
this.tomorrow = t;
}
private void open() {
final String name = "Logging-" + getClass().getSimpleName() + "-Thread";
new Thread() {
{
setName(name);
setDaemon(true);
}
@Override
public void run() {
while (true) {
try {
LogRecord record = records.take();
final boolean bigger = (limit > 0 && limit <= length.get());
if (bigger || tomorrow <= record.getMillis()) {
updateTomorrow();
if (stream != null) {
stream.close();
if (bigger) {
for (int i = Math.min(count - 2, index.get() - 1); i > 0; i--) {
File greater = new File(logfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
stream = null;
}
}
if (stream == null) {
index.incrementAndGet();
java.time.LocalDate date = LocalDate.now();
logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logfile.getParentFile().mkdirs();
length.set(logfile.length());
stream = new FileOutputStream(logfile, append);
}
//----------------------写日志-------------------------
String message = getFormatter().format(record);
String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
stream.write(bytes);
length.addAndGet(bytes.length);
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
}
}
}
}.start();
}
public String getPrefix() {
return "";
}
private void configure() {
LogManager manager = LogManager.getLogManager();
String cname = LogFileHandler.class.getName();
pattern = manager.getProperty(cname + ".pattern");
if (pattern == null) {
pattern = "logs-%m/" + getPrefix() + "log-%d.log";
} else {
int pos = pattern.lastIndexOf('/');
if (pos > 0) {
pattern = pattern.substring(0, pos + 1) + getPrefix() + pattern.substring(pos + 1);
} else {
pattern = getPrefix() + pattern;
}
}
String limitstr = manager.getProperty(cname + ".limit");
try {
if (limitstr != null) limit = Math.abs(Integer.decode(limitstr));
} catch (Exception e) {
}
String countstr = manager.getProperty(cname + ".count");
try {
if (countstr != null) count = Math.max(1, Math.abs(Integer.decode(countstr)));
} catch (Exception e) {
}
String appendstr = manager.getProperty(cname + ".append");
try {
if (appendstr != null) append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
} catch (Exception e) {
}
String levelstr = manager.getProperty(cname + ".level");
try {
if (levelstr != null) {
Level l = Level.parse(levelstr);
setLevel(l != null ? l : Level.ALL);
}
} catch (Exception e) {
}
String filterstr = manager.getProperty(cname + ".filter");
try {
if (filterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
setFilter((Filter) clz.newInstance());
}
} catch (Exception e) {
}
String formatterstr = manager.getProperty(cname + ".formatter");
try {
if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
setFormatter((Formatter) clz.newInstance());
}
} catch (Exception e) {
}
if (getFormatter() == null) setFormatter(new SimpleFormatter());
String encodingstr = manager.getProperty(cname + ".encoding");
try {
if (encodingstr != null) setEncoding(encodingstr);
} catch (Exception e) {
}
}
@Override
public void publish(LogRecord record) {
final String sourceClassName = record.getSourceClassName();
if (sourceClassName == null || true) {
StackTraceElement[] ses = new Throwable().getStackTrace();
for (int i = 2; i < ses.length; i++) {
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
record.setSourceMethodName(ses[i].getMethodName());
break;
}
} else {
record.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
}
records.offer(record);
}
@Override
public void flush() {
try {
if (stream != null) stream.flush();
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE);
}
}
@Override
public void close() throws SecurityException {
try {
if (stream != null) stream.close();
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE);
}
}
}

View File

@@ -0,0 +1,145 @@
/*
* 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.boot;
import org.redkale.net.http.WebServlet;
import org.redkale.net.http.HttpServer;
import org.redkale.net.http.HttpServlet;
import org.redkale.util.AnyValue;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.util.AnyValue.DefaultAnyValue;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.logging.*;
import javax.annotation.*;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
/**
* HTTP Server节点的配置Server
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@NodeProtocol({"HTTP"})
public final class NodeHttpServer extends NodeServer {
private final HttpServer httpServer;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.httpServer = (HttpServer) server;
}
private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application.getStartTime(), application.getWatchFactory());
}
@Override
public InetSocketAddress getSocketAddress() {
return httpServer == null ? null : httpServer.getSocketAddress();
}
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, HttpServlet.class, null, "servlets", "servlet");
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
if (httpServer != null) loadHttpServlet(this.serverConf.getAnyValue("servlets"), servletFilter);
}
@Override
protected void loadService(ClassFilter serviceFilter) throws Exception {
super.loadService(serviceFilter);
initWebSocketService();
}
private void initWebSocketService() {
final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory();
resourceFactory.add(WebSocketNode.class, (ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try {
if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof WebSocketServlet)) return;
synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) {
nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (Transport) null, (Collection<Transport>) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
}
field.set(src, nodeService);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}
});
}
protected void loadHttpServlet(final AnyValue conf, final ClassFilter<? extends Servlet> filter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String prefix = conf == null ? "" : conf.getValue("path", "");
final String threadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Servlet>> list = new ArrayList(filter.getFilterEntrys());
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
if (ws1 == ws2) return o1.getType().getName().compareTo(o2.getType().getName());
return ws1 ? -1 : 1;
});
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
for (FilterEntry<? extends Servlet> en : list) {
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null || ws.value().length == 0) continue;
final HttpServlet servlet = clazz.newInstance();
resourceFactory.inject(servlet, this);
final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : "";
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
WebInitParam[] webparams = ws.initParams();
if (webparams.length > 0) {
if (servletConf == null) servletConf = new DefaultAnyValue();
for (WebInitParam webparam : webparams) {
servletConf.addValue(webparam.name(), webparam.value());
}
}
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null) {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = pref + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
}
}
if (ss != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
int max = 0;
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Loaded ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' ');
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
}
}

View File

@@ -0,0 +1,24 @@
/*
* 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.boot;
import java.lang.annotation.*;
/**
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NodeProtocol {
String[] value();
}

View File

@@ -0,0 +1,493 @@
/*
* 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.boot;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.logging.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.Transient;
import static org.redkale.boot.Application.*;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.net.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public abstract class NodeServer {
//INFO日志的换行符
public static final String LINE_SEPARATOR = "\r\n";
//日志输出对象
protected final Logger logger;
//日志是否为FINE级别
protected final boolean fine;
//日志是否为FINE级别
protected final boolean finer;
//进程主类
protected final Application application;
//依赖注入工厂类
protected final ResourceFactory resourceFactory;
//当前Server对象
protected final Server server;
private String sncpGroup = null; //当前Server的SNCP协议的组
private InetSocketAddress sncpAddress; //SNCP服务的地址 非SNCP为null
protected Consumer<ServiceWrapper> consumer;
protected AnyValue serverConf;
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>();
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>();
public NodeServer(Application application, Server server) {
this.application = application;
this.resourceFactory = application.getResourceFactory().createChild();
this.server = server;
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.fine = logger.isLoggable(Level.FINE);
this.finer = logger.isLoggable(Level.FINER);
}
protected Consumer<Runnable> getExecutor() throws Exception {
if (server == null) return null;
final Field field = Server.class.getDeclaredField("context");
field.setAccessible(true);
return new Consumer<Runnable>() {
private Context context;
@Override
public void accept(Runnable t) {
if (context == null && server != null) {
try {
this.context = (Context) field.get(server);
} catch (Exception e) {
logger.log(Level.SEVERE, "Server (" + server.getSocketAddress() + ") cannot find Context", e);
}
}
context.submit(t);
}
};
}
public static <T extends NodeServer> NodeServer create(Class<T> clazz, Application application, AnyValue serconf) {
try {
return clazz.getConstructor(Application.class, AnyValue.class).newInstance(application, serconf);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void init(AnyValue config) throws Exception {
this.serverConf = config == null ? AnyValue.create() : config;
if (isSNCP()) { // SNCP协议
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.globalNodes.get(this.sncpAddress);
//单向SNCP服务不需要对等group
//if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
}
if (this.sncpAddress != null) this.resourceFactory.register(RESNAME_SERVER_ADDR, this.sncpAddress); //单点服务不会有 sncpAddress、sncpGroup
if (this.sncpGroup != null) this.resourceFactory.register(RESNAME_SERVER_GROUP, this.sncpGroup);
{
//设置root文件夹
String webroot = config.getValue("root", "root");
File myroot = new File(webroot);
if (!webroot.contains(":") && !webroot.startsWith("/")) {
myroot = new File(System.getProperty(Application.RESNAME_APP_HOME), webroot);
}
resourceFactory.register(Server.RESNAME_SERVER_ROOT, String.class, myroot.getCanonicalPath());
resourceFactory.register(Server.RESNAME_SERVER_ROOT, File.class, myroot.getCanonicalFile());
resourceFactory.register(Server.RESNAME_SERVER_ROOT, Path.class, myroot.toPath());
final String homepath = myroot.getCanonicalPath();
Server.loadLib(logger, config.getValue("lib", "").replace("${APP_HOME}", homepath) + ";" + homepath + "/lib/*;" + homepath + "/classes");
if (server != null) server.init(config);
}
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter<Service> serviceFilter = createServiceClassFilter();
long s = System.currentTimeMillis();
if (servletFilter == null) {
ClassFilter.Loader.load(application.getHome(), serviceFilter);
} else {
ClassFilter.Loader.load(application.getHome(), serviceFilter, servletFilter);
}
long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " load filter class in " + e + " ms");
loadService(serviceFilter); //必须在servlet之前
loadServlet(servletFilter);
}
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
private void initResource() {
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
resourceFactory.add(DataSource.class, (ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
DataSource source = new DataDefaultSource(resourceName);
application.dataSources.add(source);
appResFactory.register(resourceName, DataSource.class, source);
SncpClient client = null;
Transport sameGroupTransport = null;
List<Transport> diffGroupTransports = null;
try {
Field ts = src.getClass().getDeclaredField("_sameGroupTransport");
ts.setAccessible(true);
sameGroupTransport = (Transport) ts.get(src);
ts = src.getClass().getDeclaredField("_diffGroupTransports");
ts.setAccessible(true);
diffGroupTransports = Arrays.asList((Transport[]) ts.get(src));
ts = src.getClass().getDeclaredField("_client");
ts.setAccessible(true);
client = (SncpClient) ts.get(src);
} catch (Exception e) {
throw new RuntimeException(src.getClass().getName() + " not found _sameGroupTransport or _diffGroupTransports at " + field, e);
}
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null);
localServiceWrappers.add(wrapper);
sncpServer.consumerAccept(wrapper);
rf.inject(cacheListenerService, self);
if (fine) logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
}
field.set(src, source);
rf.inject(source, self); // 给 "datasource.nodeid" 赋值;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
});
resourceFactory.add(CacheSource.class, (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 CacheSource
SncpClient client = null;
Transport sameGroupTransport = null;
List<Transport> diffGroupTransports = null;
try {
Field ts = src.getClass().getDeclaredField("_sameGroupTransport");
ts.setAccessible(true);
sameGroupTransport = (Transport) ts.get(src);
ts = src.getClass().getDeclaredField("_diffGroupTransports");
ts.setAccessible(true);
Transport[] dts = (Transport[]) ts.get(src);
if (dts != null) diffGroupTransports = Arrays.asList(dts);
ts = src.getClass().getDeclaredField("_client");
ts.setAccessible(true);
client = (SncpClient) ts.get(src);
} catch (Exception e) {
throw new RuntimeException(src.getClass().getName() + " not found _sameGroupTransport or _diffGroupTransports at " + field, e);
}
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
source.setStoreType(pt == null ? Serializable.class : (Class) pt.getActualTypeArguments()[0], valType instanceof Class ? (Class) valType : Object.class);
if (field.getAnnotation(Transient.class) != null) source.setNeedStore(false); //必须在setStoreType之后
application.cacheSources.add(source);
appResFactory.register(resourceName, CacheSource.class, source);
field.set(src, source);
rf.inject(source, self); //
((Service) source).init(null);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null);
sncpServer.getSncpServer().addService(wrapper);
if (finer) logger.finer("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
}
logger.finer("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
});
}
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter serviceFilter) throws Exception {
if (serviceFilter == null) return;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<Service>> entrys = serviceFilter.getFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
for (FilterEntry<Service> entry : entrys) { //service实现类
final Class<? extends Service> type = entry.getType();
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(type.getModifiers())) continue;
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (resourceFactory.find(entry.getName(), type) != null) continue; //Server加载Service时需要判断是否已经加载过了。
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| type.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
Service service;
if (localed) { //本地模式
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type, this.sncpAddress, loadTransport(this.sncpGroup), loadTransports(groups));
} else {
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, this.sncpAddress, loadTransport(groups));
}
if(SncpClient.parseMethod(type).isEmpty()) continue; //class没有可用的方法 通常为BaseService
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : wrapper.getTypes()) {
if (resourceFactory.find(wrapper.getName(), restype) == null) {
regFactory.register(wrapper.getName(), restype, wrapper.getService());
} else if (isSNCP() && !entry.isAutoload()) {
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
}
}
if (wrapper.isRemote()) {
remoteServiceWrappers.add(wrapper);
} else {
localServiceWrappers.add(wrapper);
if (consumer != null) consumer.accept(wrapper);
}
}
application.servicecdl.countDown();
application.servicecdl.await();
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ----------------
new ArrayList<>(localServiceWrappers).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
});
remoteServiceWrappers.forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
if (sb != null) {
sb.append(threadName).append(y.toSimpleString()).append(" loaded and injected").append(LINE_SEPARATOR);
}
});
//----------------- init -----------------
List<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers);
Collections.sort(swlist);
localServiceWrappers.clear();
localServiceWrappers.addAll(swlist);
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
localServiceWrappers.parallelStream().forEach(y -> {
long s = System.currentTimeMillis();
y.getService().init(y.getConf());
long e = System.currentTimeMillis() - s;
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" loaded and init ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
});
Collections.sort(slist);
if (slist != null && sb != null) {
for (String s : slist) {
sb.append(s);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
protected List<Transport> loadTransports(final HashSet<String> groups) {
if (groups == null) return null;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
if (this.sncpGroup == null || !this.sncpGroup.equals(group)) {
transports.add(loadTransport(group));
}
}
return transports;
}
protected Transport loadTransport(final HashSet<String> groups) {
if (groups == null || groups.isEmpty()) return null;
List<String> tmpgroup = new ArrayList<>(groups);
Collections.sort(tmpgroup); //按字母排列顺序
final String groupid = tmpgroup.stream().collect(Collectors.joining(";"));
Transport transport = application.resourceFactory.find(groupid, Transport.class);
if (transport != null) return transport;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
transports.add(loadTransport(group));
}
Set<InetSocketAddress> addrs = new HashSet();
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
Transport first = transports.get(0);
Transport newTransport = new Transport(groupid, application.findGroupProtocol(first.getName()), application.getWatchFactory(),
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(groupid, Transport.class);
if (transport == null) {
transport = newTransport;
application.resourceFactory.register(groupid, transport);
}
}
return transport;
}
protected Transport loadTransport(final String group) {
if (group == null) return null;
Transport transport;
synchronized (application.resourceFactory) {
transport = application.resourceFactory.find(group, Transport.class);
if (transport != null) {
if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) {
throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress());
}
return transport;
}
Set<InetSocketAddress> addrs = application.findGlobalGroup(group);
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, application.findGroupProtocol(group), application.getWatchFactory(),
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.resourceFactory.register(group, transport);
}
return transport;
}
protected abstract ClassFilter<Servlet> createServletClassFilter();
protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, Service.class, Annotation.class, "services", "service");
}
protected ClassFilter createClassFilter(final String localGroup, Class<? extends Annotation> ref,
Class inter, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, null);
if (properties == null && properties == null) return cf;
if (this.serverConf == null) return cf;
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
if (proplist == null || proplist.length < 1) return cf;
cf = null;
for (AnyValue list : proplist) {
DefaultAnyValue prop = null;
String sc = list.getValue("groups");
if (sc != null) {
sc = sc.trim();
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
}
if (sc == null) sc = localGroup;
if (sc != null) {
prop = new AnyValue.DefaultAnyValue();
prop.addValue("groups", sc);
}
ClassFilter filter = new ClassFilter(ref, inter, prop);
for (AnyValue av : list.getAnyValues(property)) {
final AnyValue[] items = av.getAnyValues("property");
if (av instanceof DefaultAnyValue && items.length > 0) {
DefaultAnyValue dav = DefaultAnyValue.create();
final AnyValue.Entry<String>[] strings = av.getStringEntrys();
if (strings != null) {
for (AnyValue.Entry<String> en : strings) {
dav.addValue(en.name, en.getValue());
}
}
final AnyValue.Entry<AnyValue>[] anys = av.getAnyEntrys();
if (anys != null) {
for (AnyValue.Entry<AnyValue> en : anys) {
if (!"property".equals(en.name)) dav.addValue(en.name, en.getValue());
}
}
DefaultAnyValue ps = DefaultAnyValue.create();
for (AnyValue item : items) {
ps.addValue(item.getValue("name"), item.getValue("value"));
}
dav.addValue("property", ps);
av = dav;
}
filter.filter(av, av.getValue("value"), false);
}
if (list.getBoolValue("autoload", true)) {
String includes = list.getValue("includes", "");
String excludes = list.getValue("excludes", "");
filter.setIncludePatterns(includes.split(";"));
filter.setExcludePatterns(excludes.split(";"));
} else if (ref2 == null || ref2 == Annotation.class) { //service如果是autoload=false则不需要加载
filter.setRefused(true);
} else if (ref2 != Annotation.class) {
filter.setAnnotationClass(ref2);
}
cf = (cf == null) ? filter : cf.or(filter);
}
return cf;
}
public abstract InetSocketAddress getSocketAddress();
public boolean isSNCP() {
return false;
}
public InetSocketAddress getSncpAddress() {
return sncpAddress;
}
public String getSncpGroup() {
return sncpGroup;
}
public void start() throws IOException {
server.start();
}
public void shutdown() throws IOException {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
localServiceWrappers.forEach(y -> {
long s = System.currentTimeMillis();
y.getService().destroy(y.getConf());
long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) {
sb.append(y.toSimpleString()).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
}
});
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
server.shutdown();
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.boot;
import java.net.*;
import java.util.*;
import java.util.logging.*;
import org.redkale.net.*;
import org.redkale.net.sncp.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@NodeProtocol({"SNCP"})
public final class NodeSncpServer extends NodeServer {
private final SncpServer sncpServer;
public NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null ? null : x -> sncpServer.addService(x);
}
private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer(application.getStartTime(), application.getWatchFactory());
}
@Override
public InetSocketAddress getSocketAddress() {
return sncpServer == null ? null : sncpServer.getSocketAddress();
}
public void consumerAccept(ServiceWrapper wrapper) {
if (this.consumer != null) this.consumer.accept(wrapper);
}
@Override
public void init(AnyValue config) throws Exception {
super.init(config);
//-------------------------------------------------------------------
if (sncpServer == null) return; //调试时server才可能为null
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets);
for (SncpServlet en : servlets) {
if (sb != null) sb.append(threadName).append(" Loaded ").append(en).append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
}
@Override
public boolean isSNCP() {
return true;
}
public SncpServer getSncpServer() {
return sncpServer;
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
}
@Override
protected ClassFilter<Servlet> createServletClassFilter() {
return null;
}
}

View File

@@ -0,0 +1,4 @@
/**
* 提供RedKale服务器的启动、初始化和加载功能
*/
package org.redkale.boot;

View File

@@ -0,0 +1,42 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
/**
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <T> 序列化的泛型类型
*/
public final class AnyEncoder<T> implements Encodeable<Writer, T> {
final ConvertFactory factory;
AnyEncoder(ConvertFactory factory) {
this.factory = factory;
}
@Override
@SuppressWarnings("unchecked")
public void convertTo(final Writer out, final T value) {
if (value == null) {
out.wirteClassName(null);
out.writeNull();
} else {
out.wirteClassName(factory.getEntity(value.getClass()));
factory.loadEncoder(value.getClass()).convertTo(out, value);
}
}
@Override
public Type getType() {
return Object.class;
}
}

View File

@@ -0,0 +1,82 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.*;
/**
* 对象数组的序列化不包含int[]、long[]这样的primitive class数组.
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有采用int存储。
* 支持一定程度的泛型。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 反解析的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
private final Type type;
private final Type componentType;
private final Class componentClass;
private final Decodeable<Reader, T> decoder;
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
}
if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else {
this.componentClass = (Class) this.componentType;
}
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
}
@Override
public T[] convertFrom(Reader in) {
final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
final Decodeable<Reader, T> localdecoder = this.decoder;
final List<T> result = new ArrayList();
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
}
} else {
for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in));
}
}
in.readArrayE();
T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size());
return result.toArray(rs);
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.decoder + "}";
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,78 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
/**
* 对象数组的反序列化不包含int[]、long[]这样的primitive class数组.
* 数组长度不能超过 32767。 在BSON中数组长度设定的是short对于大于32767长度的数组传输会影响性能所以没有必要采用int存储。
* 支持一定程度的泛型。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 序列化的数组元素类型
*/
@SuppressWarnings("unchecked")
public final class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
private final Type type;
private final Type componentType;
private final Encodeable anyEncoder;
private final Encodeable<Writer, Object> encoder;
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType();
} else {
throw new ConvertException("(" + type + ") is not a array type");
}
factory.register(type, this);
this.encoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder();
}
@Override
public void convertTo(Writer out, T[] value) {
if (value == null) {
out.writeNull();
return;
}
if (value.length == 0) {
out.writeArrayB(0);
out.writeArrayE();
return;
}
out.writeArrayB(value.length);
final Type comp = this.componentType;
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
((v != null && v.getClass() == comp) ? encoder : anyEncoder).convertTo(out, v);
if (first) first = false;
}
out.writeArrayE();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.encoder + "}";
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,72 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* 对象集合的反序列化.
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。
* 支持一定程度的泛型。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 反解析的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
private final Type type;
private final Type componentType;
protected Creator<Collection<T>> creator;
private final Decodeable<Reader, T> decoder;
public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.decoder = factory.loadDecoder(this.componentType);
} else {
throw new ConvertException("collectiondecoder not support the type (" + type + ")");
}
}
@Override
public Collection<T> convertFrom(Reader in) {
final int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
final Decodeable<Reader, T> localdecoder = this.decoder;
final Collection<T> result = this.creator.create();
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
result.add(localdecoder.convertFrom(in));
}
} else {
for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in));
}
}
in.readArrayE();
return result;
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,66 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.Collection;
/**
* 对象集合的序列化.
* 集合大小不能超过 32767。 在BSON中集合大小设定的是short对于大于32767长度的集合传输会影响性能所以没有采用int存储。
* 支持一定程度的泛型。
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <T> 序列化的集合元素类型
*/
@SuppressWarnings("unchecked")
public final class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
private final Type type;
private final Encodeable<Writer, Object> encoder;
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) {
this.encoder = factory.getAnyEncoder();
} else {
this.encoder = factory.loadEncoder(t);
}
} else {
this.encoder = factory.getAnyEncoder();
}
}
@Override
public void convertTo(Writer out, Collection<T> value) {
if (value == null) {
out.writeNull();
return;
}
if (value.isEmpty()) {
out.writeArrayB(0);
out.writeArrayE();
return;
}
out.writeArrayB(value.size());
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
encoder.convertTo(out, v);
if (first) first = false;
}
out.writeArrayE();
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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;
/**
* 序列化操作类
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
public abstract class Convert<R extends Reader, W extends Writer> {
protected final ConvertFactory<R, W> factory;
protected Convert(ConvertFactory<R, W> factory) {
this.factory = factory;
}
public ConvertFactory<R, W> getFactory() {
return this.factory;
}
}

View File

@@ -0,0 +1,47 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* 依附在setter、getter方法、字段进行简单的配置
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Repeatable(ConvertColumns.class)
public @interface ConvertColumn {
/**
* 给字段取个别名
*
* @return 字段别名
*/
String name() default "";
/**
* 解析/序列化时是否屏蔽该字段
*
* @return 是否屏蔽该字段
*/
boolean ignore() default false;
/**
* 解析/序列化定制化的TYPE
*
* @return JSON or BSON or ALL
*/
ConvertType type() default ConvertType.ALL;
}

View File

@@ -0,0 +1,68 @@
/*
* 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;
/**
* ConvertColumn 对应的实体类
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public final class ConvertColumnEntry {
private String name = "";
private boolean ignore;
private ConvertType convertType;
public ConvertColumnEntry() {
}
public ConvertColumnEntry(ConvertColumn column) {
if (column == null) return;
this.name = column.name();
this.ignore = column.ignore();
this.convertType = column.type();
}
public ConvertColumnEntry(String name, boolean ignore) {
this.name = name;
this.ignore = ignore;
this.convertType = ConvertType.ALL;
}
public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) {
this.name = name;
this.ignore = ignore;
this.convertType = convertType;
}
public String name() {
return name == null ? "" : name;
}
public void setName(String name) {
this.name = name;
}
public boolean ignore() {
return ignore;
}
public void setIgnore(boolean ignore) {
this.ignore = ignore;
}
public ConvertType type() {
return convertType == null ? ConvertType.ALL : convertType;
}
public void setConvertType(ConvertType convertType) {
this.convertType = convertType;
}
}

View 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.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* ConvertColumn 的多用类
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ConvertColumns {
ConvertColumn[] value();
}

View File

@@ -0,0 +1,27 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 用于类名的别名, 类似javax.persistence.Table
* 该值必须是全局唯一
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名。关联方法: Reader.readClassName() 和 Writer.wirteClassName(String value) 。
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ConvertEntity {
String value();
}

View File

@@ -0,0 +1,29 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public class ConvertException extends RuntimeException {
public ConvertException() {
super();
}
public ConvertException(String s) {
super(s);
}
public ConvertException(String message, Throwable cause) {
super(message, cause);
}
public ConvertException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,486 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
import java.lang.reflect.*;
import java.math.BigInteger;
import java.net.*;
import java.nio.channels.*;
import static org.redkale.convert.ext.InetAddressSimpledCoder.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
*/
@SuppressWarnings("unchecked")
public abstract class ConvertFactory<R extends Reader, W extends Writer> {
private final ConvertFactory parent;
protected Convert<R, W> convert;
protected boolean tiny;
private final Encodeable<W, ?> anyEncoder = new AnyEncoder(this);
//-----------------------------------------------------------------------------------
private final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap();
private final ConcurrentHashMap<String, Class> entitys = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Decodeable<R, ?>> decoders = new ConcurrentHashMap();
private final ConcurrentHashMap<Type, Encodeable<W, ?>> encoders = new ConcurrentHashMap();
private final ConcurrentHashMap<AccessibleObject, ConvertColumnEntry> columnEntrys = new ConcurrentHashMap();
private final Set<Class> skipIgnores = new HashSet();
private boolean skipAllIgnore = false;
protected ConvertFactory(ConvertFactory<R, W> parent, boolean tiny) {
this.tiny = tiny;
this.parent = parent;
if (parent == null) {
//---------------------------------------------------------
this.register(boolean.class, BoolSimpledCoder.instance);
this.register(Boolean.class, BoolSimpledCoder.instance);
this.register(byte.class, ByteSimpledCoder.instance);
this.register(Byte.class, ByteSimpledCoder.instance);
this.register(short.class, ShortSimpledCoder.instance);
this.register(Short.class, ShortSimpledCoder.instance);
this.register(char.class, CharSimpledCoder.instance);
this.register(Character.class, CharSimpledCoder.instance);
this.register(int.class, IntSimpledCoder.instance);
this.register(Integer.class, IntSimpledCoder.instance);
this.register(long.class, LongSimpledCoder.instance);
this.register(Long.class, LongSimpledCoder.instance);
this.register(float.class, FloatSimpledCoder.instance);
this.register(Float.class, FloatSimpledCoder.instance);
this.register(double.class, DoubleSimpledCoder.instance);
this.register(Double.class, DoubleSimpledCoder.instance);
this.register(Number.class, NumberSimpledCoder.instance);
this.register(String.class, StringSimpledCoder.instance);
this.register(CharSequence.class, CharSequenceSimpledCoder.instance);
this.register(java.util.Date.class, DateSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.instance);
this.register(InetAddress.class, InetAddressSimpledCoder.instance);
this.register(DLong.class, DLongSimpledCoder.instance);
this.register(Class.class, TypeSimpledCoder.instance);
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance);
//---------------------------------------------------------
this.register(boolean[].class, BoolArraySimpledCoder.instance);
this.register(byte[].class, ByteArraySimpledCoder.instance);
this.register(short[].class, ShortArraySimpledCoder.instance);
this.register(char[].class, CharArraySimpledCoder.instance);
this.register(int[].class, IntArraySimpledCoder.instance);
this.register(long[].class, LongArraySimpledCoder.instance);
this.register(float[].class, FloatArraySimpledCoder.instance);
this.register(double[].class, DoubleArraySimpledCoder.instance);
this.register(String[].class, StringArraySimpledCoder.instance);
//---------------------------------------------------------
}
}
public ConvertFactory parent() {
return this.parent;
}
public abstract ConvertType getConvertType();
public abstract boolean isReversible();
public abstract ConvertFactory createChild();
public abstract ConvertFactory createChild(boolean tiny);
public Convert getConvert() {
return convert;
}
public ConvertFactory tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
public ConvertColumnEntry findRef(AccessibleObject element) {
if (element == null) return null;
ConvertColumnEntry en = this.columnEntrys.get(element);
if (en != null) return en;
final ConvertType ct = this.getConvertType();
ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class);
if (ccs.length == 0 && element instanceof Method) {
final Method method = (Method) element;
String fieldName = readGetSetFieldName(method);
if (fieldName != null) {
try {
ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class);
} catch (Exception e) { //说明没有该字段,忽略异常
}
}
}
for (ConvertColumn ref : ccs) {
if (ref.type().contains(ct)) {
ConvertColumnEntry entry = new ConvertColumnEntry(ref);
if (skipAllIgnore) {
entry.setIgnore(false);
return entry;
}
if (skipIgnores.isEmpty()) return entry;
if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false);
return entry;
}
}
return null;
}
static String readGetSetFieldName(Method method) {
if (method == null) return null;
String fname = method.getName();
if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname;
fname = fname.substring(fname.startsWith("is") ? 2 : 3);
if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) {
fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1);
} else if (fname.length() == 1) {
fname = "" + Character.toLowerCase(fname.charAt(0));
}
return fname;
}
final String getEntity(Class clazz) {
ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class);
if (ce != null && findEntity(ce.value()) == null) entitys.put(ce.value(), clazz);
return ce == null ? clazz.getName() : ce.value();
}
private Class findEntity(String name) {
Class clazz = entitys.get(name);
return parent == null ? clazz : parent.findEntity(name);
}
final Class getEntity(String name) {
Class clazz = findEntity(name);
try {
return clazz == null ? Class.forName(name) : clazz;
} catch (Exception ex) {
throw new ConvertException("convert entity is " + name, ex);
}
}
/**
* 使所有类的所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
*
* @param skipIgnore 是否忽略Ignore注解
*/
public final void registerSkipAllIgnore(final boolean skipIgnore) {
this.skipAllIgnore = skipIgnore;
}
/**
* 使该类所有被声明为ConvertColumn.ignore = true 的字段或方法变为ConvertColumn.ignore = false
*
* @param type 指定的类
*/
public final void registerSkipIgnore(final Class type) {
skipIgnores.add(type);
}
public final void register(final Class type, boolean ignore, String... columns) {
for (String column : columns) {
register(type, column, new ConvertColumnEntry(column, ignore));
}
}
public final boolean register(final Class type, String column, ConvertColumnEntry entry) {
if (type == null || column == null || entry == null) return false;
try {
final Field field = type.getDeclaredField(column);
String get = "get";
if (field.getType() == boolean.class || field.getType() == Boolean.class) get = "is";
char[] cols = column.toCharArray();
cols[0] = Character.toUpperCase(cols[0]);
String col2 = new String(cols);
try {
register(type.getMethod(get + col2), entry);
} catch (Exception ex) {
}
try {
register(type.getMethod("set" + col2, field.getType()), entry);
} catch (Exception ex) {
}
return register(field, entry);
} catch (Exception e) {
return false;
}
}
public final <E> boolean register(final AccessibleObject field, final ConvertColumnEntry entry) {
if (field == null || entry == null) return false;
this.columnEntrys.put(field, entry);
return true;
}
public final void reloadCoder(final Type type) {
this.register(type, this.createDecoder(type));
this.register(type, this.createEncoder(type));
}
public final void reloadCoder(final Type type, final Class clazz) {
this.register(type, this.createDecoder(type, clazz));
this.register(type, this.createEncoder(type, clazz));
}
public final <E> void register(final Class<E> clazz, final Creator<? extends E> creator) {
creators.put(clazz, creator);
}
public final <T> Creator<T> findCreator(Class<T> type) {
Creator<T> creator = creators.get(type);
if (creator != null) return creator;
return this.parent == null ? null : this.parent.findCreator(type);
}
public final <T> Creator<T> loadCreator(Class<T> type) {
Creator result = findCreator(type);
if (result == null) {
result = Creator.create(type);
if (result != null) creators.put(type, result);
}
return result;
}
//----------------------------------------------------------------------
public final <E> Encodeable<W, E> getAnyEncoder() {
return (Encodeable<W, E>) anyEncoder;
}
public final <E> void register(final Type clazz, final SimpledCoder<R, W, E> coder) {
decoders.put(clazz, coder);
encoders.put(clazz, coder);
}
public final <E> void register(final Type clazz, final Decodeable<R, E> decoder) {
decoders.put(clazz, decoder);
}
public final <E> void register(final Type clazz, final Encodeable<W, E> printer) {
encoders.put(clazz, printer);
}
public final <E> Decodeable<R, E> findDecoder(final Type type) {
Decodeable<R, E> rs = (Decodeable<R, E>) decoders.get(type);
if (rs != null) return rs;
return this.parent == null ? null : this.parent.findDecoder(type);
}
public final <E> Encodeable<W, E> findEncoder(final Type type) {
Encodeable<W, E> rs = (Encodeable<W, E>) encoders.get(type);
if (rs != null) return rs;
return this.parent == null ? null : this.parent.findEncoder(type);
}
public final <E> Decodeable<R, E> loadDecoder(final Type type) {
Decodeable<R, E> decoder = findDecoder(type);
if (decoder != null) return decoder;
if (type instanceof GenericArrayType) return new ArrayDecoder(this, type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
final TypeVariable tv = (TypeVariable) type;
Class cz = tv.getBounds().length == 0 ? Object.class : null;
for (Type f : tv.getBounds()) {
if (f instanceof Class) {
cz = (Class) f;
break;
}
}
clazz = cz;
if (cz == null) throw new ConvertException("not support the type (" + type + ")");
} else if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
Class cz = null;
for (Type f : wt.getUpperBounds()) {
if (f instanceof Class) {
cz = (Class) f;
break;
}
}
clazz = cz;
if (cz == null) throw new ConvertException("not support the type (" + type + ")");
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
decoder = findDecoder(clazz);
if (decoder != null) return decoder;
return createDecoder(type, clazz);
}
public final <E> Decodeable<R, E> createDecoder(final Type type) {
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
return createDecoder(type, clazz);
}
private <E> Decodeable<R, E> createDecoder(final Type type, final Class clazz) {
Decodeable<R, E> decoder = null;
ObjectDecoder od = null;
if (clazz.isEnum()) {
decoder = new EnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
decoder = new ArrayDecoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) {
decoder = new CollectionDecoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) {
decoder = new MapDecoder(this, type);
} else if (clazz == Object.class) {
od = new ObjectDecoder(type);
decoder = od;
} else if (!clazz.getName().startsWith("java.")) {
Decodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) continue;
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) continue;
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue;
if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue;
try {
method.setAccessible(true);
simpleCoder = (Decodeable) method.invoke(null, this);
break;
} catch (Exception e) {
}
}
if (simpleCoder == null) {
od = new ObjectDecoder(type);
decoder = od;
} else {
decoder = simpleCoder;
}
}
if (decoder == null) throw new ConvertException("not support the type (" + type + ")");
register(type, decoder);
if (od != null) od.init(this);
return decoder;
}
public final <E> Encodeable<W, E> loadEncoder(final Type type) {
Encodeable<W, E> encoder = findEncoder(type);
if (encoder != null) return encoder;
if (type instanceof GenericArrayType) return new ArrayEncoder(this, type);
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) type;
Type t = Object.class;
if (tv.getBounds().length == 1) {
t = tv.getBounds()[0];
}
if (!(t instanceof Class)) t = Object.class;
clazz = (Class) t;
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
encoder = findEncoder(clazz);
if (encoder != null) return encoder;
return createEncoder(type, clazz);
}
public final <E> Encodeable<W, E> createEncoder(final Type type) {
Class clazz;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (type instanceof Class) {
clazz = (Class) type;
} else {
throw new ConvertException("not support the type (" + type + ")");
}
return createEncoder(type, clazz);
}
private <E> Encodeable<W, E> createEncoder(final Type type, final Class clazz) {
Encodeable<W, E> encoder = null;
ObjectEncoder oe = null;
if (clazz.isEnum()) {
encoder = new EnumSimpledCoder(clazz);
} else if (clazz.isArray()) {
encoder = new ArrayEncoder(this, type);
} else if (Collection.class.isAssignableFrom(clazz)) {
encoder = new CollectionEncoder(this, type);
} else if (Map.class.isAssignableFrom(clazz)) {
encoder = new MapEncoder(this, type);
} else if (clazz == Object.class) {
return (Encodeable<W, E>) this.anyEncoder;
} else if (!clazz.getName().startsWith("java.")) {
Encodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isStatic(method.getModifiers())) continue;
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) continue;
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue;
if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue;
try {
method.setAccessible(true);
simpleCoder = (Encodeable) method.invoke(null, this);
break;
} catch (Exception e) {
}
}
if (simpleCoder == null) {
oe = new ObjectEncoder(type);
encoder = oe;
} else {
encoder = simpleCoder;
}
}
if (encoder == null) throw new ConvertException("not support the type (" + type + ")");
register(type, encoder);
if (oe != null) oe.init(this);
return encoder;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public enum ConvertType {
JSON(1),
BSON(2),
ALL(127);
private final int value;
private ConvertType(int v) {
this.value = v;
}
public boolean contains(ConvertType type) {
if (type == null) return false;
return this.value >= type.value && (this.value & type.value) > 0;
}
}

View File

@@ -0,0 +1,85 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import org.redkale.util.Attribute;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <T> 字段依附的类
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class DeMember<R extends Reader, T, F> implements Comparable<DeMember<R, T, F>> {
protected final Attribute<T, F> attribute;
protected Decodeable<R, F> decoder;
public DeMember(final Attribute<T, F> attribute) {
this.attribute = attribute;
}
public DeMember(Attribute<T, F> attribute, Decodeable<R, F> decoder) {
this(attribute);
this.decoder = decoder;
}
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldname) {
try {
Field field = clazz.getDeclaredField(fieldname);
return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public final boolean match(String name) {
return attribute.field().equals(name);
}
public final void read(R in, T obj) {
this.attribute.set(obj, decoder.convertFrom(in));
}
public final F read(R in) {
return decoder.convertFrom(in);
}
public Attribute<T, F> getAttribute() {
return this.attribute;
}
@Override
public final int compareTo(DeMember<R, T, F> o) {
if (o == null) return 1;
return this.attribute.field().compareTo(o.attribute.field());
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof DeMember)) return false;
DeMember other = (DeMember) obj;
return compareTo(other) == 0;
}
@Override
public int hashCode() {
return this.attribute.field().hashCode();
}
@Override
public String toString() {
return "DeMember{" + "attribute=" + attribute.field() + ", decoder=" + decoder + '}';
}
}

View File

@@ -0,0 +1,30 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <T> 反解析的数据类型
*/
public interface Decodeable<R extends Reader, T> {
public T convertFrom(final R in);
/**
* 泛型映射接口
*
* @return 反解析的数据类型
*/
public Type getType();
}

View File

@@ -0,0 +1,78 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.*;
import org.redkale.util.Attribute;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <W> Writer输出的子类
* @param <T> 字段依附的类
* @param <F> 字段的数据类型
*/
@SuppressWarnings("unchecked")
public final class EnMember<W extends Writer, T, F> implements Comparable<EnMember<W, T, F>> {
final Attribute<T, F> attribute;
final Encodeable<W, F> encoder;
final boolean istring;
//final boolean isnumber;
final boolean isbool;
public EnMember(Attribute<T, F> attribute, Encodeable<W, F> encoder) {
this.attribute = attribute;
this.encoder = encoder;
Class t = attribute.type();
this.istring = CharSequence.class.isAssignableFrom(t);
this.isbool = t == Boolean.class || t == boolean.class;
//this.isnumber = Number.class.isAssignableFrom(t) || (!this.isbool && t.isPrimitive());
}
public static <W extends Writer, T, F> EnMember<W, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldname) {
try {
Field field = clazz.getDeclaredField(fieldname);
return new EnMember<>(Attribute.create(field), factory.loadEncoder(field.getGenericType()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public final boolean match(String name) {
return attribute.field().equals(name);
}
@Override
public final int compareTo(EnMember<W, T, F> o) {
if (o == null) return 1;
return this.attribute.field().compareTo(o.attribute.field());
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EnMember)) return false;
EnMember other = (EnMember) obj;
return compareTo(other) == 0;
}
@Override
public int hashCode() {
return this.attribute.field().hashCode();
}
@Override
public String toString() {
return "EnMember{" + "attribute=" + attribute.field() + ", encoder=" + encoder + '}';
}
}

View File

@@ -0,0 +1,30 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <W> Writer输出的子类
* @param <T> 序列化的数据类型
*/
public interface Encodeable<W extends Writer, T> {
public void convertTo(final W out, T value);
/**
* 泛型映射接口
*
* @return 返回序列化对象类的数据类型
*/
public Type getType();
}

View File

@@ -0,0 +1,79 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <K> Map key的数据类型
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
private final Type type;
private final Type keyType;
private final Type valueType;
protected Creator<Map<K, V>> creator;
private final Decodeable<Reader, K> keyDecoder;
private final Decodeable<Reader, V> valueDecoder;
public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.keyType = pt.getActualTypeArguments()[0];
this.valueType = pt.getActualTypeArguments()[1];
this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this);
this.keyDecoder = factory.loadDecoder(this.keyType);
this.valueDecoder = factory.loadDecoder(this.valueType);
} else {
throw new ConvertException("mapdecoder not support the type (" + type + ")");
}
}
@Override
public Map<K, V> convertFrom(Reader in) {
final int len = in.readMapB();
if (len == Reader.SIGN_NULL) return null;
final Map<K, V> result = this.creator.create();
if (len == Reader.SIGN_NOLENGTH) {
while (in.hasNext()) {
K key = keyDecoder.convertFrom(in);
in.readBlank();
V value = valueDecoder.convertFrom(in);
result.put(key, value);
}
} else {
for (int i = 0; i < len; i++) {
K key = keyDecoder.convertFrom(in);
in.readBlank();
V value = valueDecoder.convertFrom(in);
result.put(key, value);
}
}
in.readMapE();
return result;
}
@Override
public Type getType() {
return this.type;
}
}

View File

@@ -0,0 +1,65 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <K> Map key的数据类型
* @param <V> Map value的数据类型
*/
@SuppressWarnings("unchecked")
public final class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
private final Type type;
private final Encodeable<Writer, K> keyencoder;
private final Encodeable<Writer, V> valencoder;
public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final Type[] pt = ((ParameterizedType) type).getActualTypeArguments();
this.keyencoder = factory.loadEncoder(pt[0]);
this.valencoder = factory.loadEncoder(pt[1]);
} else {
this.keyencoder = factory.getAnyEncoder();
this.valencoder = factory.getAnyEncoder();
}
}
@Override
public void convertTo(Writer out, Map<K, V> value) {
final Map<K, V> values = value;
if (values == null) {
out.writeNull();
return;
}
out.writeMapB(values.size());
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
this.keyencoder.convertTo(out, en.getKey());
out.writeMapMark();
this.valencoder.convertTo(out, en.getValue());
if (first) first = false;
}
out.writeMapE();
}
@Override
public Type getType() {
return type;
}
}

View File

@@ -0,0 +1,234 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <T> 反解析的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
protected final Type type;
protected final Class typeClass;
protected Creator<T> creator;
protected DeMember<R, T, ?>[] creatorConstructorMembers;
protected DeMember<R, T, ?>[] members;
protected ConvertFactory factory;
private boolean inited = false;
private final Object lock = new Object();
protected ObjectDecoder(Type type) {
this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.typeClass = (Class) pt.getRawType();
} else {
this.typeClass = (Class) type;
}
this.members = new DeMember[0];
}
public void init(final ConvertFactory factory) {
this.factory = factory;
try {
if (type == Object.class) return;
Class clazz = null;
if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type;
clazz = (Class) (pts).getRawType();
} else if (!(type instanceof Class)) {
throw new ConvertException("[" + type + "] is no a class");
} else {
clazz = (Class) type;
}
this.creator = factory.loadCreator(clazz);
final Set<DeMember> list = new HashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
ConvertColumnEntry ref;
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(field.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)));
}
final boolean reversible = factory.isReversible();
for (final Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue;
if (Modifier.isAbstract(method.getModifiers())) continue;
if (method.isSynthetic()) continue;
if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue;
if (method.getParameterTypes().length != 1) continue;
if (method.getReturnType() != void.class) continue;
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class;
try {
clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get"));
} catch (Exception e) {
continue;
}
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(method.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)));
}
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
for (final String constructorField : cps) {
boolean flag = false;
for (DeMember m : list) {
if (m.attribute.field().equals(constructorField)) {
flag = true;
break;
}
}
if (flag) continue;
//不存在setter方法
try {
Field f = clazz.getDeclaredField(constructorField);
Type t = ObjectEncoder.createClassType(f.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
} catch (NoSuchFieldException nsfe) { //不存在field 可能存在getter方法
char[] fs = constructorField.toCharArray();
fs[0] = Character.toUpperCase(fs[0]);
String mn = new String(fs);
Method getter;
try {
getter = clazz.getMethod("get" + mn);
} catch (NoSuchMethodException ex) {
getter = clazz.getMethod("is" + mn);
}
Type t = ObjectEncoder.createClassType(getter.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
}
}
}
this.members = list.toArray(new DeMember[list.size()]);
Arrays.sort(this.members);
if (cps != null) {
final String[] fields = cps;
final DeMember<R, T, ?>[] ms = new DeMember[fields.length];
for (int i = 0; i < fields.length; i++) {
for (DeMember m : this.members) {
if (m.attribute.field().equals(fields[i])) {
ms[i] = m;
break;
}
}
}
this.creatorConstructorMembers = ms;
}
} catch (Exception ex) {
throw new ConvertException(ex);
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
/**
* 对象格式: [0x1][short字段个数][字段名][字段值]...[0x2]
*
* @param in 输入流
* @return 反解析后的对象结果
*/
@Override
public final T convertFrom(final R in) {
final String clazz = in.readObjectB(typeClass);
if (clazz == null) return null;
if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntity(clazz)).convertFrom(in);
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator.create();
while (in.hasNext()) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
member.read(in, result);
}
}
in.readObjectE(typeClass);
return result;
} else { //带参数的构造函数
final DeMember<R, T, ?>[] fields = this.creatorConstructorMembers;
final Object[] constructorParams = new Object[fields.length];
final Object[][] otherParams = new Object[this.members.length][2];
int oc = 0;
while (in.hasNext()) {
DeMember member = in.readFieldName(members);
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
Object val = member.read(in);
boolean flag = true;
for (int i = 0; i < fields.length; i++) {
if (member == fields[i]) {
constructorParams[i] = val;
flag = false;
break;
}
}
if (flag) otherParams[oc++] = new Object[]{member.attribute, val};
}
}
in.readObjectE(typeClass);
final T result = this.creator.create(constructorParams);
for (int i = 0; i < oc; i++) {
((Attribute) otherParams[i][0]).set(result, otherParams[i][1]);
}
return result;
}
}
@Override
public final Type getType() {
return this.type;
}
@Override
public String toString() {
return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
}
}

View File

@@ -0,0 +1,278 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Attribute;
import java.lang.reflect.*;
import java.util.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <W> Writer输出的子类
* @param <T> 序列化的数据类型
*/
@SuppressWarnings("unchecked")
public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
static final Type[] TYPEZERO = new Type[0];
protected final Type type;
protected final Class typeClass;
protected EnMember[] members;
protected ConvertFactory factory;
private boolean inited = false;
private final Object lock = new Object();
protected ObjectEncoder(Type type) {
this.type = type;
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
this.typeClass = (Class) pt.getRawType();
} else {
this.typeClass = (Class) type;
}
this.members = new EnMember[0];
}
public void init(final ConvertFactory factory) {
this.factory = factory;
try {
if (type == Object.class) return;
//if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class");
final Class clazz = this.typeClass;
final Set<EnMember> list = new HashSet();
final boolean reversible = factory.isReversible();
Creator creator = null;
try {
creator = factory.loadCreator(this.typeClass);
} catch (RuntimeException e) {
if (reversible) throw e;
}
final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator);
try {
ConvertColumnEntry ref;
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(field.getGenericType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)));
}
for (final Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue;
if (Modifier.isAbstract(method.getModifiers())) continue;
if (method.isSynthetic()) continue;
if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue;
if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue;
if (reversible && (cps == null || !contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
boolean is = method.getName().startsWith("is");
try {
clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType());
} catch (Exception e) {
continue;
}
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(method.getGenericReturnType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)));
}
this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members);
} catch (Exception ex) {
throw new ConvertException(ex);
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
}
}
}
@Override
public final void convertTo(W out, T value) {
if (value == null) {
out.writeObjectNull(null);
return;
}
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (value != null && value.getClass() != this.typeClass) {
final Class clz = value.getClass();
out.wirteClassName(factory.getEntity(clz));
factory.loadEncoder(clz).convertTo(out, value);
return;
}
out.writeObjectB(value);
for (EnMember member : members) {
out.writeObjectField(member, value);
}
out.writeObjectE(value);
}
@Override
public final Type getType() {
return this.type;
}
@Override
public String toString() {
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
}
static Type createClassType(final Type type, final Type declaringType0) {
if (TypeToken.isClassType(type)) return type;
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
final ParameterizedType pt = (ParameterizedType) type;
final Type[] paramTypes = pt.getActualTypeArguments();
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
}
return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
}
Type declaringType = declaringType0;
if (declaringType instanceof Class) {
do {
declaringType = ((Class) declaringType).getGenericSuperclass();
if (declaringType == Object.class) return Object.class;
} while (declaringType instanceof Class);
}
//存在通配符则declaringType 必须是 ParameterizedType
if (!(declaringType instanceof ParameterizedType)) return Object.class;
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
final Type[] desTypes = declaringPType.getActualTypeArguments();
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
for (Type f : wt.getUpperBounds()) {
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
return type;
}
//
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
// if (type instanceof Class) { //e.g. String
// return type;
// } else if (type instanceof ParameterizedType) { //e.g. Map<String, String>
// final ParameterizedType pt = (ParameterizedType) type;
// Type[] paramTypes = pt.getActualTypeArguments();
// final Type[] newTypes = new Type[paramTypes.length];
// int count = 0;
// for (int i = 0; i < newTypes.length; i++) {
// newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes);
// if (paramTypes[i] == newTypes[i]) count++;
// }
// if (count == paramTypes.length) return pt;
// return new ParameterizedType() {
//
// @Override
// public Type[] getActualTypeArguments() {
// return newTypes;
// }
//
// @Override
// public Type getRawType() {
// return pt.getRawType();
// }
//
// @Override
// public Type getOwnerType() {
// return pt.getOwnerType();
// }
//
// };
// }
// if (realGenericTypes == null) return type;
// if (type instanceof WildcardType) { // e.g. <? extends Serializable>
// final WildcardType wt = (WildcardType) type;
// for (Type f : wt.getUpperBounds()) {
// for (int i = 0; i < virGenericTypes.length; i++) {
// if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i];
// }
// }
// } else if (type instanceof TypeVariable) { // e.g. <? extends E>
// for (int i = 0; i < virGenericTypes.length; i++) {
// if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i];
// }
// }
// return type;
// }
static boolean contains(String[] values, String value) {
for (String str : values) {
if (str.equals(value)) return true;
}
return false;
}
static String[] findConstructorProperties(Creator creator) {
try {
Creator.ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(Creator.ConstructorParameters.class);
return cps == null ? null : cps.value();
} catch (Exception e) {
return null;
}
}
static Attribute createAttribute(final ConvertFactory factory, Class clazz, final Field field, final Method getter, final Method setter) {
String fieldalias;
if (field != null) { // public field
ConvertColumnEntry ref = factory.findRef(field);
fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name();
} else if (getter != null) {
ConvertColumnEntry ref = factory.findRef(getter);
String mfieldname = ConvertFactory.readGetSetFieldName(getter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
} else { // setter != null
ConvertColumnEntry ref = factory.findRef(setter);
String mfieldname = ConvertFactory.readGetSetFieldName(setter);
if (ref == null) {
try {
ref = factory.findRef(clazz.getDeclaredField(mfieldname));
} catch (Exception e) {
}
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
}
return Attribute.create(clazz, fieldalias, field, getter, setter);
}
}

View File

@@ -0,0 +1,170 @@
/*
* 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;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class Reader {
//当前对象字段名的游标
protected int fieldIndex;
public static final short SIGN_NULL = -1;
public static final short SIGN_NOLENGTH = -2;
/**
* 是否还存在下个元素或字段
*
* @return 是否还存在下个元素或字段
*/
public abstract boolean hasNext();
/**
* 跳过值(不包含值前面的字段)
*/
public abstract void skipValue();
/**
* /跳过字段与值之间的多余内容, json就是跳过:符, map跳过:
*/
public abstract void readBlank();
/**
* 读取对象的类名, 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
*
* @param clazz 类名
* @return 返回字段数
*/
public String readObjectB(final Class clazz) {
this.fieldIndex = 0;
return null;
}
/**
* 读取对象的尾端
*
* @param clazz 类名
*/
public abstract void readObjectE(final Class clazz);
/**
* 读取数组的开头并返回数组的长度
*
* @return 返回数组的长度
*/
public abstract int readArrayB();
/**
* 读取数组的尾端
*
*/
public abstract void readArrayE();
/**
* 读取map的开头并返回map的size
*
* @return 返回map的size
*/
public abstract int readMapB();
/**
* 读取数组的尾端
*
*/
public abstract void readMapE();
/**
* 根据字段读取字段对应的DeMember
*
* @param members DeMember的全量集合
* @return 匹配的DeMember
*/
public abstract DeMember readFieldName(final DeMember[] members);
/**
* 读取一个boolean值
*
* @return boolean值
*/
public abstract boolean readBoolean();
/**
* 读取一个byte值
*
* @return byte值
*/
public abstract byte readByte();
/**
* 读取一个char值
*
* @return char值
*/
public abstract char readChar();
/**
* 读取一个short值
*
* @return short值
*/
public abstract short readShort();
/**
* 读取一个int值
*
* @return int值
*/
public abstract int readInt();
/**
* 读取一个long值
*
* @return long值
*/
public abstract long readLong();
/**
* 读取一个float值
*
* @return float值
*/
public abstract float readFloat();
/**
* 读取一个double值
*
* @return double值
*/
public abstract double readDouble();
/**
* 读取无转义字符长度不超过255的字符串 例如枚举值、字段名、类名字符串等
*
* @return String值
*/
public abstract String readSmallString();
/**
* 读取反解析对象的类名
*
* @return 类名
*/
public abstract String readClassName();
/**
* 读取一个String值
*
* @return String值
*/
public abstract String readString();
}

View File

@@ -0,0 +1,45 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类
* @param <W> Writer输出的子类
* @param <T> 序列化/反解析的数据类型
*/
public abstract class SimpledCoder<R extends Reader, W extends Writer, T> implements Decodeable<R, T>, Encodeable<W, T> {
private Type type;
@Override
public abstract void convertTo(final W out, final T value);
@Override
public abstract T convertFrom(final R in);
@Override
@SuppressWarnings("unchecked")
public Class<T> getType() {
if (type == null) {
Type[] ts = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
type = ts[ts.length - 1];
}
return (Class<T>) type;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}

View File

@@ -0,0 +1,205 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import org.redkale.util.Attribute;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class Writer {
//当前对象输出字段名之前是否需要分隔符, JSON字段间的分隔符为,逗号
protected boolean comma;
/**
* 当tiny=true时 字符串为空、boolean为false的字段值都会被跳过 不会输出。
*
* @return 是否简化
*/
public abstract boolean tiny();
/**
* 输出null值
*/
public abstract void writeNull();
/**
* 写入类名
*
* @param clazz 类名
*/
public abstract void wirteClassName(String clazz);
/**
* 输出一个对象前的操作
* 注: 覆盖此方法必须要先调用父方法 super.writeObjectB(obj);
*
* @param obj 写入的对象
*/
public void writeObjectB(Object obj) {
this.comma = false;
}
/**
* 输出一个为null的对象
*
* @param clazz 对象的类名
*/
public final void writeObjectNull(final Class clazz) {
wirteClassName(null);
writeNull();
}
/**
* 输出一个对象的某个字段
*
* @param member 字段
*
* @param obj 写入的对象
*/
@SuppressWarnings("unchecked")
public final void writeObjectField(final EnMember member, Object obj) {
Object value = member.attribute.get(obj);
if (value == null) return;
if (tiny()) {
if (member.istring) {
if (((CharSequence) value).length() == 0) return;
} else if (member.isbool) {
if (!((Boolean) value)) return;
}
}
this.writeFieldName(member.attribute);
member.encoder.convertTo(this, value);
this.comma = true;
}
/**
* 输出一个对象后的操作
*
* @param obj 写入的对象
*/
public abstract void writeObjectE(Object obj);
/**
* 输出一个数组前的操作
*
* @param size 数组长度
*/
public abstract void writeArrayB(int size);
/**
* 输出数组元素间的间隔符
*
*/
public abstract void writeArrayMark();
/**
* 输出一个数组后的操作
*
*/
public abstract void writeArrayE();
/**
* 输出一个Map前的操作
*
* @param size map大小
*/
public abstract void writeMapB(int size);
/**
* 输出一个Map中key与value间的间隔符
*
*/
public abstract void writeMapMark();
/**
* 输出一个Map后的操作
*
*/
public abstract void writeMapE();
/**
* 输出一个字段名
*
* @param attribute 字段的Attribute对象
*/
public abstract void writeFieldName(Attribute attribute);
/**
* 写入一个boolean值
*
* @param value boolean值
*/
public abstract void writeBoolean(boolean value);
/**
* 写入一个byte值
*
* @param value byte值
*/
public abstract void writeByte(byte value);
/**
* 写入一个char值
*
* @param value char值
*/
public abstract void writeChar(char value);
/**
* 写入一个short值
*
* @param value short值
*/
public abstract void writeShort(short value);
/**
* 写入一个int值
*
* @param value int值
*/
public abstract void writeInt(int value);
/**
* 写入一个long值
*
* @param value long值
*/
public abstract void writeLong(long value);
/**
* 写入一个float值
*
* @param value float值
*/
public abstract void writeFloat(float value);
/**
* 写入一个double值
*
* @param value double值
*/
public abstract void writeDouble(double value);
/**
* 写入无转义字符长度不超过255的字符串 例如枚举值、字段名、类名字符串等 *
*
* @param value 非空且不含需要转义的字符的String值
*/
public abstract void writeSmallString(String value);
/**
* 写入一个String值
*
* @param value String值
*/
public abstract void writeString(String value);
}

View File

@@ -0,0 +1,172 @@
/*
* 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.bson;
import java.nio.*;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.util.*;
/**
*
* @author zhangjx
*/
public class BsonByteBufferReader extends BsonReader {
private ByteBuffer[] buffers;
private int currentIndex = 0;
private ByteBuffer currentBuffer;
protected BsonByteBufferReader(ByteBuffer... buffers) {
this.buffers = buffers;
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
}
@Override
protected boolean recycle() {
super.recycle(); // this.position 初始化值为-1
this.currentIndex = 0;
this.currentBuffer = null;
this.buffers = null;
return false;
}
@Override
protected byte currentByte() {
return currentBuffer.get(currentBuffer.position());
}
/**
* 判断下一个非空白字节是否为[
*
* @return 数组长度或 SIGN_NULL
*/
@Override
public final int readArrayB() {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
short lt = readShort();
return (bt & 0xffff) << 16 | (lt & 0xffff);
}
//------------------------------------------------------------
@Override
public final boolean readBoolean() {
return readByte() == 1;
}
@Override
public byte readByte() {
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
}
for (;;) {
this.currentBuffer = this.buffers[++this.currentIndex];
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
}
}
}
@Override
public final char readChar() {
if (this.currentBuffer != null) {
int remain = this.currentBuffer.remaining();
if (remain >= 2) {
this.position += 2;
return this.currentBuffer.getChar();
}
}
return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
}
@Override
public final short readShort() {
if (this.currentBuffer != null) {
int remain = this.currentBuffer.remaining();
if (remain >= 2) {
this.position += 2;
return this.currentBuffer.getShort();
}
}
return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte()));
}
@Override
public final int readInt() {
if (this.currentBuffer != null) {
int remain = this.currentBuffer.remaining();
if (remain >= 4) {
this.position += 4;
return this.currentBuffer.getInt();
}
}
return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
}
@Override
public final long readLong() {
if (this.currentBuffer != null) {
int remain = this.currentBuffer.remaining();
if (remain >= 8) {
this.position += 8;
return this.currentBuffer.getLong();
}
}
return ((((long) readByte() & 0xff) << 56)
| (((long) readByte() & 0xff) << 48)
| (((long) readByte() & 0xff) << 40)
| (((long) readByte() & 0xff) << 32)
| (((long) readByte() & 0xff) << 24)
| (((long) readByte() & 0xff) << 16)
| (((long) readByte() & 0xff) << 8)
| (((long) readByte() & 0xff)));
}
protected byte[] read(final int len) {
byte[] bs = new byte[len];
read(bs, 0);
return bs;
}
private void read(final byte[] bs, final int pos) {
int remain = this.currentBuffer.remaining();
if (remain < 1) {
this.currentBuffer = this.buffers[++this.currentIndex];
read(bs, pos);
return;
}
int len = bs.length - pos;
if (remain >= len) {
this.position += len;
this.currentBuffer.get(bs, pos, len);
return;
}
this.currentBuffer.get(bs, pos, remain);
this.position += remain;
this.currentBuffer = this.buffers[++this.currentIndex];
read(bs, pos + remain);
}
@Override
public final String readSmallString() {
int len = 0xff & readByte();
if (len == 0) return "";
return new String(read(len));
}
@Override
public final String readString() {
int len = readInt();
if (len == SIGN_NULL) return null;
if (len == 0) return "";
return new String(Utility.decodeUTF8(read(len)));
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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.bson;
import java.nio.*;
import java.util.function.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class BsonByteBufferWriter extends BsonWriter {
private final Supplier<ByteBuffer> supplier;
private ByteBuffer[] buffers;
private int index;
public BsonByteBufferWriter(Supplier<ByteBuffer> supplier) {
this(false, supplier);
}
protected BsonByteBufferWriter(boolean tiny, Supplier<ByteBuffer> supplier) {
super((byte[]) null);
this.tiny = tiny;
this.supplier = supplier;
}
@Override
public ByteBuffer[] toBuffers() {
if (buffers == null) return new ByteBuffer[0];
for (int i = index; i < this.buffers.length; i++) {
ByteBuffer buf = this.buffers[i];
if (buf.position() != 0) buf.flip();
}
return this.buffers;
}
@Override
public byte[] toArray() {
if (buffers == null) return new byte[0];
int pos = 0;
byte[] bytes = new byte[this.count];
for (ByteBuffer buf : toBuffers()) {
int r = buf.remaining();
buf.get(bytes, pos, r);
buf.flip();
pos += r;
}
return bytes;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[count=" + this.count + "]";
}
@Override
public BsonByteBufferWriter tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
@Override
protected int expand(final int byteLength) {
if (this.buffers == null) {
this.index = 0;
this.buffers = new ByteBuffer[]{supplier.get()};
}
ByteBuffer buffer = this.buffers[index];
if (!buffer.hasRemaining()) {
buffer.flip();
buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1];
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++;
}
int len = buffer.remaining();
int size = 0;
while (len < byteLength) {
buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1];
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining();
size++;
}
return size;
}
@Override
public void writeTo(final byte[] chs, final int start, final int len) {
if (expand(len) == 0) {
this.buffers[index].put(chs, start, len);
} else {
ByteBuffer buffer = this.buffers[index];
final int end = start + len;
int remain = len; //还剩多少没有写
while (remain > 0) {
final int br = buffer.remaining();
if (remain > br) { //一个buffer写不完
buffer.put(chs, end - remain, br);
buffer = nextByteBuffer();
remain -= br;
} else {
buffer.put(chs, end - remain, remain);
remain = 0;
}
}
}
this.count += len;
}
private ByteBuffer nextByteBuffer() {
this.buffers[this.index].flip();
return this.buffers[++this.index];
}
@Override
public void writeTo(final byte ch) {
expand(1);
this.buffers[index].put(ch);
count++;
}
@Override
protected boolean recycle() {
this.index = 0;
this.buffers = null;
return false;
}
}

View File

@@ -0,0 +1,214 @@
/*
* 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.bson;
import java.io.*;
import java.lang.reflect.*;
import java.nio.*;
import java.util.function.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
* <blockquote><pre>
* BSON协议格式:
* 1). 基本数据类型: 直接转换成byte[]
* 2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。
* 3). String: length(4 bytes) + byte[](utf8);
* 4). 数组: length(4 bytes) + byte[]...
* 5). Object:
* 1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名)
* 2. 空字符串(SmallString)
* 3. SIGN_OBJECTB 标记位值固定为0xBB (short)
* 4. 循环字段值:
* 4.1 SIGN_HASNEXT 标记位值固定为1 (byte)
* 4.2 字段类型; 1-9为基本类型和字符串; 101-109为基本类型和字符串的数组; 127为Object
* 4.3 字段名 (SmallString)
* 4.4 字段的值Object
* 5. SIGN_NONEXT 标记位值固定为0 (byte)
* 6. SIGN_OBJECTE 标记位值固定为0xEE (short)
*
* </pre></blockquote>
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public final class BsonConvert extends Convert<BsonReader, BsonWriter> {
private static final ObjectPool<BsonReader> readerPool = BsonReader.createPool(Integer.getInteger("convert.bson.pool.size", 16));
private static final ObjectPool<BsonWriter> writerPool = BsonWriter.createPool(Integer.getInteger("convert.bson.pool.size", 16));
private final boolean tiny;
protected BsonConvert(ConvertFactory<BsonReader, BsonWriter> factory, boolean tiny) {
super(factory);
this.tiny = tiny;
}
@Override
public BsonFactory getFactory() {
return (BsonFactory) factory;
}
public static BsonConvert root() {
return BsonFactory.root().getConvert();
}
//------------------------------ reader -----------------------------------------------------------
public BsonReader pollBsonReader(final ByteBuffer... buffers) {
return new BsonByteBufferReader(buffers);
}
public BsonReader pollBsonReader(final InputStream in) {
return new BsonStreamReader(in);
}
public BsonReader pollBsonReader() {
return readerPool.get();
}
public void offerBsonReader(final BsonReader in) {
if (in != null) readerPool.offer(in);
}
//------------------------------ writer -----------------------------------------------------------
public BsonByteBufferWriter pollBsonWriter(final Supplier<ByteBuffer> supplier) {
return new BsonByteBufferWriter(tiny, supplier);
}
public BsonWriter pollBsonWriter(final OutputStream out) {
return new BsonStreamWriter(tiny, out);
}
public BsonWriter pollBsonWriter() {
return writerPool.get().tiny(tiny);
}
public void offerBsonWriter(final BsonWriter out) {
if (out != null) writerPool.offer(out);
}
//------------------------------ convertFrom -----------------------------------------------------------
public <T> T convertFrom(final Type type, final byte[] bytes) {
if (bytes == null) return null;
return convertFrom(type, bytes, 0, bytes.length);
}
public <T> T convertFrom(final Type type, final byte[] bytes, final int start, final int len) {
if (type == null) return null;
final BsonReader in = readerPool.get();
in.setBytes(bytes, start, len);
@SuppressWarnings("unchecked")
T rs = (T) factory.loadDecoder(type).convertFrom(in);
readerPool.offer(in);
return rs;
}
public <T> T convertFrom(final Type type, final InputStream in) {
if (type == null || in == null) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in));
}
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers.length < 1) return null;
return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(buffers));
}
public <T> T convertFrom(final Type type, final BsonReader reader) {
if (type == null) return null;
@SuppressWarnings("unchecked")
T rs = (T) factory.loadDecoder(type).convertFrom(reader);
return rs;
}
//------------------------------ convertTo -----------------------------------------------------------
public byte[] convertTo(final Object value) {
if (value == null) {
final BsonWriter out = writerPool.get().tiny(tiny);
out.writeNull();
byte[] result = out.toArray();
writerPool.offer(out);
return result;
}
return convertTo(value.getClass(), value);
}
public byte[] convertTo(final Type type, final Object value) {
if (type == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
byte[] result = out.toArray();
writerPool.offer(out);
return result;
}
public void convertTo(final OutputStream out, final Object value) {
if (value == null) {
new BsonStreamWriter(tiny, out).writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(new BsonStreamWriter(tiny, out), value);
}
}
public void convertTo(final OutputStream out, final Type type, final Object value) {
if (type == null) return;
if (value == null) {
new BsonStreamWriter(tiny, out).writeNull();
} else {
factory.loadEncoder(type).convertTo(new BsonStreamWriter(tiny, out), value);
}
}
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
if (supplier == null || type == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
if (value == null) {
out.writeNull();
} else {
factory.loadEncoder(type).convertTo(out, value);
}
return out.toBuffers();
}
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
if (supplier == null) return null;
BsonByteBufferWriter out = new BsonByteBufferWriter(tiny, supplier);
if (value == null) {
out.writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(out, value);
}
return out.toBuffers();
}
public void convertTo(final BsonWriter writer, final Object value) {
if (value == null) {
writer.writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(writer, value);
}
}
public void convertTo(final BsonWriter writer, final Type type, final Object value) {
if (type == null) return;
factory.loadEncoder(type).convertTo(writer, value);
}
public BsonWriter convertToWriter(final Object value) {
if (value == null) return null;
return convertToWriter(value.getClass(), value);
}
public BsonWriter convertToWriter(final Type type, final Object value) {
if (type == null) return null;
final BsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
return out;
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.bson;
import java.io.Serializable;
import org.redkale.convert.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
private static final BsonFactory instance = new BsonFactory(null, Boolean.getBoolean("convert.bson.tiny"));
static final Decodeable objectDecoder = instance.loadDecoder(Object.class);
static final Encodeable objectEncoder = instance.loadEncoder(Object.class);
static {
instance.register(Serializable.class, objectDecoder);
instance.register(Serializable.class, objectEncoder);
}
private BsonFactory(BsonFactory parent, boolean tiny) {
super(parent, tiny);
}
@Override
public BsonFactory tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
public static BsonFactory root() {
return instance;
}
@Override
public final BsonConvert getConvert() {
if (convert == null) convert = new BsonConvert(this, tiny);
return (BsonConvert) convert;
}
@Override
public BsonFactory createChild() {
return new BsonFactory(this, this.tiny);
}
@Override
public BsonFactory createChild(boolean tiny) {
return new BsonFactory(this, tiny);
}
@Override
public ConvertType getConvertType() {
return ConvertType.BSON;
}
@Override
public boolean isReversible() {
return true;
}
}

View File

@@ -0,0 +1,324 @@
/*
* 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.bson;
import java.util.function.*;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class BsonReader extends Reader {
public static final short SIGN_OBJECTB = (short) 0xBB;
public static final short SIGN_OBJECTE = (short) 0xEE;
public static final byte SIGN_HASNEXT = 1;
public static final byte SIGN_NONEXT = 0;
public static final byte VERBOSE_NO = 1;
public static final byte VERBOSE_YES = 2;
protected byte typeval; //字段的类型值 对应 BsonWriter.writeField
protected int position = -1;
private byte[] content;
public BsonReader() {
}
public static ObjectPool<BsonReader> createPool(int max) {
return new ObjectPool<BsonReader>(max, new Creator<BsonReader>() {
@Override
public BsonReader create(Object... params) {
return new BsonReader();
}
}, null, new Predicate<BsonReader>() {
@Override
public boolean test(BsonReader t) {
return t.recycle();
}
});
}
public BsonReader(byte[] bytes) {
setBytes(bytes, 0, bytes.length);
}
public BsonReader(byte[] bytes, int start, int len) {
setBytes(bytes, start, len);
}
public final void setBytes(byte[] bytes) {
if (bytes == null) {
this.position = 0;
} else {
setBytes(bytes, 0, bytes.length);
}
}
public final void setBytes(byte[] bytes, int start, int len) {
if (bytes == null) {
this.position = 0;
} else {
this.content = bytes;
this.position = start - 1;
//this.limit = start + len - 1;
}
}
protected boolean recycle() {
this.position = -1;
this.typeval = 0;
//this.limit = -1;
this.content = null;
return true;
}
public void close() {
this.recycle();
}
/**
* 跳过属性的值
*/
@Override
public final void skipValue() {
if (typeval == 0) return;
final byte val = this.typeval;
this.typeval = 0;
switch (val) {
case 1: readBoolean();
break;
case 2: readByte();
break;
case 3: readShort();
break;
case 4: readChar();
break;
case 5: readInt();
break;
case 6: readLong();
break;
case 7: readFloat();
break;
case 8: readDouble();
break;
case 9: readString();
break;
case 101:
BoolArraySimpledCoder.instance.convertFrom(this);
break;
case 102:
ByteArraySimpledCoder.instance.convertFrom(this);
break;
case 103:
ShortArraySimpledCoder.instance.convertFrom(this);
break;
case 104:
CharArraySimpledCoder.instance.convertFrom(this);
break;
case 105:
IntArraySimpledCoder.instance.convertFrom(this);
break;
case 106:
LongArraySimpledCoder.instance.convertFrom(this);
break;
case 107:
FloatArraySimpledCoder.instance.convertFrom(this);
break;
case 108:
DoubleArraySimpledCoder.instance.convertFrom(this);
break;
case 109:
StringArraySimpledCoder.instance.convertFrom(this);
break;
case 127:
BsonFactory.objectDecoder.convertFrom(this);
break;
}
}
@Override
public final String readObjectB(final Class clazz) {
this.fieldIndex = 0; //必须要重置为0
final String newcls = readClassName();
if (newcls != null && !newcls.isEmpty()) return newcls;
short bt = readShort();
if (bt == Reader.SIGN_NULL) return null;
if (bt != SIGN_OBJECTB) {
throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB)
+ " (position = " + position + ") but '" + currentByte() + "'");
}
return "";
}
@Override
public final void readObjectE(final Class clazz) {
if (readShort() != SIGN_OBJECTE) {
throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE)
+ " (position = " + position + ") but '" + currentByte() + "'");
}
}
protected byte currentByte() {
return this.content[this.position];
}
@Override
public final int readMapB() {
return readArrayB();
}
@Override
public final void readMapE() {
}
/**
* 判断下一个非空白字节是否为[
*
* @return 数组长度或SIGN_NULL
*/
@Override
public int readArrayB() {
short bt = readShort();
if (bt == Reader.SIGN_NULL) return bt;
return (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
}
@Override
public final void readArrayE() {
}
/**
* 判断下一个非空白字节是否:
*/
@Override
public final void readBlank() {
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
byte b = readByte();
if (b == SIGN_HASNEXT) return true;
if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT)
+ " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")");
return false;
}
@Override
public final DeMember readFieldName(final DeMember[] members) {
final String exceptedfield = readSmallString();
this.typeval = readByte();
final int len = members.length;
if (this.fieldIndex >= len) this.fieldIndex = 0;
for (int k = this.fieldIndex; k < len; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) {
this.fieldIndex = k;
return members[k];
}
}
for (int k = 0; k < this.fieldIndex; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) {
this.fieldIndex = k;
return members[k];
}
}
return null;
}
//------------------------------------------------------------
@Override
public boolean readBoolean() {
return content[++this.position] == 1;
}
@Override
public byte readByte() {
return content[++this.position];
}
@Override
public char readChar() {
return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position]));
}
@Override
public short readShort() {
return (short) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position]));
}
@Override
public int readInt() {
return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16)
| ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff);
}
@Override
public long readLong() {
return ((((long) content[++this.position] & 0xff) << 56)
| (((long) content[++this.position] & 0xff) << 48)
| (((long) content[++this.position] & 0xff) << 40)
| (((long) content[++this.position] & 0xff) << 32)
| (((long) content[++this.position] & 0xff) << 24)
| (((long) content[++this.position] & 0xff) << 16)
| (((long) content[++this.position] & 0xff) << 8)
| (((long) content[++this.position] & 0xff)));
}
@Override
public final float readFloat() {
return Float.intBitsToFloat(readInt());
}
@Override
public final double readDouble() {
return Double.longBitsToDouble(readLong());
}
@Override
public final String readClassName() {
return readSmallString();
}
@Override
public String readSmallString() {
int len = 0xff & readByte();
if (len == 0) return "";
String value = new String(content, ++this.position, len);
this.position += len - 1; //上一行已经++this.position所以此处要-1
return value;
}
@Override
public String readString() {
int len = readInt();
if (len == SIGN_NULL) return null;
if (len == 0) return "";
String value = new String(Utility.decodeUTF8(content, ++this.position, len));
this.position += len - 1;//上一行已经++this.position所以此处要-1
return value;
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.bson;
import org.redkale.convert.SimpledCoder;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 序列化/反解析的数据类型
*/
public abstract class BsonSimpledCoder<T> extends SimpledCoder<BsonReader, BsonWriter, T> {
}

View File

@@ -0,0 +1,60 @@
/*
* 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.bson;
import java.io.*;
import org.redkale.convert.*;
/**
*
* @author zhangjx
*/
class BsonStreamReader extends BsonByteBufferReader {
private InputStream in;
private byte currByte;
protected BsonStreamReader(InputStream in) {
this.in = in;
}
@Override
protected boolean recycle() {
super.recycle(); // this.position 初始化值为-1
this.in = null;
this.currByte = 0;
return false;
}
@Override
public byte readByte() {
try {
byte b = (currByte = (byte) in.read());
this.position++;
return b;
} catch (IOException e) {
throw new ConvertException(e);
}
}
@Override
protected byte currentByte() {
return currByte;
}
@Override
protected byte[] read(final int len) {
byte[] bs = new byte[len];
try {
in.read(bs);
this.position += len;
} catch (IOException e) {
throw new ConvertException(e);
}
return bs;
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.bson;
import java.io.*;
import org.redkale.convert.*;
/**
*
* @author zhangjx
*/
class BsonStreamWriter extends BsonByteBufferWriter {
private OutputStream out;
protected BsonStreamWriter(boolean tiny, OutputStream out) {
super(tiny, null);
this.out = out;
}
@Override
protected boolean recycle() {
super.recycle();
this.out = null;
return false;
}
@Override
public void writeTo(final byte[] chs, final int start, final int len) {
try {
out.write(chs, start, len);
} catch (IOException e) {
throw new ConvertException(e);
}
}
@Override
public void writeTo(final byte ch) {
try {
out.write((byte) ch);
} catch (IOException e) {
throw new ConvertException(e);
}
}
}

View File

@@ -0,0 +1,301 @@
/*
* 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.bson;
import java.nio.*;
import java.util.function.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class BsonWriter extends Writer {
private static final int defaultSize = Integer.getInteger("convert.bson.writer.buffer.defsize", 1024);
private byte[] content;
protected int count;
protected boolean tiny;
public static ObjectPool<BsonWriter> createPool(int max) {
return new ObjectPool<BsonWriter>(max, new Creator<BsonWriter>() {
@Override
public BsonWriter create(Object... params) {
return new BsonWriter();
}
}, null, new Predicate<BsonWriter>() {
@Override
public boolean test(BsonWriter t) {
return t.recycle();
}
});
}
public byte[] toArray() {
if (count == content.length) return content;
byte[] newdata = new byte[count];
System.arraycopy(content, 0, newdata, 0, count);
return newdata;
}
public ByteBuffer[] toBuffers() {
return new ByteBuffer[]{ByteBuffer.wrap(content, 0, count)};
}
protected BsonWriter(byte[] bs) {
this.content = bs;
}
public BsonWriter() {
this(defaultSize);
}
public BsonWriter(int size) {
this.content = new byte[size > 128 ? size : 128];
}
@Override
public final boolean tiny() {
return tiny;
}
public BsonWriter tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
/**
* 扩充指定长度的缓冲区
*
* @param len 扩容长度
* @return 固定0
*/
protected int expand(int len) {
int newcount = count + len;
if (newcount <= content.length) return 0;
byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)];
System.arraycopy(content, 0, newdata, 0, count);
this.content = newdata;
return 0;
}
public void writeTo(final byte ch) {
expand(1);
content[count++] = ch;
}
public final void writeTo(final byte... chs) {
writeTo(chs, 0, chs.length);
}
public void writeTo(final byte[] chs, final int start, final int len) {
expand(len);
System.arraycopy(chs, start, content, count, len);
count += len;
}
protected boolean recycle() {
this.count = 0;
if (this.content.length > defaultSize) {
this.content = new byte[defaultSize];
}
return true;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[count=" + this.count + "]";
}
//------------------------------------------------------------------------
public final int count() {
return this.count;
}
@Override
public final void writeBoolean(boolean value) {
writeTo(value ? (byte) 1 : (byte) 0);
}
@Override
public final void writeByte(byte value) {
writeTo(value);
}
@Override
public final void writeChar(final char value) {
writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF));
}
@Override
public final void writeShort(short value) {
writeTo((byte) (value >> 8), (byte) value);
}
@Override
public final void writeInt(int value) {
writeTo((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value);
}
@Override
public final void writeLong(long value) {
writeTo((byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32),
(byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value);
}
@Override
public final void writeFloat(float value) {
writeInt(Float.floatToIntBits(value));
}
@Override
public final void writeDouble(double value) {
writeLong(Double.doubleToLongBits(value));
}
@Override
public final void wirteClassName(String clazz) {
writeSmallString(clazz == null ? "" : clazz);
}
@Override
public final void writeObjectB(Object obj) {
super.writeObjectB(obj);
writeSmallString("");
writeShort(BsonReader.SIGN_OBJECTB);
}
@Override
public final void writeObjectE(Object obj) {
writeByte(BsonReader.SIGN_NONEXT);
writeShort(BsonReader.SIGN_OBJECTE);
}
@Override
public final void writeFieldName( Attribute attribute) {
writeByte(BsonReader.SIGN_HASNEXT);
writeSmallString(attribute.field());
byte typeval = 127; //字段的类型值
final Class type = attribute.type();
if (type == boolean.class || type == Boolean.class) {
typeval = 1;
} else if (type == byte.class || type == Byte.class) {
typeval = 2;
} else if (type == short.class || type == Short.class) {
typeval = 3;
} else if (type == char.class || type == Character.class) {
typeval = 4;
} else if (type == int.class || type == Integer.class) {
typeval = 5;
} else if (type == long.class || type == Long.class) {
typeval = 6;
} else if (type == float.class || type == Float.class) {
typeval = 7;
} else if (type == double.class || type == Double.class) {
typeval = 8;
} else if (type == String.class) {
typeval = 9;
} else if (type == boolean[].class || type == Boolean[].class) {
typeval = 101;
} else if (type == byte[].class || type == Byte[].class) {
typeval = 102;
} else if (type == short[].class || type == Short[].class) {
typeval = 103;
} else if (type == char[].class || type == Character[].class) {
typeval = 104;
} else if (type == int[].class || type == Integer[].class) {
typeval = 105;
} else if (type == long[].class || type == Long[].class) {
typeval = 106;
} else if (type == float[].class || type == Float[].class) {
typeval = 107;
} else if (type == double[].class || type == Double[].class) {
typeval = 108;
} else if (type == String[].class) {
typeval = 109;
}
writeByte(typeval);
}
/**
* 对于类的字段名、枚举值这些长度一般不超过255且不会出现双字节字符的字符串采用writeSmallString处理, readSmallString用于读取
*
* @param value String值
*/
@Override
public final void writeSmallString(String value) {
if (value.isEmpty()) {
writeTo((byte) 0);
return;
}
char[] chars = Utility.charArray(value);
if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length");
byte[] bytes = new byte[chars.length + 1];
bytes[0] = (byte) chars.length;
for (int i = 0; i < chars.length; i++) {
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word");
bytes[i + 1] = (byte) chars[i];
}
writeTo(bytes);
}
@Override
public final void writeString(String value) {
if (value == null) {
writeInt(Reader.SIGN_NULL);
return;
} else if (value.isEmpty()) {
writeInt(0);
return;
}
byte[] bytes = Utility.encodeUTF8(value);
writeInt(bytes.length);
writeTo(bytes);
}
@Override
public final void writeNull() {
writeShort(Reader.SIGN_NULL);
}
@Override
public final void writeArrayB(int size) {
writeInt(size);
}
@Override
public final void writeArrayMark() {
}
@Override
public final void writeArrayE() {
}
@Override
public void writeMapB(int size) {
writeArrayB(size);
}
@Override
public final void writeMapMark() {
}
@Override
public final void writeMapE() {
}
}

View File

@@ -0,0 +1,4 @@
/**
* 提供BSON的序列化和反解析功能
*/
package org.redkale.convert.bson;

View File

@@ -0,0 +1,68 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
import org.redkale.convert.Reader;
import java.math.BigInteger;
/**
* BigInteger 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class BigIntegerSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, BigInteger> {
public static final BigIntegerSimpledCoder instance = new BigIntegerSimpledCoder();
@Override
public void convertTo(W out, BigInteger value) {
if (value == null) {
out.writeNull();
return;
}
ByteArraySimpledCoder.instance.convertTo(out, value.toByteArray());
}
@Override
public BigInteger convertFrom(R in) {
byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in);
return bytes == null ? null : new BigInteger(bytes);
}
/**
* BigInteger 的JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class BigIntegerJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, BigInteger> {
public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder();
@Override
public void convertTo(final Writer out, final BigInteger value) {
if (value == null) {
out.writeNull();
} else {
out.writeString(value.toString());
}
}
@Override
public BigInteger convertFrom(Reader in) {
final String str = in.readString();
if (str == null) return null;
return new BigInteger(str);
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* boolean[] 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class BoolArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, boolean[]> {
public static final BoolArraySimpledCoder instance = new BoolArraySimpledCoder();
@Override
public void convertTo(W out, boolean[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (boolean v : values) {
if (flag) out.writeArrayMark();
out.writeBoolean(v);
flag = true;
}
out.writeArrayE();
}
@Override
public boolean[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
boolean[] data = new boolean[8];
while (in.hasNext()) {
if (size >= data.length) {
boolean[] newdata = new boolean[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readBoolean();
}
in.readArrayE();
boolean[] newdata = new boolean[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
boolean[] values = new boolean[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readBoolean();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* boolean 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class BoolSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Boolean> {
public static final BoolSimpledCoder instance = new BoolSimpledCoder();
@Override
public void convertTo(W out, Boolean value) {
out.writeBoolean(value);
}
@Override
public Boolean convertFrom(R in) {
return in.readBoolean();
}
}

View File

@@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* byte[] 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class ByteArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, byte[]> {
public static final ByteArraySimpledCoder instance = new ByteArraySimpledCoder();
@Override
public void convertTo(W out, byte[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (byte v : values) {
if (flag) out.writeArrayMark();
out.writeByte(v);
flag = true;
}
out.writeArrayE();
}
@Override
public byte[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
byte[] data = new byte[8];
while (in.hasNext()) {
if (size >= data.length) {
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readByte();
}
in.readArrayE();
byte[] newdata = new byte[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
byte[] values = new byte[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readByte();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* byte 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class ByteSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Byte> {
public static final ByteSimpledCoder instance = new ByteSimpledCoder();
@Override
public void convertTo(W out, Byte value) {
out.writeByte(value);
}
@Override
public Byte convertFrom(R in) {
return in.readByte();
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* char[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class CharArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, char[]> {
public static final CharArraySimpledCoder instance = new CharArraySimpledCoder();
@Override
public void convertTo(W out, char[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (char v : values) {
if (flag) out.writeArrayMark();
out.writeChar(v);
flag = true;
}
out.writeArrayE();
}
@Override
public char[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
char[] data = new char[8];
while (in.hasNext()) {
if (size >= data.length) {
char[] newdata = new char[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readChar();
}
in.readArrayE();
char[] newdata = new char[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
char[] values = new char[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readChar();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,31 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.*;
/**
* CharSequence 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class CharSequenceSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, CharSequence> {
public static final CharSequenceSimpledCoder instance = new CharSequenceSimpledCoder();
@Override
public void convertTo(W out, CharSequence value) {
out.writeString(value == null ? null : value.toString());
}
@Override
public CharSequence convertFrom(R in) {
return in.readString();
}
}

View File

@@ -0,0 +1,35 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* char 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class CharSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Character> {
public static final CharSimpledCoder instance = new CharSimpledCoder();
@Override
public void convertTo(W out, Character value) {
out.writeChar(value);
}
@Override
public Character convertFrom(R in) {
return in.readChar();
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.nio.channels.*;
import org.redkale.convert.*;
/**
* java.nio.channels.CompletionHandler 的SimpledCoder实现, 只输出null
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class CompletionHandlerSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, CompletionHandler> {
public static final CompletionHandlerSimpledCoder instance = new CompletionHandlerSimpledCoder();
@Override
public void convertTo(W out, CompletionHandler value) {
out.writeObjectNull(CompletionHandler.class);
}
@Override
public CompletionHandler convertFrom(R in) {
in.readObjectB(CompletionHandler.class);
return null;
}
}

View File

@@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.Writer;
import org.redkale.convert.SimpledCoder;
import org.redkale.util.*;
/**
* Dlong 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class DLongSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, DLong> {
private static final ByteArraySimpledCoder bsSimpledCoder = ByteArraySimpledCoder.instance;
public static final DLongSimpledCoder instance = new DLongSimpledCoder();
@Override
public void convertTo(final W out, final DLong value) {
if (value == null) {
out.writeNull();
} else {
bsSimpledCoder.convertTo(out, value.directBytes());
}
}
@Override
public DLong convertFrom(R in) {
byte[] bs = bsSimpledCoder.convertFrom(in);
if (bs == null) return null;
return DLong.create(bs);
}
/**
* DLong 的JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class DLongJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, DLong> {
public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder();
@Override
public void convertTo(final Writer out, final DLong value) {
if (value == null) {
out.writeNull();
} else {
out.writeSmallString(value.toString());
}
}
@Override
public DLong convertFrom(Reader in) {
final String str = in.readSmallString();
if (str == null) return null;
return DLong.create(Utility.hexToBin(str));
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
import java.util.Date;
/**
* Date 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class DateSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Date> {
public static final DateSimpledCoder instance = new DateSimpledCoder();
@Override
public void convertTo(W out, Date value) {
out.writeLong(value.getTime());
}
@Override
public Date convertFrom(R in) {
return new Date(in.readLong());
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* double[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class DoubleArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, double[]> {
public static final DoubleArraySimpledCoder instance = new DoubleArraySimpledCoder();
@Override
public void convertTo(W out, double[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (double v : values) {
if (flag) out.writeArrayMark();
out.writeDouble(v);
flag = true;
}
out.writeArrayE();
}
@Override
public double[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
double[] data = new double[8];
while (in.hasNext()) {
if (size >= data.length) {
double[] newdata = new double[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readDouble();
}
in.readArrayE();
double[] newdata = new double[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
double[] values = new double[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readDouble();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* double 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class DoubleSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Double> {
public static final DoubleSimpledCoder instance = new DoubleSimpledCoder();
@Override
public void convertTo(W out, Double value) {
out.writeDouble(value);
}
@Override
public Double convertFrom(R in) {
return in.readDouble();
}
}

View File

@@ -0,0 +1,48 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* 枚举 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
* @param <E> Enum的子类
*/
public final class EnumSimpledCoder<R extends Reader, W extends Writer, E extends Enum> extends SimpledCoder<R, W, E> {
private final Class<E> type;
public EnumSimpledCoder(Class<E> type) {
this.type = type;
}
@Override
public void convertTo(final W out, final E value) {
if (value == null) {
out.writeNull();
} else {
out.writeSmallString(value.toString());
}
}
@Override
@SuppressWarnings("unchecked")
public E convertFrom(final R in) {
String value = in.readSmallString();
if (value == null) return null;
return (E) Enum.valueOf(type, value);
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* float[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class FloatArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, float[]> {
public static final FloatArraySimpledCoder instance = new FloatArraySimpledCoder();
@Override
public void convertTo(W out, float[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (float v : values) {
if (flag) out.writeArrayMark();
out.writeFloat(v);
flag = true;
}
out.writeArrayE();
}
@Override
public float[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
float[] data = new float[8];
while (in.hasNext()) {
if (size >= data.length) {
float[] newdata = new float[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readFloat();
}
in.readArrayE();
float[] newdata = new float[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
float[] values = new float[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readFloat();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* float 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class FloatSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Float> {
public static final FloatSimpledCoder instance = new FloatSimpledCoder();
@Override
public void convertTo(W out, Float value) {
out.writeFloat(value);
}
@Override
public Float convertFrom(R in) {
return in.readFloat();
}
}

View File

@@ -0,0 +1,145 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
import org.redkale.convert.Reader;
import java.net.*;
/**
* InetAddress 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> {
public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder();
@Override
public void convertTo(W out, InetAddress value) {
if (value == null) {
out.writeNull();
return;
}
ByteArraySimpledCoder.instance.convertTo(out, value.getAddress());
}
@Override
public InetAddress convertFrom(R in) {
byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in);
if (bytes == null) return null;
try {
return InetAddress.getByAddress(bytes);
} catch (Exception ex) {
return null;
}
}
/**
* InetSocketAddress 的SimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final static class InetSocketAddressSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> {
public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder();
@Override
public void convertTo(W out, InetSocketAddress value) {
if (value == null) {
out.writeNull();
return;
}
ByteArraySimpledCoder.instance.convertTo(out, value.getAddress().getAddress());
out.writeInt(value.getPort());
}
@Override
public InetSocketAddress convertFrom(R in) {
byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in);
if (bytes == null) return null;
int port = in.readInt();
try {
return new InetSocketAddress(InetAddress.getByAddress(bytes), port);
} catch (Exception ex) {
return null;
}
}
}
/**
* InetAddress 的JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final static class InetAddressJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> {
public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder();
@Override
public void convertTo(W out, InetAddress value) {
if (value == null) {
out.writeNull();
return;
}
StringSimpledCoder.instance.convertTo(out, value.getHostAddress());
}
@Override
public InetAddress convertFrom(R in) {
String str = StringSimpledCoder.instance.convertFrom(in);
if (str == null) return null;
try {
return InetAddress.getByName(str);
} catch (Exception ex) {
return null;
}
}
}
/**
* InetSocketAddress 的JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final static class InetSocketAddressJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> {
public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder();
@Override
public void convertTo(W out, InetSocketAddress value) {
if (value == null) {
out.writeNull();
return;
}
StringSimpledCoder.instance.convertTo(out, value.getHostString() + ":" + value.getPort());
}
@Override
public InetSocketAddress convertFrom(R in) {
String str = StringSimpledCoder.instance.convertFrom(in);
if (str == null) return null;
try {
int pos = str.indexOf(':');
return new InetSocketAddress(str.substring(0, pos), Integer.parseInt(str.substring(pos + 1)));
} catch (Exception ex) {
return null;
}
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* int[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class IntArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, int[]> {
public static final IntArraySimpledCoder instance = new IntArraySimpledCoder();
@Override
public void convertTo(W out, int[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (int v : values) {
if (flag) out.writeArrayMark();
out.writeInt(v);
flag = true;
}
out.writeArrayE();
}
@Override
public int[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
int[] data = new int[8];
while (in.hasNext()) {
if (size >= data.length) {
int[] newdata = new int[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readInt();
}
in.readArrayE();
int[] newdata = new int[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
int[] values = new int[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readInt();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* int 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class IntSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Integer> {
public static final IntSimpledCoder instance = new IntSimpledCoder();
@Override
public void convertTo(W out, Integer value) {
out.writeInt(value);
}
@Override
public Integer convertFrom(R in) {
return in.readInt();
}
}

View File

@@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* long[] 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class LongArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, long[]> {
public static final LongArraySimpledCoder instance = new LongArraySimpledCoder();
@Override
public void convertTo(W out, long[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (long v : values) {
if (flag) out.writeArrayMark();
out.writeLong(v);
flag = true;
}
out.writeArrayE();
}
@Override
public long[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
long[] data = new long[8];
while (in.hasNext()) {
if (size >= data.length) {
long[] newdata = new long[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readLong();
}
in.readArrayE();
long[] newdata = new long[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
long[] values = new long[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readLong();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* long 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class LongSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Long> {
public static final LongSimpledCoder instance = new LongSimpledCoder();
@Override
public void convertTo(W out, Long value) {
out.writeLong(value);
}
@Override
public Long convertFrom(R in) {
return in.readLong();
}
}

View File

@@ -0,0 +1,36 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* Number 的SimpledCoder实现
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class NumberSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Number> {
public static final NumberSimpledCoder instance = new NumberSimpledCoder();
@Override
public void convertTo(W out, Number value) {
out.writeLong(value == null ? 0L : value.longValue());
}
@Override
public Number convertFrom(R in) {
return in.readLong();
}
}

View File

@@ -0,0 +1,40 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.util.regex.*;
import org.redkale.convert.*;
/**
* Pattern 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class PatternSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Pattern> {
public static final PatternSimpledCoder instance = new PatternSimpledCoder();
@Override
public void convertTo(W out, Pattern value) {
if (value == null) {
out.writeNull();
} else {
out.writeString(value.flags() + "," + value.pattern());
}
}
@Override
public Pattern convertFrom(R in) {
String value = in.readString();
if (value == null) return null;
int pos = value.indexOf(',');
return Pattern.compile(value.substring(pos + 1), Integer.parseInt(value.substring(0, pos)));
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* short[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class ShortArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, short[]> {
public static final ShortArraySimpledCoder instance = new ShortArraySimpledCoder();
@Override
public void convertTo(W out, short[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (short v : values) {
if (flag) out.writeArrayMark();
out.writeShort(v);
flag = true;
}
out.writeArrayE();
}
@Override
public short[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
short[] data = new short[8];
while (in.hasNext()) {
if (size >= data.length) {
short[] newdata = new short[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readShort();
}
in.readArrayE();
short[] newdata = new short[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
short[] values = new short[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readShort();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* short 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class ShortSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Short> {
public static final ShortSimpledCoder instance = new ShortSimpledCoder();
@Override
public void convertTo(W out, Short value) {
out.writeShort(value);
}
@Override
public Short convertFrom(R in) {
return in.readShort();
}
}

View File

@@ -0,0 +1,69 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* String[] 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class StringArraySimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, String[]> {
public static final StringArraySimpledCoder instance = new StringArraySimpledCoder();
@Override
public void convertTo(W out, String[] values) {
if (values == null) {
out.writeNull();
return;
}
out.writeArrayB(values.length);
boolean flag = false;
for (String v : values) {
if (flag) out.writeArrayMark();
out.writeString(v);
flag = true;
}
out.writeArrayE();
}
@Override
public String[] convertFrom(R in) {
int len = in.readArrayB();
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENGTH) {
int size = 0;
String[] data = new String[8];
while (in.hasNext()) {
if (size >= data.length) {
String[] newdata = new String[data.length + 4];
System.arraycopy(data, 0, newdata, 0, size);
data = newdata;
}
data[size++] = in.readString();
}
in.readArrayE();
String[] newdata = new String[size];
System.arraycopy(data, 0, newdata, 0, size);
return newdata;
} else {
String[] values = new String[len];
for (int i = 0; i < values.length; i++) {
values[i] = in.readString();
}
in.readArrayE();
return values;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer;
/**
* String 的SimpledCoder实现
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public final class StringSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, String> {
public static final StringSimpledCoder instance = new StringSimpledCoder();
@Override
public void convertTo(W out, String value) {
out.writeString(value);
}
@Override
public String convertFrom(R in) {
return in.readString();
}
}

View File

@@ -0,0 +1,46 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import org.redkale.convert.Reader;
import org.redkale.convert.Writer;
import org.redkale.convert.SimpledCoder;
/**
* Type 的SimpledCoder实现 只支持Type的子类Class
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public class TypeSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Class> {
public static final TypeSimpledCoder instance = new TypeSimpledCoder();
@Override
public void convertTo(final W out, final Class value) {
if (value == null) {
out.writeNull();
} else {
out.writeSmallString(value.getName());
}
}
@Override
public Class convertFrom(R in) {
String str = in.readSmallString();
if (str == null) return null;
try {
return Class.forName(str);
} catch (Exception e) {
return null;
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.net.*;
import org.redkale.convert.*;
/**
*
* @author zhangjx
*/
public class URISimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, URI> {
public static final URLSimpledCoder instance = new URLSimpledCoder();
@Override
public void convertTo(final Writer out, final URI value) {
if (value == null) {
out.writeNull();
} else {
out.writeString(value.toString());
}
}
@Override
public URI convertFrom(Reader in) {
final String str = in.readString();
if (str == null) return null;
try {
return new URI(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.ext;
import java.net.*;
import org.redkale.convert.*;
/**
*
* @author zhangjx
*/
public class URLSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, URL> {
public static final URLSimpledCoder instance = new URLSimpledCoder();
@Override
public void convertTo(final Writer out, final URL value) {
if (value == null) {
out.writeNull();
} else {
out.writeString(value.toString());
}
}
@Override
public URL convertFrom(Reader in) {
final String str = in.readString();
if (str == null) return null;
try {
return new URL(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,4 @@
/**
* Convert的基本数据的Coder实现
*/
package org.redkale.convert.ext;

View File

@@ -0,0 +1,336 @@
/*
* 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.json;
import java.nio.*;
import java.nio.charset.*;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.*;
/**
* 只支持UTF-8格式
*
* @author zhangjx
*/
public class JsonByteBufferReader extends JsonReader {
private char currentChar;
private ByteBuffer[] buffers;
private int currentIndex = 0;
private ByteBuffer currentBuffer;
protected JsonByteBufferReader(ByteBuffer... buffers) {
this.buffers = buffers;
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
}
@Override
protected boolean recycle() {
super.recycle(); // this.position 初始化值为-1
this.currentIndex = 0;
this.currentChar = 0;
this.currentBuffer = null;
this.buffers = null;
return false;
}
protected byte nextByte() {
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
}
for (;;) {
this.currentBuffer = this.buffers[++this.currentIndex];
if (this.currentBuffer.hasRemaining()) {
this.position++;
return this.currentBuffer.get();
}
}
}
/**
* 读取下一个字符, 不跳过空白字符
*
* @return 有效字符或空白字符
*/
@Override
protected final char nextChar() {
if (currentChar != 0) {
char ch = currentChar;
this.currentChar = 0;
return ch;
}
if (this.currentBuffer != null) {
int remain = this.currentBuffer.remaining();
if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0;
}
byte b1 = nextByte();
if (b1 >= 0) {// 1 byte, 7 bits: 0xxxxxxx
return (char) b1;
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx
return (char) (((b1 << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80)));
} else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
return (char) ((b1 << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
} else { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
throw new RuntimeException(new UnmappableCharacterException(4));
}
}
/**
* 读取下一个有效字符
*
* @return 有效字符
*/
@Override
protected final char nextGoodChar() {
char c = nextChar();
if (c > ' ' || c == 0) return c; // 0 表示buffer结尾了
for (;;) {
c = nextChar();
if (c > ' ' || c == 0) return c;
}
}
/**
* 回退最后读取的字符
*
* @param ch 回退的字符
*/
@Override
protected final void backChar(char ch) {
this.currentChar = ch;
}
/**
* 判断下一个非空白字符是否为{
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final String readObjectB(final Class clazz) {
char ch = nextGoodChar();
if (ch == '{') return "";
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null;
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "'");
}
/**
* 判断下一个非空白字符是否为[
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readArrayB() {
char ch = nextGoodChar();
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL;
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "'");
}
/**
* 判断下一个非空白字符是否:
*/
@Override
public final void readBlank() {
char ch = nextGoodChar();
if (ch == ':') return;
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ")");
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @return 是否存在
*/
@Override
public final boolean hasNext() {
char ch = nextGoodChar();
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
return true;
}
/**
* 读取小字符串
*
* @return String值
*/
@Override
public final String readSmallString() {
char ch = nextGoodChar();
if (ch == 0) return null;
final StringBuilder sb = new StringBuilder();
if (ch == '"' || ch == '\'') {
final char quote = ch;
for (;;) {
ch = nextChar();
if (ch == '\\') {
char c = nextChar();
switch (c) {
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 'u':
sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16));
break;
case 't':
sb.append('\t');
break;
case 'b':
sb.append('\b');
break;
case 'f':
sb.append('\f');
break;
default:
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
}
} else if (ch == quote || ch == 0) {
break;
} else {
sb.append(ch);
}
}
return sb.toString();
} else {
sb.append(ch);
for (;;) {
ch = nextChar();
if (ch == '\\') {
char c = nextChar();
switch (c) {
case '"':
case '\'':
case '\\':
case '/':
sb.append(c);
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 'u':
sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16));
break;
case 't':
sb.append('\t');
break;
case 'b':
sb.append('\b');
break;
case 'f':
sb.append('\f');
break;
default:
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
}
} else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0
break;
} else {
sb.append(ch);
}
}
String rs = sb.toString();
return "null".equalsIgnoreCase(rs) ? null : rs;
}
}
/**
* 读取一个int值
*
* @return int值
*/
@Override
public final int readInt() {
char firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
if (firstchar == '"' || firstchar == '\'') return 0;
}
int value = 0;
final boolean negative = firstchar == '-';
if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
value = firstchar - '0';
}
for (;;) {
char ch = nextChar();
if (ch == 0) break;
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
} else {
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
}
}
return negative ? -value : value;
}
/**
* 读取一个long值
*
* @return long值
*/
@Override
public final long readLong() {
char firstchar = nextGoodChar();
if (firstchar == '"' || firstchar == '\'') {
firstchar = nextChar();
if (firstchar == '"' || firstchar == '\'') return 0L;
}
long value = 0;
final boolean negative = firstchar == '-';
if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
value = firstchar - '0';
}
for (;;) {
char ch = nextChar();
if (ch == 0) break;
if (ch >= '0' && ch <= '9') {
value = (value << 3) + (value << 1) + (ch - '0');
} else if (ch == '"' || ch == '\'') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
} else {
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
}
}
return negative ? -value : value;
}
/**
* 读取字符串, 必须是"或者'包围的字符串值
*
* @return String值
*/
@Override
public final String readString() {
return readSmallString();
}
}

View File

@@ -0,0 +1,352 @@
/*
* 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.json;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import java.util.function.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class JsonByteBufferWriter extends JsonWriter {
protected static final Charset UTF8 = Charset.forName("UTF-8");
protected Charset charset;
private final Supplier<ByteBuffer> supplier;
private ByteBuffer[] buffers;
private int index;
protected JsonByteBufferWriter(boolean tiny, Supplier<ByteBuffer> supplier) {
this(tiny, null, supplier);
}
protected JsonByteBufferWriter(boolean tiny, Charset charset, Supplier<ByteBuffer> supplier) {
this.tiny = tiny;
this.charset = UTF8.equals(charset) ? null : charset;
this.supplier = supplier;
}
@Override
public JsonByteBufferWriter tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
@Override
protected boolean recycle() {
this.index = 0;
this.charset = null;
this.buffers = null;
return false;
}
@Override
public ByteBuffer[] toBuffers() {
if (buffers == null) return new ByteBuffer[0];
for (int i = index; i < this.buffers.length; i++) {
ByteBuffer buf = this.buffers[i];
if (buf.position() != 0) buf.flip();
}
return this.buffers;
}
@Override
public int count() {
if (this.buffers == null) return 0;
int len = 0;
for (ByteBuffer buffer : buffers) {
len += buffer.remaining();
}
return len;
}
private int expand(final int byteLength) {
if (this.buffers == null) {
this.index = 0;
this.buffers = new ByteBuffer[]{supplier.get()};
}
ByteBuffer buffer = this.buffers[index];
if (!buffer.hasRemaining()) {
buffer.flip();
buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1];
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
this.index++;
}
int len = buffer.remaining();
int size = 0;
while (len < byteLength) {
buffer = supplier.get();
ByteBuffer[] bufs = new ByteBuffer[this.buffers.length + 1];
System.arraycopy(this.buffers, 0, bufs, 0, this.buffers.length);
bufs[this.buffers.length] = buffer;
this.buffers = bufs;
len += buffer.remaining();
size++;
}
return size;
}
@Override
public void writeTo(final char ch) {
if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127");
expand(1);
this.buffers[index].put((byte) ch);
}
@Override
public void writeTo(final char[] chs, final int start, final int len) {
writeTo(-1, false, chs, start, len);
}
private void writeTo(int expandsize, final boolean quote, final char[] chs, final int start, final int len) {
int byteLength = quote ? 2 : 0;
ByteBuffer bb = null;
if (charset == null) {
byteLength += encodeUTF8Length(chs, start, len);
} else {
bb = charset.encode(CharBuffer.wrap(chs, start, len));
byteLength += bb.remaining();
}
if (expandsize < 0) expandsize = expand(byteLength);
if (expandsize == 0) { // 只需要一个buffer
final ByteBuffer buffer = this.buffers[index];
if (quote) buffer.put((byte) '"');
if (charset == null) { //UTF-8
final int limit = start + len;
for (int i = start; i < limit; i++) {
char c = chs[i];
if (c < 0x80) {
buffer.put((byte) c);
} else if (c < 0x800) {
buffer.put((byte) (0xc0 | (c >> 6)));
buffer.put((byte) (0x80 | (c & 0x3f)));
} else {
buffer.put((byte) (0xe0 | ((c >> 12))));
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
buffer.put((byte) (0x80 | (c & 0x3f)));
}
}
} else {
buffer.put(bb);
}
if (quote) buffer.put((byte) '"');
return;
}
ByteBuffer buffer = this.buffers[index];
if (quote) {
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
buffer.put((byte) '"');
}
if (charset == null) { //UTF-8
final int limit = start + len;
for (int i = start; i < limit; i++) {
buffer = putChar(buffer, chs[i]);
}
} else {
while (bb.hasRemaining()) {
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
buffer.put(bb.get());
}
}
if (quote) {
if (!buffer.hasRemaining()) buffer = nextByteBuffer();
buffer.put((byte) '"');
}
}
private ByteBuffer putChar(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 int limit = start + len;
for (int i = start; i < limit; i++) {
c = chars[i];
switch (c) {
case '\n': size += 2;
break;
case '\r': size += 2;
break;
case '\t': size += 2;
break;
case '\\': size += 2;
break;
case '"': size += 2;
break;
default:
size += (c < 0x80 ? 1 : (c < 0x800 ? 2 : 3));
break;
}
}
return size;
}
/**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String
*
* @param quote 是否写入双引号
* @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);
}
@Override
public void writeInt(int value) {
writeTo(false, String.valueOf(value));
}
@Override
public void writeLong(long value) {
writeTo(false, String.valueOf(value));
}
@Override
public void writeString(String value) {
if (value == null) {
writeNull();
return;
}
final char[] chs = Utility.charArray(value);
int len = 0;
for (char ch : chs) {
switch (ch) {
case '\n': len += 2;
break;
case '\r': len += 2;
break;
case '\t': len += 2;
break;
case '\\': len += 2;
break;
case '"': len += 2;
break;
default: len++;
break;
}
}
if (len == chs.length) {
writeTo(-1, true, chs, 0, len);
return;
}
int expandsize = -1;
if (this.charset == null) { //UTF-8
final int byteLength = 2 + encodeEscapeUTF8Length(chs, 0, chs.length);
expandsize = expand(byteLength);
if (expandsize == 0) { // 只需要一个buffer
final ByteBuffer buffer = this.buffers[index];
buffer.put((byte) '"');
for (char c : chs) {
switch (c) {
case '\n': buffer.put((byte) '\\').put((byte) 'n');
break;
case '\r': buffer.put((byte) '\\').put((byte) 'r');
break;
case '\t': buffer.put((byte) '\\').put((byte) 't');
break;
case '\\': buffer.put((byte) '\\').put((byte) '\\');
break;
case '"': buffer.put((byte) '\\').put((byte) '"');
break;
default:
if (c < 0x80) {
buffer.put((byte) c);
} else if (c < 0x800) {
buffer.put((byte) (0xc0 | (c >> 6)));
buffer.put((byte) (0x80 | (c & 0x3f)));
} else {
buffer.put((byte) (0xe0 | ((c >> 12))));
buffer.put((byte) (0x80 | ((c >> 6) & 0x3f)));
buffer.put((byte) (0x80 | (c & 0x3f)));
}
break;
}
}
buffer.put((byte) '"');
return;
}
}
StringBuilder sb = new StringBuilder(len);
for (char ch : chs) {
switch (ch) {
case '\n': sb.append("\\n");
break;
case '\r': sb.append("\\r");
break;
case '\t': sb.append("\\t");
break;
case '\\': sb.append("\\\\");
break;
case '"': sb.append("\\\"");
break;
default: sb.append(ch);
break;
}
}
char[] cs = Utility.charArray(sb);
writeTo(expandsize, true, cs, 0, sb.length());
}
@Override
public String toString() {
return Objects.toString(this);
}
}

View File

@@ -0,0 +1,207 @@
/*
* 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.json;
import java.io.*;
import java.lang.reflect.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.function.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class JsonConvert extends Convert<JsonReader, JsonWriter> {
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.LinkedHashMap<String, String>>() {
}.getType();
private static final ObjectPool<JsonReader> readerPool = JsonReader.createPool(Integer.getInteger("convert.json.pool.size", 16));
private static final ObjectPool<JsonWriter> writerPool = JsonWriter.createPool(Integer.getInteger("convert.json.pool.size", 16));
private final boolean tiny;
protected JsonConvert(JsonFactory factory, boolean tiny) {
super(factory);
this.tiny = tiny;
}
@Override
public JsonFactory getFactory() {
return (JsonFactory) factory;
}
public static JsonConvert root() {
return JsonFactory.root().getConvert();
}
//------------------------------ reader -----------------------------------------------------------
public JsonReader pollJsonReader(final ByteBuffer... buffers) {
return new JsonByteBufferReader(buffers);
}
public JsonReader pollJsonReader(final InputStream in) {
return new JsonStreamReader(in);
}
public JsonReader pollJsonReader() {
return readerPool.get();
}
public void offerJsonReader(final JsonReader in) {
if (in != null) readerPool.offer(in);
}
//------------------------------ writer -----------------------------------------------------------
public JsonByteBufferWriter pollJsonWriter(final Supplier<ByteBuffer> supplier) {
return new JsonByteBufferWriter(tiny, supplier);
}
public JsonWriter pollJsonWriter(final OutputStream out) {
return new JsonStreamWriter(tiny, out);
}
public JsonWriter pollJsonWriter(final Charset charset, final OutputStream out) {
return new JsonStreamWriter(tiny, charset, out);
}
public JsonWriter pollJsonWriter() {
return writerPool.get().tiny(tiny);
}
public void offerJsonWriter(final JsonWriter out) {
if (out != null) writerPool.offer(out);
}
//------------------------------ convertFrom -----------------------------------------------------------
public <T> T convertFrom(final Type type, final String text) {
if (text == null) return null;
return convertFrom(type, Utility.charArray(text));
}
public <T> T convertFrom(final Type type, final char[] text) {
if (text == null) return null;
return convertFrom(type, text, 0, text.length);
}
public <T> T convertFrom(final Type type, final char[] text, final int start, final int len) {
if (text == null || type == null) return null;
final JsonReader in = readerPool.get();
in.setText(text, start, len);
T rs = (T) factory.loadDecoder(type).convertFrom(in);
readerPool.offer(in);
return rs;
}
public <T> T convertFrom(final Type type, final InputStream in) {
if (type == null || in == null) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonStreamReader(in));
}
public <T> T convertFrom(final Type type, final ByteBuffer... buffers) {
if (type == null || buffers == null || buffers.length == 0) return null;
return (T) factory.loadDecoder(type).convertFrom(new JsonByteBufferReader(buffers));
}
public <T> T convertFrom(final Type type, final JsonReader reader) {
if (type == null) return null;
@SuppressWarnings("unchecked")
T rs = (T) factory.loadDecoder(type).convertFrom(reader);
return rs;
}
//------------------------------ convertTo -----------------------------------------------------------
public String convertTo(final Object value) {
if (value == null) return "null";
return convertTo(value.getClass(), value);
}
public String convertTo(final Type type, final Object value) {
if (type == null) return null;
if (value == null) return "null";
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
String result = out.toString();
writerPool.offer(out);
return result;
}
public void convertTo(final OutputStream out, final Object value) {
if (value == null) {
new JsonStreamWriter(tiny, out).writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(new JsonStreamWriter(tiny, out), value);
}
}
public void convertTo(final OutputStream out, final Type type, final Object value) {
if (type == null) return;
if (value == null) {
new JsonStreamWriter(tiny, out).writeNull();
} else {
factory.loadEncoder(type).convertTo(new JsonStreamWriter(tiny, out), value);
}
}
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value) {
if (supplier == null) return null;
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
if (value == null) {
out.writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(out, value);
}
return out.toBuffers();
}
public ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value) {
if (supplier == null || type == null) return null;
JsonByteBufferWriter out = new JsonByteBufferWriter(tiny, null, supplier);
if (value == null) {
out.writeNull();
} else {
factory.loadEncoder(type).convertTo(out, value);
}
return out.toBuffers();
}
public void convertTo(final JsonWriter writer, final Object value) {
if (value == null) {
writer.writeNull();
} else {
factory.loadEncoder(value.getClass()).convertTo(writer, value);
}
}
public void convertTo(final JsonWriter writer, final Type type, final Object value) {
if (type == null) return;
if (value == null) {
writer.writeNull();
} else {
factory.loadEncoder(type).convertTo(writer, value);
}
}
public JsonWriter convertToWriter(final Object value) {
if (value == null) return null;
return convertToWriter(value.getClass(), value);
}
public JsonWriter convertToWriter(final Type type, final Object value) {
if (type == null) return null;
final JsonWriter out = writerPool.get().tiny(tiny);
factory.loadEncoder(type).convertTo(out, value);
return out;
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.json;
import org.redkale.convert.ConvertType;
import org.redkale.convert.ConvertFactory;
import java.io.Serializable;
import java.math.*;
import java.net.*;
import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
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));
}
private JsonFactory(JsonFactory parent, boolean tiny) {
super(parent, tiny);
}
@Override
public JsonFactory tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
public static JsonFactory root() {
return instance;
}
@Override
public final JsonConvert getConvert() {
if (convert == null) convert = new JsonConvert(this, tiny);
return (JsonConvert) convert;
}
@Override
public JsonFactory createChild() {
return new JsonFactory(this, this.tiny);
}
@Override
public JsonFactory createChild(boolean tiny) {
return new JsonFactory(this, tiny);
}
@Override
public ConvertType getConvertType() {
return ConvertType.JSON;
}
@Override
public boolean isReversible() {
return false;
}
}

View File

@@ -0,0 +1,582 @@
/*
* 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.json;
import org.redkale.convert.*;
import static org.redkale.convert.Reader.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class JsonReader extends Reader {
protected int position = -1;
private char[] text;
private int limit;
public static ObjectPool<JsonReader> createPool(int max) {
return new ObjectPool<>(max, (Object... params) -> new JsonReader(), null, JsonReader::recycle);
}
public JsonReader() {
}
public JsonReader(String json) {
setText(Utility.charArray(json));
}
public JsonReader(char[] text) {
setText(text, 0, text.length);
}
public JsonReader(char[] text, int start, int len) {
setText(text, start, len);
}
public final void setText(String text) {
setText(Utility.charArray(text));
}
public final void setText(char[] text) {
setText(text, 0, text.length);
}
public final void setText(char[] text, int start, int len) {
this.text = text;
this.position = start - 1;
this.limit = start + len - 1;
}
protected boolean recycle() {
this.position = -1;
this.limit = -1;
this.text = null;
return true;
}
public void close() {
this.recycle();
}
/**
* 找到指定的属性值 例如: {id : 1, data : { name : 'a', items : [1,2,3]}} seek('data.items') 直接跳转到 [1,2,3];
*
* @param key 指定的属性名
*/
public final void seek(String key) {
if (key == null || key.length() < 1) return;
final String[] keys = key.split("\\.");
nextGoodChar(); //读掉 { [
for (String key1 : keys) {
while (this.hasNext()) {
String field = this.readSmallString();
readBlank();
if (key1.equals(field)) break;
skipValue();
}
}
}
/**
* 跳过属性的值
*/
@Override
public final void skipValue() {
final char ch = nextGoodChar();
switch (ch) {
case '"':
case '\'':
backChar(ch);
readString();
break;
case '{':
while (hasNext()) {
this.readSmallString(); //读掉field
this.readBlank();
this.skipValue();
}
break;
case '[':
while (hasNext()) {
this.skipValue();
}
break;
default:
char c;
for (;;) {
c = nextChar();
if (c <= ' ') return;
if (c == '}' || c == ']' || c == ',' || c == ':') {
backChar(c);
return;
}
}
}
}
/**
* 读取下一个字符, 不跳过空白字符
*
* @return 空白字符或有效字符
*/
protected char nextChar() {
return this.text[++this.position];
}
/**
* 跳过空白字符, 返回一个非空白字符
*
* @return 有效字符
*/
protected char nextGoodChar() {
char c = nextChar();
if (c > ' ') return c;
for (;;) {
c = nextChar();
if (c > ' ') return c;
}
}
/**
* 回退最后读取的字符
*
* @param ch 后退的字符
*/
protected void backChar(char ch) {
this.position--;
}
/**
* 判断下一个非空白字符是否为{
*
* @param clazz 类名
* @return 返回 null 表示对象为null 返回空字符串表示当前class与返回的class一致返回非空字符串表示class是当前class的子类。
*/
@Override
public String readObjectB(final Class clazz) {
this.fieldIndex = 0; //必须要重置为0
char ch = this.text[++this.position];
if (ch == '{') return "";
if (ch <= ' ') {
for (;;) {
ch = this.text[++this.position];
if (ch > ' ') break;
}
if (ch == '{') return "";
}
if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return null;
if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return null;
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")");
}
@Override
public final void readObjectE(final Class clazz) {
}
/**
* 判断下一个非空白字符是否为{
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public final int readMapB() {
return readArrayB();
}
@Override
public final void readMapE() {
}
/**
* 判断下一个非空白字符是否为[
*
* @return SIGN_NOLENGTH 或 SIGN_NULL
*/
@Override
public int readArrayB() {
char ch = this.text[++this.position];
if (ch == '[') return SIGN_NOLENGTH;
if (ch == '{') return SIGN_NOLENGTH;
if (ch <= ' ') {
for (;;) {
ch = this.text[++this.position];
if (ch > ' ') break;
}
if (ch == '[') return SIGN_NOLENGTH;
if (ch == '{') return SIGN_NOLENGTH;
}
if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return SIGN_NULL;
if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return SIGN_NULL;
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")");
}
@Override
public final void readArrayE() {
}
/**
* 判断下一个非空白字符是否:
*/
@Override
public void readBlank() {
char ch = this.text[++this.position];
if (ch == ':') return;
if (ch <= ' ') {
for (;;) {
ch = this.text[++this.position];
if (ch > ' ') break;
}
if (ch == ':') return;
}
throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")");
}
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @return 是否存在
*/
@Override
public boolean hasNext() {
char ch = this.text[++this.position];
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
if (ch <= ' ') {
for (;;) {
ch = this.text[++this.position];
if (ch > ' ') break;
}
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
}
this.position--; // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
return true;
}
@Override
public final String readClassName() {
return null;
}
@Override
public String readSmallString() {
final int eof = this.limit;
if (this.position == eof) return null;
final char[] text0 = this.text;
int currpos = this.position;
char ch = text0[++currpos];
if (ch <= ' ') {
for (;;) {
ch = text0[++currpos];
if (ch > ' ') break;
}
}
if (ch == '"' || ch == '\'') {
final char quote = ch;
final int start = currpos + 1;
for (;;) {
ch = text0[++currpos];
if (ch == '\\') {
this.position = currpos - 1;
return readEscapeValue(quote, start);
} else if (ch == quote) {
break;
}
}
this.position = currpos;
char[] chs = new char[currpos - start];
System.arraycopy(text0, start, chs, 0, chs.length);
return new String(chs);
} else {
int start = currpos;
for (;;) {
if (currpos == eof) break;
ch = text0[++currpos];
if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') break;
}
int len = currpos - start;
if (len < 1) {
this.position = currpos;
return String.valueOf(ch);
}
this.position = currpos - 1;
if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null;
return new String(text0, start, len);
}
}
/**
* 读取一个int值
*
* @return int值
*/
@Override
public int readInt() {
final char[] text0 = this.text;
final int eof = this.limit;
int currpos = this.position;
char firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
firstchar = text0[++currpos];
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0;
}
}
int value = 0;
final boolean negative = firstchar == '-';
if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")");
value = firstchar - '0';
}
for (;;) {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
this.position = currpos - 1;
return negative ? -value : value;
}
/**
* 读取一个long值
*
* @return long值
*/
@Override
public long readLong() {
final char[] text0 = this.text;
final int eof = this.limit;
int currpos = this.position;
char firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
firstchar = text0[++currpos];
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0L;
}
}
long value = 0;
final boolean negative = firstchar == '-';
if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")");
value = firstchar - '0';
}
for (;;) {
if (currpos == eof) break;
char ch = text0[++currpos];
int val = digits[ch];
if (val == -3) break;
if (val == -1) throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")");
if (val != -2) value = value * 10 + val;
}
this.position = currpos - 1;
return negative ? -value : value;
}
@Override
public final DeMember readFieldName(final DeMember[] members) {
final String exceptedfield = this.readSmallString();
final int len = members.length;
if (this.fieldIndex >= len) this.fieldIndex = 0;
for (int k = this.fieldIndex; k < len; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) {
this.fieldIndex = k;
return members[k];
}
}
for (int k = 0; k < this.fieldIndex; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) {
this.fieldIndex = k;
return members[k];
}
}
return null;
//if (result == null && len == 1 && text0[start] == '@') return REFER;
}
//------------------------------------------------------------
@Override
public final boolean readBoolean() {
return "true".equalsIgnoreCase(this.readSmallString());
}
@Override
public final byte readByte() {
return (byte) readInt();
}
@Override
public final char readChar() {
return (char) readInt();
}
@Override
public final short readShort() {
return (short) readInt();
}
@Override
public final float readFloat() {
String chars = readSmallString();
if (chars == null || chars.isEmpty()) return 0.f;
return Float.parseFloat(chars);
}
@Override
public final double readDouble() {
String chars = readSmallString();
if (chars == null || chars.isEmpty()) return 0.0;
return Double.parseDouble(chars);
}
/**
* 读取字符串, 必须是"或者'包围的字符串值
*
* @return String值
*/
@Override
public String readString() {
final char[] text0 = this.text;
int currpos = this.position;
char expected = text0[++currpos];
if (expected <= ' ') {
for (;;) {
expected = text0[++currpos];
if (expected > ' ') break;
}
}
if (expected != '"' && expected != '\'') {
if (expected == 'n' && text0.length > currpos + 3) {
if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') {
this.position = currpos;
if (text0.length > currpos + 4) {
char ch = text0[currpos + 1];
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null;
} else {
return null;
}
}
} else {
final int start = currpos;
for (;;) {
char ch = text0[currpos];
if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break;
currpos++;
}
if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")");
this.position = currpos - 1;
return new String(text0, start, currpos - start);
}
this.position = currpos;
throw new ConvertException("expected a ':' after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")");
}
final int start = ++currpos;
for (;;) {
char ch = text0[currpos];
if (ch == expected) {
break;
} else if (ch == '\\') {
this.position = currpos - 1;
return readEscapeValue(expected, start);
}
currpos++;
}
this.position = currpos;
return new String(text0, start, currpos - start);
}
private String readEscapeValue(final char expected, int start) {
StringBuilder array = new StringBuilder();
final char[] text0 = this.text;
int pos = this.position;
array.append(text0, start, pos + 1 - start);
char c;
for (;;) {
c = text0[++pos];
if (c == expected) {
this.position = pos;
return array.toString();
} else if (c == '\\') {
c = text0[++pos];
switch (c) {
case '"':
case '\'':
case '\\':
case '/':
array.append(c);
break;
case 'n':
array.append('\n');
break;
case 'r':
array.append('\r');
break;
case 'u':
array.append((char) Integer.parseInt(new String(new char[]{text0[++pos], text0[++pos], text0[++pos], text0[++pos]}), 16));
break;
case 't':
array.append('\t');
break;
case 'b':
array.append('\b');
break;
case 'f':
array.append('\f');
break;
default:
this.position = pos;
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ") in (" + new String(this.text) + ")");
}
} else {
array.append(c);
}
}
}
final static int[] digits = new int[255];
static {
for (int i = 0; i < digits.length; i++) {
digits[i] = -1; //-1 错误
}
for (int i = '0'; i <= '9'; i++) {
digits[i] = i - '0';
}
for (int i = 'a'; i <= 'f'; i++) {
digits[i] = i - 'a' + 10;
}
for (int i = 'A'; i <= 'F'; i++) {
digits[i] = i - 'A' + 10;
}
digits['"'] = digits['\''] = -2; //-2 跳过
digits[','] = digits['}'] = digits[']'] = digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = digits[':'] = -3; //-3退出
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.json;
import org.redkale.convert.SimpledCoder;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <T> 序列化/反解析的数据类型
*/
public abstract class JsonSimpledCoder<T> extends SimpledCoder<JsonReader, JsonWriter, T> {
}

View File

@@ -0,0 +1,40 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert.json;
import java.io.*;
import org.redkale.convert.*;
/**
*
* @author zhangjx
*/
class JsonStreamReader extends JsonByteBufferReader {
private InputStream in;
protected JsonStreamReader(InputStream in) {
this.in = in;
}
@Override
protected boolean recycle() {
super.recycle(); // this.position 初始化值为-1
this.in = null;
return false;
}
@Override
protected byte nextByte() {
try {
byte b = (byte) in.read();
this.position++;
return b;
} catch (IOException e) {
throw new ConvertException(e);
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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.json;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
*
* @author zhangjx
*/
class JsonStreamWriter extends JsonByteBufferWriter {
private OutputStream out;
protected JsonStreamWriter(boolean tiny, OutputStream out) {
this(tiny, null, out);
}
protected JsonStreamWriter(boolean tiny, Charset charset, OutputStream out) {
super(tiny, charset, null);
this.out = out;
}
@Override
protected boolean recycle() {
super.recycle();
this.out = null;
return false;
}
@Override
public void writeTo(final char ch) {
if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127");
try {
out.write((byte) ch);
} catch (IOException e) {
throw new ConvertException(e);
}
}
@Override
public void writeTo(final char[] chs, final int start, final int len) {
writeTo(false, chs, start, len);
}
private void writeTo(final boolean quote, final char[] chs, final int start, final int len) {
try {
if (quote) out.write('"');
if (charset == null) { //UTF-8
final int limit = start + len;
for (int i = start; i < limit; i++) {
char c = chs[i];
if (c < 0x80) {
out.write((byte) c);
} else if (c < 0x800) {
out.write((byte) (0xc0 | (c >> 6)));
out.write((byte) (0x80 | (c & 0x3f)));
} else {
out.write((byte) (0xe0 | ((c >> 12))));
out.write((byte) (0x80 | ((c >> 6) & 0x3f)));
out.write((byte) (0x80 | (c & 0x3f)));
}
}
} else {
ByteBuffer bb = charset.encode(CharBuffer.wrap(chs, start, len));
out.write(bb.array());
}
if (quote) out.write('"');
} catch (IOException e) {
throw new ConvertException(e);
}
}
/**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String
*
* @param quote 是否写入双引号
* @param value String值
*/
@Override
public void writeTo(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));
}
@Override
public void writeLong(long value) {
writeTo(false, String.valueOf(value));
}
@Override
public void writeString(String value) {
if (value == null) {
writeNull();
return;
}
final char[] chs = Utility.charArray(value);
int len = 0;
for (char ch : chs) {
switch (ch) {
case '\n': len += 2;
break;
case '\r': len += 2;
break;
case '\t': len += 2;
break;
case '\\': len += 2;
break;
case '"': len += 2;
break;
default: len++;
break;
}
}
if (len == chs.length) {
writeTo(true, chs, 0, len);
return;
}
StringBuilder sb = new StringBuilder(len);
for (char ch : chs) {
switch (ch) {
case '\n': sb.append("\\n");
break;
case '\r': sb.append("\\r");
break;
case '\t': sb.append("\\t");
break;
case '\\': sb.append("\\\\");
break;
case '"': sb.append("\\\"");
break;
default: sb.append(ch);
break;
}
}
char[] cs = Utility.charArray(sb);
writeTo(true, cs, 0, sb.length());
}
}

View File

@@ -0,0 +1,381 @@
/*
* 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.json;
import java.nio.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
*
* writeTo系列的方法输出的字符不能含特殊字符
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class JsonWriter extends Writer {
private static final char[] CHARS_TUREVALUE = "true".toCharArray();
private static final char[] CHARS_FALSEVALUE = "false".toCharArray();
private static final int defaultSize = Integer.getInteger("convert.json.writer.buffer.defsize", 1024);
private int count;
private char[] content;
protected boolean tiny;
public static ObjectPool<JsonWriter> createPool(int max) {
return new ObjectPool<>(max, (Object... params) -> new JsonWriter(), null, (JsonWriter t) -> t.recycle());
}
public JsonWriter() {
this(defaultSize);
}
public JsonWriter(int size) {
this.content = new char[size > 128 ? size : 128];
}
@Override
public boolean tiny() {
return tiny;
}
public JsonWriter tiny(boolean tiny) {
this.tiny = tiny;
return this;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
/**
* 返回指定至少指定长度的缓冲区
*
* @param len
* @return
*/
private char[] expand(int len) {
int newcount = count + len;
if (newcount <= content.length) return content;
char[] newdata = new char[Math.max(content.length * 3 / 2, newcount)];
System.arraycopy(content, 0, newdata, 0, count);
this.content = newdata;
return newdata;
}
public void writeTo(final char ch) { //只能是 0 - 127 的字符
expand(1);
content[count++] = ch;
}
public void writeTo(final char[] chs, final int start, final int len) { //只能是 0 - 127 的字符
expand(len);
System.arraycopy(chs, start, content, count, len);
count += len;
}
/**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String
*
* @param quote 是否加双引号
* @param value 非null且不含需要转义的字符的String值
*/
public void writeTo(final boolean quote, final String value) {
int len = value.length();
expand(len + (quote ? 2 : 0));
if (quote) content[count++] = '"';
value.getChars(0, len, content, count);
count += len;
if (quote) content[count++] = '"';
}
protected boolean recycle() {
this.count = 0;
if (this.content.length > defaultSize) {
this.content = new char[defaultSize];
}
return true;
}
public ByteBuffer[] toBuffers() {
return new ByteBuffer[]{ByteBuffer.wrap(Utility.encodeUTF8(content, 0, count))};
}
public int count() {
return this.count;
}
@Override
public void writeString(String value) {
if (value == null) {
writeNull();
return;
}
expand(value.length() * 2 + 2);
content[count++] = '"';
for (char ch : Utility.charArray(value)) {
switch (ch) {
case '\n': content[count++] = '\\';
content[count++] = 'n';
break;
case '\r': content[count++] = '\\';
content[count++] = 'r';
break;
case '\t': content[count++] = '\\';
content[count++] = 't';
break;
case '\\': content[count++] = '\\';
content[count++] = ch;
break;
case '"': content[count++] = '\\';
content[count++] = ch;
break;
default: content[count++] = ch;
break;
}
}
content[count++] = '"';
}
@Override
public final void writeFieldName(Attribute attribute) {
if (this.comma) writeTo(',');
writeTo(true, attribute.field());
writeTo(':');
}
@Override
public final void writeSmallString(String value) {
writeTo(true, value);
}
@Override
public String toString() {
return new String(content, 0, count);
}
//----------------------------------------------------------------------------------------------
public final void writeTo(final char... chs) { //只能是 0 - 127 的字符
writeTo(chs, 0, chs.length);
}
@Override
public final void writeBoolean(boolean value) {
writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE);
}
@Override
public final void writeByte(byte value) {
writeInt(value);
}
@Override
public final void writeChar(char value) {
writeInt(value);
}
@Override
public final void writeShort(short value) {
writeInt(value);
}
@Override
public void writeInt(int value) {
final char sign = value >= 0 ? 0 : '-';
if (value < 0) value = -value;
int size;
for (int i = 0;; i++) {
if (value <= sizeTable[i]) {
size = i + 1;
break;
}
}
if (sign != 0) size++; //负数
expand(size);
int q, r;
int charPos = count + size;
// Generate two digits per iteration
while (value >= 65536) {
q = value / 100;
// really: r = i - (q * 100);
r = value - ((q << 6) + (q << 5) + (q << 2));
value = q;
content[--charPos] = DigitOnes[r];
content[--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (value * 52429) >>> (16 + 3);
r = value - ((q << 3) + (q << 1)); // r = i-(q*10) ...
content[--charPos] = digits[r];
value = q;
if (value == 0) break;
}
if (sign != 0) content[--charPos] = sign;
count += size;
}
@Override
public void writeLong(long value) {
final char sign = value >= 0 ? 0 : '-';
if (value < 0) value = -value;
int size = 19;
long p = 10;
for (int i = 1; i < 19; i++) {
if (value < p) {
size = i;
break;
}
p = 10 * p;
}
if (sign != 0) size++; //负数
expand(size);
long q;
int r;
int charPos = count + size;
// Get 2 digits/iteration using longs until quotient fits into an int
while (value > Integer.MAX_VALUE) {
q = value / 100;
// really: r = i - (q * 100);
r = (int) (value - ((q << 6) + (q << 5) + (q << 2)));
value = q;
content[--charPos] = DigitOnes[r];
content[--charPos] = DigitTens[r];
}
// Get 2 digits/iteration using ints
int q2;
int i2 = (int) value;
while (i2 >= 65536) {
q2 = i2 / 100;
// really: r = i2 - (q * 100);
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
i2 = q2;
content[--charPos] = DigitOnes[r];
content[--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i2 <= 65536, i2);
for (;;) {
q2 = (i2 * 52429) >>> (16 + 3);
r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
content[--charPos] = digits[r];
i2 = q2;
if (i2 == 0) break;
}
if (sign != 0) content[--charPos] = sign;
count += size;
}
@Override
public final void writeFloat(float value) {
writeTo(false, String.valueOf(value));
}
@Override
public final void writeDouble(double value) {
writeTo(false, String.valueOf(value));
}
@Override
public final void wirteClassName(String clazz) {
}
@Override
public final void writeObjectB(Object obj) {
super.writeObjectB(obj);
writeTo('{');
}
@Override
public final void writeObjectE(Object obj) {
writeTo('}');
}
@Override
public final void writeNull() {
writeTo('n', 'u', 'l', 'l');
}
@Override
public final void writeArrayB(int size) {
writeTo('[');
}
@Override
public final void writeArrayMark() {
writeTo(',');
}
@Override
public final void writeArrayE() {
writeTo(']');
}
@Override
public final void writeMapB(int size) {
writeTo('{');
}
@Override
public final void writeMapMark() {
writeTo(':');
}
@Override
public final void writeMapE() {
writeTo('}');
}
final static char[] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9'
};
final static char[] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
final static char[] digits = {
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
};
final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE};
}

View File

@@ -0,0 +1,4 @@
/**
* 提供JSON的序列化和反解析功能
*/
package org.redkale.convert.json;

View File

@@ -0,0 +1,4 @@
/**
* 提供数据的序列化和反解析功能
*/
package org.redkale.convert;

View File

@@ -0,0 +1,575 @@
/*
* 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.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class AsyncConnection implements AsynchronousByteChannel, AutoCloseable {
protected Map<String, Object> attributes;
public abstract boolean isTCP();
public abstract SocketAddress getRemoteAddress();
public abstract SocketAddress getLocalAddress();
public abstract int getReadTimeoutSecond();
public abstract int getWriteTimeoutSecond();
public abstract void setReadTimeoutSecond(int readTimeoutSecond);
public abstract void setWriteTimeoutSecond(int writeTimeoutSecond);
public final <A> void write(ByteBuffer[] srcs, A attachment, CompletionHandler<Integer, ? super A> handler) {
write(srcs, 0, srcs.length, attachment, handler);
}
protected abstract <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler);
public void dispose() {//同close 只是去掉throws IOException
try {
this.close();
} catch (IOException io) {
}
}
@Override
public void close() throws IOException {
if (attributes == null) return;
try {
for (Object obj : attributes.values()) {
if (obj instanceof AutoCloseable) ((AutoCloseable) obj).close();
}
} catch (Exception io) {
}
}
public void setAttribute(String name, Object value) {
if (attributes == null) attributes = new HashMap<>();
attributes.put(name, value);
}
@SuppressWarnings("unchecked")
public final <T> T getAttribute(String name) {
return (T) (attributes == null ? null : attributes.get(name));
}
public final void removeAttribute(String name) {
if (attributes != null) attributes.remove(name);
}
public final Map<String, Object> getAttributes() {
return attributes;
}
public final void clearAttribute() {
if (attributes != null) attributes.clear();
}
//------------------------------------------------------------------------------------------------------------------------------
public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address) throws IOException {
return create(protocol, group, address, 0, 0);
}
/**
* 创建客户端连接
*
* @param protocol 连接类型 只能是TCP或UDP
* @param address 连接点子
* @param group 连接AsynchronousChannelGroup
* @param readTimeoutSecond0 读取超时秒数
* @param writeTimeoutSecond0 写入超时秒数
* @return 连接
* @throws java.io.IOException 异常
*/
public static AsyncConnection create(final String protocol, final AsynchronousChannelGroup group, final SocketAddress address,
final int readTimeoutSecond0, final int writeTimeoutSecond0) throws IOException {
if ("TCP".equalsIgnoreCase(protocol)) {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group);
try {
channel.connect(address).get(3, TimeUnit.SECONDS);
} catch (Exception e) {
throw new IOException("AsyncConnection connect " + address, e);
}
return create(channel, address, readTimeoutSecond0, writeTimeoutSecond0);
} else if ("UDP".equalsIgnoreCase(protocol)) {
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.connect(address);
return create(channel, address, true, readTimeoutSecond0, writeTimeoutSecond0);
} else {
throw new RuntimeException("AsyncConnection not support protocol " + protocol);
}
}
private static class BIOUDPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond;
private int writeTimeoutSecond;
private final DatagramChannel channel;
private final SocketAddress remoteAddress;
private final boolean client;
public BIOUDPAsyncConnection(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.channel = ch;
this.client = client0;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
this.remoteAddress = addr;
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
public int getReadTimeoutSecond() {
return this.readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return this.writeTimeoutSecond;
}
@Override
public final SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
try {
return channel.getLocalAddress();
} catch (IOException e) {
return null;
}
}
@Override
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = 0;
for (int i = offset; i < offset + length; i++) {
rs += channel.send(srcs[i], remoteAddress);
if (i != offset) Thread.sleep(10);
}
if (handler != null) handler.completed(rs, attachment);
} catch (Exception e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = channel.read(dst);
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> read(ByteBuffer dst) {
try {
int rs = channel.read(dst);
return new SimpleFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = channel.send(src, remoteAddress);
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> write(ByteBuffer src) {
try {
int rs = channel.send(src, remoteAddress);
return new SimpleFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public final void close() throws IOException {
super.close();
if (client) {
channel.close();
}
}
@Override
public final boolean isOpen() {
return channel.isOpen();
}
@Override
public final boolean isTCP() {
return false;
}
}
public static AsyncConnection create(final DatagramChannel ch, SocketAddress addr,
final boolean client0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new BIOUDPAsyncConnection(ch, addr, client0, readTimeoutSecond0, writeTimeoutSecond0);
}
private static class SimpleFuture implements Future<Integer> {
private final int rs;
public SimpleFuture(int rs) {
this.rs = rs;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return true;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public Integer get() throws InterruptedException, ExecutionException {
return rs;
}
@Override
public Integer get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return rs;
}
}
private static class BIOTCPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond;
private int writeTimeoutSecond;
private final Socket socket;
private final ReadableByteChannel readChannel;
private final WritableByteChannel writeChannel;
private final SocketAddress remoteAddress;
public BIOTCPAsyncConnection(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.socket = socket;
ReadableByteChannel rc = null;
WritableByteChannel wc = null;
try {
socket.setSoTimeout(Math.max(readTimeoutSecond0, writeTimeoutSecond0));
rc = Channels.newChannel(socket.getInputStream());
wc = Channels.newChannel(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
this.readChannel = rc;
this.writeChannel = wc;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
SocketAddress addr = addr0;
if (addr == null) {
try {
addr = socket.getRemoteSocketAddress();
} catch (Exception e) {
//do nothing
}
}
this.remoteAddress = addr;
}
@Override
public boolean isTCP() {
return true;
}
@Override
public SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
return socket.getLocalSocketAddress();
}
@Override
public int getReadTimeoutSecond() {
return readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return writeTimeoutSecond;
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
protected <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = 0;
for (int i = offset; i < offset + length; i++) {
rs += writeChannel.write(srcs[i]);
}
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = readChannel.read(dst);
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> read(ByteBuffer dst) {
try {
int rs = readChannel.read(dst);
return new SimpleFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
try {
int rs = writeChannel.write(src);
if (handler != null) handler.completed(rs, attachment);
} catch (IOException e) {
if (handler != null) handler.failed(e, attachment);
}
}
@Override
public Future<Integer> write(ByteBuffer src) {
try {
int rs = writeChannel.write(src);
return new SimpleFuture(rs);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void close() throws IOException {
super.close();
this.socket.close();
}
@Override
public boolean isOpen() {
return !socket.isClosed();
}
}
/**
* 通常用于 ssl socket
*
* @param socket Socket对象
* @return 连接对象
*/
public static AsyncConnection create(final Socket socket) {
return create(socket, null, 0, 0);
}
public static AsyncConnection create(final Socket socket, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new BIOTCPAsyncConnection(socket, addr0, readTimeoutSecond0, writeTimeoutSecond0);
}
private static class AIOTCPAsyncConnection extends AsyncConnection {
private int readTimeoutSecond;
private int writeTimeoutSecond;
private final AsynchronousSocketChannel channel;
private final SocketAddress remoteAddress;
public AIOTCPAsyncConnection(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
this.channel = ch;
this.readTimeoutSecond = readTimeoutSecond0;
this.writeTimeoutSecond = writeTimeoutSecond0;
SocketAddress addr = addr0;
if (addr == null) {
try {
addr = ch.getRemoteAddress();
} catch (Exception e) {
//do nothing
}
}
this.remoteAddress = addr;
}
@Override
public <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {
if (readTimeoutSecond > 0) {
channel.read(dst, readTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
} else {
channel.read(dst, attachment, handler);
}
}
@Override
public <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {
if (writeTimeoutSecond > 0) {
channel.write(src, writeTimeoutSecond, TimeUnit.SECONDS, attachment, handler);
} else {
channel.write(src, attachment, handler);
}
}
@Override
public <A> void write(ByteBuffer[] srcs, int offset, int length, A attachment, final CompletionHandler<Integer, ? super A> handler) {
channel.write(srcs, offset, length, writeTimeoutSecond > 0 ? writeTimeoutSecond : 60, TimeUnit.SECONDS,
attachment, new CompletionHandler<Long, A>() {
@Override
public void completed(Long result, A attachment) {
handler.completed(result.intValue(), attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
handler.failed(exc, attachment);
}
});
}
@Override
public void setReadTimeoutSecond(int readTimeoutSecond) {
this.readTimeoutSecond = readTimeoutSecond;
}
@Override
public void setWriteTimeoutSecond(int writeTimeoutSecond) {
this.writeTimeoutSecond = writeTimeoutSecond;
}
@Override
public int getReadTimeoutSecond() {
return this.readTimeoutSecond;
}
@Override
public int getWriteTimeoutSecond() {
return this.writeTimeoutSecond;
}
@Override
public final SocketAddress getRemoteAddress() {
return remoteAddress;
}
@Override
public SocketAddress getLocalAddress() {
try {
return channel.getLocalAddress();
} catch (IOException e) {
return null;
}
}
@Override
public final Future<Integer> read(ByteBuffer dst) {
return channel.read(dst);
}
@Override
public final Future<Integer> write(ByteBuffer src) {
return channel.write(src);
}
@Override
public final void close() throws IOException {
super.close();
channel.close();
}
@Override
public final boolean isOpen() {
return channel.isOpen();
}
@Override
public final boolean isTCP() {
return true;
}
}
public static AsyncConnection create(final AsynchronousSocketChannel ch) {
return create(ch, null, 0, 0);
}
public static AsyncConnection create(final AsynchronousSocketChannel ch, final SocketAddress addr0, final int readTimeoutSecond0, final int writeTimeoutSecond0) {
return new AIOTCPAsyncConnection(ch, addr0, readTimeoutSecond0, writeTimeoutSecond0);
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.net.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.logging.*;
import org.redkale.convert.bson.*;
import org.redkale.convert.json.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public class Context {
private static final Charset UTF8 = Charset.forName("UTF-8");
protected final long serverStartTime;
protected final ExecutorService executor;
protected final int bufferCapacity;
protected final ObjectPool<ByteBuffer> bufferPool;
protected final ObjectPool<Response> responsePool;
protected final PrepareServlet prepare;
private final InetSocketAddress address;
protected final Charset charset;
protected final int maxbody;
protected final int readTimeoutSecond;
protected final int writeTimeoutSecond;
protected final Logger logger;
protected final BsonFactory bsonFactory;
protected final JsonFactory jsonFactory;
protected final WatchFactory watch;
public Context(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool, ObjectPool<Response> responsePool,
final int maxbody, Charset charset, InetSocketAddress address, final PrepareServlet prepare, final WatchFactory watch,
final int readTimeoutSecond, final int writeTimeoutSecond) {
this.serverStartTime = serverStartTime;
this.logger = logger;
this.executor = executor;
this.bufferCapacity = bufferCapacity;
this.bufferPool = bufferPool;
this.responsePool = responsePool;
this.maxbody = maxbody;
this.charset = UTF8.equals(charset) ? null : charset;
this.address = address;
this.prepare = prepare;
this.watch = watch;
this.readTimeoutSecond = readTimeoutSecond;
this.writeTimeoutSecond = writeTimeoutSecond;
this.jsonFactory = JsonFactory.root();
this.bsonFactory = BsonFactory.root();
}
public int getMaxbody() {
return maxbody;
}
public InetSocketAddress getServerAddress() {
return address;
}
public long getServerStartTime() {
return serverStartTime;
}
public Charset getCharset() {
return charset;
}
public void submit(Runnable r) {
executor.submit(r);
}
public int getBufferCapacity() {
return bufferCapacity;
}
public Supplier<ByteBuffer> getBufferSupplier() {
return bufferPool;
}
public ByteBuffer pollBuffer() {
return bufferPool.get();
}
public void offerBuffer(ByteBuffer buffer) {
bufferPool.offer(buffer);
}
public Logger getLogger() {
return logger;
}
public int getReadTimeoutSecond() {
return readTimeoutSecond;
}
public int getWriteTimeoutSecond() {
return writeTimeoutSecond;
}
public JsonConvert getJsonConvert() {
return jsonFactory.getConvert();
}
public BsonConvert getBsonConvert() {
return bsonFactory.getConvert();
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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.*;
import java.nio.channels.*;
import java.util.logging.*;
import org.redkale.util.*;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public final class PrepareRunner implements Runnable {
private final AsyncConnection channel;
private final Context context;
private ByteBuffer data;
public PrepareRunner(Context context, AsyncConnection channel, ByteBuffer data) {
this.context = context;
this.channel = channel;
this.data = data;
}
@Override
public void run() {
final PrepareServlet prepare = context.prepare;
final ObjectPool<? extends Response> responsePool = context.responsePool;
if (data != null) {
final Response response = responsePool.get();
response.init(channel);
try {
prepare.prepare(data, response.request, response);
} catch (Throwable t) {
context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", t);
response.finish(true);
}
return;
}
final ByteBuffer buffer = context.pollBuffer();
try {
channel.read(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer count, Void attachment1) {
if (count < 1 && buffer.remaining() == buffer.limit()) {
try {
context.offerBuffer(buffer);
channel.close();
} catch (Exception e) {
context.logger.log(Level.FINEST, "PrepareRunner close channel erroneous on no read bytes", e);
}
return;
}
// { //测试
// buffer.flip();
// byte[] bs = new byte[buffer.remaining()];
// buffer.get(bs);
// System.println(new String(bs));
// }
buffer.flip();
final Response response = responsePool.get();
response.init(channel);
try {
prepare.prepare(buffer, response.request, response);
} catch (Throwable t) { //此处不可 context.offerBuffer(buffer); 以免prepare.prepare内部异常导致重复 offerBuffer
context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", t);
response.finish(true);
}
}
@Override
public void failed(Throwable exc, Void attachment2) {
context.offerBuffer(buffer);
try {
channel.close();
} catch (Exception e) {
}
if (exc != null) context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, forece to close channel ", exc);
}
});
} catch (Exception te) {
context.offerBuffer(buffer);
try {
channel.close();
} catch (Exception e) {
}
if (te != null) context.logger.log(Level.FINEST, "Servlet read channel erroneous, forece to close channel ", te);
}
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <C> Context的子类型
* @param <R> Request的子类型
* @param <P> Response的子类型
*/
public abstract class PrepareServlet<K extends Serializable, C extends Context, R extends Request<C>, P extends Response<C, R>, S extends Servlet<C, R, P>> extends Servlet<C, R, P> {
protected final AtomicLong executeCounter = new AtomicLong(); //执行请求次数
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
protected final Set<S> servlets = new HashSet<>();
protected final Map<K, S> mappings = new HashMap<>();
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);
public final void prepare(final ByteBuffer buffer, final R request, final P response) throws IOException {
executeCounter.incrementAndGet();
final int rs = request.readHeader(buffer);
if (rs < 0) {
response.context.offerBuffer(buffer);
if (rs != Integer.MIN_VALUE) illRequestCounter.incrementAndGet();
response.finish(true);
} else if (rs == 0) {
response.context.offerBuffer(buffer);
request.prepare();
this.execute(request, response);
} else {
buffer.clear();
final AtomicInteger ai = new AtomicInteger(rs);
request.channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
buffer.flip();
ai.addAndGet(-request.readBody(buffer));
if (ai.get() > 0) {
buffer.clear();
request.channel.read(buffer, buffer, this);
} else {
response.context.offerBuffer(buffer);
request.prepare();
try {
execute(request, response);
} catch (Exception e) {
illRequestCounter.incrementAndGet();
response.finish(true);
request.context.logger.log(Level.WARNING, "prepare servlet abort, forece to close channel ", e);
}
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
illRequestCounter.incrementAndGet();
response.context.offerBuffer(buffer);
response.finish(true);
if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, forece to close channel ", exc);
}
});
}
}
protected AnyValue getServletConf(Servlet servlet) {
return servlet._conf;
}
protected void setServletConf(Servlet servlet, AnyValue conf) {
servlet._conf = conf;
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public abstract class ProtocolServer {
public abstract void open() throws IOException;
public abstract void bind(SocketAddress local, int backlog) throws IOException;
public abstract <T> Set<SocketOption<?>> supportedOptions();
public abstract <T> void setOption(SocketOption<T> name, T value) throws IOException;
public abstract void accept();
public abstract void close() throws IOException;
public abstract AsynchronousChannelGroup getChannelGroup();
//---------------------------------------------------------------------
public static ProtocolServer create(String protocol, Context context) {
if ("TCP".equalsIgnoreCase(protocol)) return new ProtocolTCPServer(context);
if ("UDP".equalsIgnoreCase(protocol)) return new ProtocolUDPServer(context);
throw new RuntimeException("ProtocolServer not support protocol " + protocol);
}
private static final class ProtocolUDPServer extends ProtocolServer {
private boolean running;
private final Context context;
private DatagramChannel serverChannel;
public ProtocolUDPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
DatagramChannel ch = DatagramChannel.open();
ch.configureBlocking(true);
this.serverChannel = ch;
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final DatagramChannel serchannel = this.serverChannel;
final int readTimeoutSecond = this.context.readTimeoutSecond;
final int writeTimeoutSecond = this.context.writeTimeoutSecond;
final CountDownLatch cdl = new CountDownLatch(1);
this.running = true;
new Thread() {
@Override
public void run() {
cdl.countDown();
while (running) {
final ByteBuffer buffer = context.pollBuffer();
try {
SocketAddress address = serchannel.receive(buffer);
buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.submit(new PrepareRunner(context, conn, buffer));
} catch (Exception e) {
context.offerBuffer(buffer);
}
}
}
}.start();
try {
cdl.await();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void close() throws IOException {
this.running = false;
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return null;
}
}
private static final class ProtocolTCPServer extends ProtocolServer {
private final Context context;
private AsynchronousChannelGroup group;
private AsynchronousServerSocketChannel serverChannel;
public ProtocolTCPServer(Context context) {
this.context = context;
}
@Override
public void open() throws IOException {
group = AsynchronousChannelGroup.withCachedThreadPool(context.executor, 1);
this.serverChannel = AsynchronousServerSocketChannel.open(group);
}
@Override
public void bind(SocketAddress local, int backlog) throws IOException {
this.serverChannel.bind(local, backlog);
}
@Override
public <T> void setOption(SocketOption<T> name, T value) throws IOException {
this.serverChannel.setOption(name, value);
}
@Override
public <T> Set<SocketOption<?>> supportedOptions() {
return this.serverChannel.supportedOptions();
}
@Override
public void accept() {
final AsynchronousServerSocketChannel serchannel = this.serverChannel;
serchannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this);
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
}
@Override
public void failed(Throwable exc, Void attachment) {
serchannel.accept(null, this);
//if (exc != null) context.logger.log(Level.FINEST, AsynchronousServerSocketChannel.class.getSimpleName() + " accept erroneous", exc);
}
});
}
@Override
public void close() throws IOException {
this.serverChannel.close();
}
@Override
public AsynchronousChannelGroup getChannelGroup() {
return this.group;
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.*;
import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class Request<C extends Context> {
protected final C context;
protected final BsonConvert bsonConvert;
protected final JsonConvert jsonConvert;
protected long createtime;
protected boolean keepAlive;
protected AsyncConnection channel;
/**
* properties 与 attributes 的区别在于调用recycle时 attributes会被清空而properties会保留;
* properties 通常存放需要永久绑定在request里的一些对象
*/
private final Map<String, Object> properties = new HashMap<>();
protected final Map<String, Object> attributes = new HashMap<>();
protected Request(C context) {
this.context = context;
this.bsonConvert = context.getBsonConvert();
this.jsonConvert = context.getJsonConvert();
}
/**
* 返回值Integer.MIN_VALUE: 帧数据; -1数据不合法 0解析完毕 &gt;0: 需再读取的字节数。
*
* @param buffer ByteBuffer对象
* @return 缺少的字节数
*/
protected abstract int readHeader(ByteBuffer buffer);
/**
* 读取buffer并返回读取的有效数据长度
*
* @param buffer ByteBuffer对象
* @return 有效数据长度
*/
protected abstract int readBody(ByteBuffer buffer);
protected abstract void prepare();
protected void recycle() {
createtime = 0;
keepAlive = false;
attributes.clear();
channel = null; // close it by response
}
protected <T> T setProperty(String name, T value) {
properties.put(name, value);
return value;
}
@SuppressWarnings("unchecked")
protected <T> T getProperty(String name) {
return (T) properties.get(name);
}
protected <T> T removeProperty(String name) {
return (T)properties.remove(name);
}
protected Map<String, Object> getProperties() {
return properties;
}
public <T> T setAttribute(String name, T value) {
attributes.put(name, value);
return value;
}
@SuppressWarnings("unchecked")
public <T> T getAttribute(String name) {
return (T) attributes.get(name);
}
public <T> T removeAttribute(String name) {
return (T)attributes.remove(name);
}
public Map<String, Object> getAttributes() {
return attributes;
}
public C getContext() {
return this.context;
}
public long getCreatetime() {
return createtime;
}
}

View File

@@ -0,0 +1,230 @@
/*
* 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.*;
import java.nio.channels.*;
import java.util.function.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <R> Request的子类型
*/
@SuppressWarnings("unchecked")
public abstract class Response<C extends Context, R extends Request<C>> {
protected final C context;
protected final R request;
protected AsyncConnection channel;
private boolean inited = true;
protected BiConsumer<R, Response<C, R>> recycleListener;
private final CompletionHandler finishHandler = new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (attachment.hasRemaining()) {
channel.write(attachment, attachment, this);
} else {
context.offerBuffer(attachment);
finish();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
context.offerBuffer(attachment);
finish(true);
}
};
private final CompletionHandler finishHandler2 = new CompletionHandler<Integer, ByteBuffer[]>() {
@Override
public void completed(Integer result, ByteBuffer[] attachments) {
int index = -1;
for (int i = 0; i < attachments.length; i++) {
if (attachments[i].hasRemaining()) {
index = i;
break;
} else {
context.offerBuffer(attachments[i]);
}
}
if (index == 0) {
channel.write(attachments, attachments, this);
} else if (index > 0) {
ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index];
System.arraycopy(attachments, index, newattachs, 0, newattachs.length);
channel.write(newattachs, newattachs, this);
} else {
finish();
}
}
@Override
public void failed(Throwable exc, ByteBuffer[] attachments) {
for (ByteBuffer attachment : attachments) {
context.offerBuffer(attachment);
}
finish(true);
}
};
protected Response(C context, final R request) {
this.context = context;
this.request = request;
}
protected AsyncConnection removeChannel() {
AsyncConnection ch = this.channel;
this.channel = null;
return ch;
}
protected void prepare() {
inited = true;
}
protected boolean recycle() {
if (!inited) return false;
boolean keepAlive = request.keepAlive;
if (recycleListener != null) {
try {
recycleListener.accept(request, this);
} catch (Exception e) {
System.err.println(request);
e.printStackTrace();
}
recycleListener = null;
}
request.recycle();
if (channel != null) {
if (keepAlive) {
this.context.submit(new PrepareRunner(context, channel, null));
} else {
try {
if (channel.isOpen()) channel.close();
} catch (Exception e) {
}
}
channel = null;
}
this.inited = false;
return true;
}
protected void refuseAlive() {
this.request.keepAlive = false;
}
protected void init(AsyncConnection channel) {
this.channel = channel;
this.request.channel = channel;
this.request.createtime = System.currentTimeMillis();
}
public void setRecycleListener(BiConsumer<R, Response<C, R>> recycleListener) {
this.recycleListener = recycleListener;
}
public void finish() {
this.finish(false);
}
public void finish(boolean kill) {
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
if (kill) refuseAlive();
this.context.responsePool.offer(this);
}
public void finish(ByteBuffer buffer) {
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(boolean kill, ByteBuffer buffer) {
if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(ByteBuffer... buffers) {
this.channel.write(buffers, buffers, finishHandler2);
}
public void finish(boolean kill, ByteBuffer... buffers) {
if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2);
}
protected <A> void send(final ByteBuffer buffer, final A attachment, final CompletionHandler<Integer, A> handler) {
this.channel.write(buffer, attachment, new CompletionHandler<Integer, A>() {
@Override
public void completed(Integer result, A attachment) {
if (buffer.hasRemaining()) {
channel.write(buffer, attachment, this);
} else {
context.offerBuffer(buffer);
if (handler != null) handler.completed(result, attachment);
}
}
@Override
public void failed(Throwable exc, A attachment) {
context.offerBuffer(buffer);
if (handler != null) handler.failed(exc, attachment);
}
});
}
protected <A> void send(final ByteBuffer[] buffers, A attachment, final CompletionHandler<Integer, A> handler) {
this.channel.write(buffers, attachment, new CompletionHandler<Integer, A>() {
@Override
public void completed(Integer result, A attachment) {
int index = -1;
for (int i = 0; i < buffers.length; i++) {
if (buffers[i].hasRemaining()) {
index = i;
break;
}
context.offerBuffer(buffers[i]);
}
if (index == 0) {
channel.write(buffers, attachment, this);
} else if (index > 0) {
ByteBuffer[] newattachs = new ByteBuffer[buffers.length - index];
System.arraycopy(buffers, index, newattachs, 0, newattachs.length);
channel.write(newattachs, attachment, this);
} else if (handler != null) handler.completed(result, attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
for (ByteBuffer buffer : buffers) {
context.offerBuffer(buffer);
}
if (handler != null) handler.failed(exc, attachment);
}
});
}
public C getContext() {
return context;
}
}

View File

@@ -0,0 +1,199 @@
/*
* 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.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.nio.charset.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class Server<K extends Serializable, C extends Context, R extends Request<C>, P extends Response<C, R>, S extends Servlet<C, R, P>> {
public static final String RESNAME_SERVER_ROOT = "SERVER_ROOT";
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
//-------------------------------------------------------------
protected final long serverStartTime;
protected final WatchFactory watch;
protected final String protocol;
protected final PrepareServlet<K, C, R, P, S> prepare;
protected C context;
protected AnyValue config;
protected Charset charset;
protected InetSocketAddress address;
protected int backlog;
protected ProtocolServer serverChannel;
protected int bufferCapacity;
protected int threads;
protected ExecutorService executor;
protected int bufferPoolSize;
protected int responsePoolSize;
protected int maxbody;
protected int readTimeoutSecond;
protected int writeTimeoutSecond;
private ScheduledThreadPoolExecutor scheduler;
protected Server(long serverStartTime, String protocol, PrepareServlet<K, C, R, P, S> servlet, final WatchFactory watch) {
this.serverStartTime = serverStartTime;
this.protocol = protocol;
this.prepare = servlet;
this.watch = watch;
}
public void init(final AnyValue config) throws Exception {
Objects.requireNonNull(config);
this.config = config;
this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80));
this.charset = Charset.forName(config.getValue("charset", "UTF-8"));
this.backlog = config.getIntValue("backlog", 8 * 1024);
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
this.maxbody = config.getIntValue("maxbody", 64 * 1024);
this.bufferCapacity = config.getIntValue("bufferCapacity", 8 * 1024);
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
final int port = this.address.getPort();
final AtomicInteger counter = new AtomicInteger();
final Format f = createFormat();
this.executor = Executors.newFixedThreadPool(threads, (Runnable r) -> {
Thread t = new WorkThread(executor, r);
t.setName("Servlet-" + protocol + "-" + port + "-Thread-" + f.format(counter.incrementAndGet()));
return t;
});
}
public void destroy(final AnyValue config) throws Exception {
this.prepare.destroy(context, config);
if (scheduler != null) scheduler.shutdownNow();
}
public InetSocketAddress getSocketAddress() {
return address;
}
public String getProtocol() {
return protocol;
}
public Logger getLogger() {
return this.logger;
}
@SuppressWarnings("unchecked")
public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) {
this.prepare.addServlet(servlet, attachment, conf, mappings);
}
public void start() throws IOException {
this.context = this.createContext();
this.prepare.init(this.context, config);
if (this.watch != null) this.watch.inject(this.prepare);
this.serverChannel = ProtocolServer.create(this.protocol, context);
this.serverChannel.open();
if (this.serverChannel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY)) {
this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
}
serverChannel.bind(address, backlog);
serverChannel.accept();
final String threadName = "[" + Thread.currentThread().getName() + "] ";
logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(protocol) ? "" : ("." + protocol)) + " listen: " + address
+ ", threads: " + threads + ", bufferCapacity: " + bufferCapacity + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
}
protected abstract C createContext();
public void shutdown() throws IOException {
long s = System.currentTimeMillis();
logger.info(this.getClass().getSimpleName() + "-" + this.protocol + " shutdowning");
try {
this.serverChannel.close();
} catch (Exception e) {
}
logger.info(this.getClass().getSimpleName() + "-" + this.protocol + " shutdow prepare servlet");
this.prepare.destroy(this.context, config);
long e = System.currentTimeMillis() - s;
logger.info(this.getClass().getSimpleName() + " shutdown in " + e + " ms");
}
protected Format createFormat() {
String sf = "0";
if (this.threads > 10) sf = "00";
if (this.threads > 100) sf = "000";
if (this.threads > 1000) sf = "0000";
return new DecimalFormat(sf);
}
public static URL[] loadLib(final Logger logger, final String lib) throws Exception {
if (lib == null || lib.isEmpty()) return new URL[0];
final Set<URL> set = new HashSet<>();
for (String s : lib.split(";")) {
if (s.isEmpty()) continue;
if (s.endsWith("*")) {
File root = new File(s.substring(0, s.length() - 1));
if (root.isDirectory()) {
for (File f : root.listFiles()) {
set.add(f.toURI().toURL());
}
}
} else {
File f = new File(s);
if (f.canRead()) set.add(f.toURI().toURL());
}
}
if (set.isEmpty()) return new URL[0];
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader loader = (URLClassLoader) cl;
final Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
for (URL url : set) {
method.invoke(loader, url);
//if (logger != null) logger.log(Level.INFO, "Server found ClassPath({0})", url);
}
} else {
Thread.currentThread().setContextClassLoader(new URLClassLoader(set.toArray(new URL[set.size()]), cl));
}
List<URL> list = new ArrayList<>(set);
Collections.sort(list, (URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile()));
return list.toArray(new URL[list.size()]);
}
}

View File

@@ -0,0 +1,33 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net;
import org.redkale.util.AnyValue;
import java.io.IOException;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
* @param <C> Context的子类型
* @param <R> Request的子类型
* @param <P> Response的子类型
*/
public abstract class Servlet<C extends Context, R extends Request<C>, P extends Response<C, R>> {
AnyValue _conf; //当前Servlet的配置
public void init(C context, AnyValue config) {
}
public abstract void execute(R request, P response) throws IOException;
public void destroy(C context, AnyValue config) {
}
}

View File

@@ -0,0 +1,253 @@
/*
* 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.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.stream.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
* 传输客户端
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public final class Transport {
public static final String DEFAULT_PROTOCOL = "TCP";
protected static final int MAX_POOL_LIMIT = Runtime.getRuntime().availableProcessors() * 16;
protected static final boolean supportTcpNoDelay;
static {
boolean tcpNoDelay = false;
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
tcpNoDelay = channel.supportedOptions().contains(StandardSocketOptions.TCP_NODELAY);
channel.close();
} catch (Exception e) {
}
supportTcpNoDelay = tcpNoDelay;
}
protected final String name; //即<group>的name属性
protected final boolean tcp;
protected final String protocol;
protected final WatchFactory watch;
protected final AsynchronousChannelGroup group;
protected final InetSocketAddress clientAddress;
protected InetSocketAddress[] remoteAddres = new InetSocketAddress[0];
protected final ObjectPool<ByteBuffer> bufferPool;
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
public Transport(String name, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, transportBufferPool, transportChannelGroup, clientAddress, addresses);
}
public Transport(String name, String protocol, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name;
this.watch = watch;
this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol);
this.group = transportChannelGroup;
this.bufferPool = transportBufferPool;
this.clientAddress = clientAddress;
updateRemoteAddresses(addresses);
}
public Transport(final Collection<Transport> transports) {
Transport first = null;
List<String> tmpgroup = new ArrayList<>();
for (Transport t : transports) {
if (first == null) first = t;
tmpgroup.add(t.name);
}
Collections.sort(tmpgroup); //必须按字母排列顺序确保相同内容的transport列表组合的name相同而不会因为list的顺序不同产生不同的name
this.name = tmpgroup.stream().collect(Collectors.joining(";"));
this.watch = first.watch;
this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group;
this.bufferPool = first.bufferPool;
this.clientAddress = first.clientAddress;
Set<InetSocketAddress> addrs = new HashSet<>();
transports.forEach(t -> addrs.addAll(Arrays.asList(t.getRemoteAddresses())));
updateRemoteAddresses(addrs);
}
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
InetSocketAddress[] oldAddresses = this.remoteAddres;
List<InetSocketAddress> list = new ArrayList<>();
if (addresses != null) {
for (InetSocketAddress addr : addresses) {
if (clientAddress != null && clientAddress.equals(addr)) continue;
list.add(addr);
}
}
this.remoteAddres = list.toArray(new InetSocketAddress[list.size()]);
return oldAddresses;
}
public String getName() {
return name;
}
public void close() {
connPool.forEach((k, v) -> v.forEach(c -> c.dispose()));
}
public InetSocketAddress getClientAddress() {
return clientAddress;
}
public InetSocketAddress[] getRemoteAddresses() {
return remoteAddres;
}
@Override
public String toString() {
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteAddres = " + Arrays.toString(remoteAddres) + "}";
}
public ByteBuffer pollBuffer() {
return bufferPool.get();
}
public Supplier<ByteBuffer> getBufferSupplier() {
return bufferPool;
}
public void offerBuffer(ByteBuffer buffer) {
bufferPool.offer(buffer);
}
public void offerBuffer(ByteBuffer... buffers) {
for (ByteBuffer buffer : buffers) offerBuffer(buffer);
}
public boolean isTCP() {
return tcp;
}
public AsyncConnection pollConnection(SocketAddress addr) {
if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0];
final boolean rand = addr == null;
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") has no remoteAddress list");
try {
if (tcp) {
AsynchronousSocketChannel channel = null;
if (rand) { //取地址
for (int i = 0; i < remoteAddres.length; i++) {
addr = remoteAddres[i];
BlockingQueue<AsyncConnection> queue = connPool.get(addr);
if (queue != null && !queue.isEmpty()) {
AsyncConnection conn;
while ((conn = queue.poll()) != null) {
if (conn.isOpen()) return conn;
}
}
if (channel == null) {
channel = AsynchronousSocketChannel.open(group);
if (supportTcpNoDelay) channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
}
try {
channel.connect(addr).get(2, TimeUnit.SECONDS);
break;
} catch (Exception iex) {
iex.printStackTrace();
if (i == remoteAddres.length - 1) channel = null;
}
}
} else {
channel = AsynchronousSocketChannel.open(group);
if (supportTcpNoDelay) channel.setOption(StandardSocketOptions.TCP_NODELAY, true);
channel.connect(addr).get(2, TimeUnit.SECONDS);
}
if (channel == null) return null;
return AsyncConnection.create(channel, addr, 3000, 3000);
} else { // UDP
if (rand) addr = remoteAddres[0];
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(true);
channel.connect(addr);
return AsyncConnection.create(channel, addr, true, 3000, 3000);
// AsyncDatagramChannel channel = AsyncDatagramChannel.open(group);
// channel.connect(addr);
// return AsyncConnection.create(channel, addr, true, 3000, 3000);
}
} catch (Exception ex) {
throw new RuntimeException("transport address = " + addr, ex);
}
}
public void offerConnection(final boolean forceClose, AsyncConnection conn) {
if (!forceClose && conn.isTCP()) {
if (conn.isOpen()) {
BlockingQueue<AsyncConnection> queue = connPool.get(conn.getRemoteAddress());
if (queue == null) {
queue = new ArrayBlockingQueue<>(MAX_POOL_LIMIT);
connPool.put(conn.getRemoteAddress(), queue);
}
if (!queue.offer(conn)) conn.dispose();
}
} else {
conn.dispose();
}
}
public <A> void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler<Integer, A> handler) {
final AsyncConnection conn = pollConnection(addr);
conn.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
buffer.clear();
conn.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (handler != null) handler.completed(result, att);
offerBuffer(buffer);
offerConnection(false, conn);
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
offerBuffer(buffer);
offerConnection(true, conn);
}
});
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
offerBuffer(buffer);
offerConnection(true, conn);
}
});
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.util.concurrent.*;
/**
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
*/
public class WorkThread extends Thread {
private final ExecutorService executor;
public WorkThread(ExecutorService executor, Runnable runner) {
super(runner);
this.executor = executor;
this.setDaemon(true);
}
public void submit(Runnable runner) {
executor.submit(runner);
}
public ExecutorService getExecutor() {
return executor;
}
}

View File

@@ -0,0 +1,325 @@
/*
* 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.http;
import org.redkale.net.Response;
import org.redkale.net.Request;
import org.redkale.util.AnyValue;
import java.io.IOException;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.reflect.Method;
import java.nio.*;
import java.util.*;
import java.util.concurrent.*;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class BasedHttpServlet extends HttpServlet {
/**
* 配合 BasedHttpServlet 使用。
* 当标记为 &#64;AuthIgnore 的方法不会再调用之前调用authenticate 方法。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, TYPE})
@Retention(RUNTIME)
protected @interface AuthIgnore {
}
/**
* 配合 BasedHttpServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其 url
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
protected @interface WebAction {
int actionid() default 0;
String url();
}
/**
* 配合 BasedHttpServlet 使用。
* 当标记为 &#64;HttpCacheable 的方法使用response.finish的参数将被缓存一定时间(默认值timeout=15秒)。
* 通常情况下 &#64;HttpCacheable 需要与 &#64;AuthIgnore 一起使用,因为没有标记&#64;AuthIgnore的方法一般输出的结果与当前用户信息有关。
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
protected @interface HttpCacheable {
/**
* 超时的秒数
*
* @return 超时秒数
*/
int timeout() default 15;
}
private Map.Entry<String, Entry>[] actions;
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
return true;
}
@Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
if (!preExecute(request, response)) return;
for (Map.Entry<String, Entry> en : actions) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
if (entry.cachetimeout > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cachetimeout > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
response.finish(ce.getBuffers());
return;
}
response.setBufferHandler(entry.cacheHandler);
}
entry.servlet.execute(request, response);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
public final void preInit(HttpContext context, AnyValue config) {
String path = _prefix == null ? "" : _prefix;
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load();
this.actions = new Map.Entry[map.size()];
int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) {
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
}
}
public final void postDestroy(HttpContext context, AnyValue config) {
}
public abstract boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException;
private HashMap<String, Entry> load() {
final boolean typeIgnore = this.getClass().getAnnotation(AuthIgnore.class) != null;
WebServlet module = this.getClass().getAnnotation(WebServlet.class);
final int serviceid = module == null ? 0 : module.moduleid();
final HashMap<String, Entry> map = new HashMap<>();
Set<String> nameset = new HashSet<>();
for (final Method method : this.getClass().getMethods()) {
//-----------------------------------------------
String methodname = method.getName();
if ("service".equals(methodname) || "preExecute".equals(methodname) || "execute".equals(methodname) || "authenticate".equals(methodname)) continue;
//-----------------------------------------------
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 2 || paramTypes[0] != HttpRequest.class
|| paramTypes[1] != HttpResponse.class) continue;
//-----------------------------------------------
Class[] exps = method.getExceptionTypes();
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
final int actionid = action.actionid();
final String name = action.url().trim();
if (nameset.contains(name)) throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
for (String n : nameset) {
if (n.contains(name) || name.contains(n)) {
throw new RuntimeException(this.getClass().getSimpleName() + " has two sub-contains " + WebAction.class.getSimpleName() + "(" + name + ", " + n + ")");
}
}
nameset.add(name);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, method, createHttpServlet(method)));
}
return map;
}
private HttpServlet createHttpServlet(final Method method) {
//------------------------------------------------------------------------------
final String supDynName = HttpServlet.class.getName().replace('.', '/');
final String interName = this.getClass().getName().replace('.', '/');
final String interDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(this.getClass());
final String requestSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Request.class);
final String responseSupDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(Response.class);
final String requestDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpRequest.class);
final String responseDesc = jdk.internal.org.objectweb.asm.Type.getDescriptor(HttpResponse.class);
String newDynName = interName + "_Dyn_" + method.getName();
int i = 0;
for (;;) {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i);
} catch (Exception ex) {
break;
}
}
//------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
final String factfield = "_factServlet";
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{
fv = cw.visitField(ACC_PUBLIC, factfield, interDesc, null, null);
fv.visitEnd();
}
{ //构造函数
mv = (cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = (cw.visitMethod(ACC_PUBLIC, "execute", "(" + requestDesc + responseDesc + ")V", null, new String[]{"java/io/IOException"}));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, factfield, interDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, interName, method.getName(), "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "execute", "(" + requestSupDesc + responseSupDesc + ")V", null, new String[]{"java/io/IOException"});
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, HttpRequest.class.getName().replace('.', '/'));
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, HttpResponse.class.getName().replace('.', '/'));
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "execute", "(" + requestDesc + responseDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
cw.visitEnd();
//------------------------------------------------------------------------------
byte[] bytes = cw.toByteArray();
Class<?> newClazz = new ClassLoader(this.getClass().getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
try {
HttpServlet instance = (HttpServlet) newClazz.newInstance();
instance.getClass().getField(factfield).set(instance, this);
return instance;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private static final class Entry {
public Entry(boolean typeIgnore, int moduleid, int actionid, String name, Method method, HttpServlet servlet) {
this.moduleid = moduleid;
this.actionid = actionid;
this.name = name;
this.method = method;
this.servlet = servlet;
this.ignore = typeIgnore || method.getAnnotation(AuthIgnore.class) != null;
HttpCacheable hc = method.getAnnotation(HttpCacheable.class);
this.cachetimeout = hc == null ? 0 : hc.timeout() * 1000;
this.cache = cachetimeout > 0 ? new ConcurrentHashMap() : null;
this.cacheHandler = cachetimeout > 0 ? (HttpResponse response, ByteBuffer[] buffers) -> {
int status = response.getStatus();
if (status != 200) return null;
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), buffers);
cache.put(response.getRequest().getRequestURI(), ce);
return ce.getBuffers();
} : null;
}
public boolean isNeedCheck() {
return this.moduleid != 0 || this.actionid != 0;
}
public final HttpResponse.BufferHandler cacheHandler;
public final ConcurrentHashMap<String, CacheEntry> cache;
public final int cachetimeout;
public final boolean ignore;
public final int moduleid;
public final int actionid;
public final String name;
public final Method method;
public final HttpServlet servlet;
}
private static final class CacheEntry {
public final long time = System.currentTimeMillis();
private final ByteBuffer[] buffers;
private final int status;
private final String contentType;
public CacheEntry(int status, String contentType, ByteBuffer[] bufs) {
this.status = status;
this.contentType = contentType;
final ByteBuffer[] newBuffers = new ByteBuffer[bufs.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = bufs[i].duplicate().asReadOnlyBuffer();
}
this.buffers = newBuffers;
}
public ByteBuffer[] getBuffers() {
final ByteBuffer[] newBuffers = new ByteBuffer[buffers.length];
for (int i = 0; i < newBuffers.length; i++) {
newBuffers[i] = buffers[i].duplicate();
}
return newBuffers;
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.http;
import java.net.*;
import java.nio.*;
import java.nio.charset.*;
import java.security.*;
import java.util.concurrent.*;
import java.util.logging.*;
import org.redkale.net.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class HttpContext extends Context {
protected final SecureRandom random = new SecureRandom();
public HttpContext(long serverStartTime, Logger logger, ExecutorService executor, int bufferCapacity, ObjectPool<ByteBuffer> bufferPool,
ObjectPool<Response> responsePool, int maxbody, Charset charset, InetSocketAddress address, PrepareServlet prepare,
WatchFactory watch, int readTimeoutSecond, int writeTimeoutSecond) {
super(serverStartTime, logger, executor, bufferCapacity, bufferPool, responsePool, maxbody, charset,
address, prepare, watch, readTimeoutSecond, writeTimeoutSecond);
random.setSeed(Math.abs(System.nanoTime()));
}
protected String createSessionid() {
byte[] bytes = new byte[16];
random.nextBytes(bytes);
return new String(Utility.binToHex(bytes));
}
protected WatchFactory getWatchFactory() {
return watch;
}
protected ExecutorService getExecutor() {
return executor;
}
protected ObjectPool<Response> getResponsePool() {
return responsePool;
}
}

View File

@@ -0,0 +1,144 @@
/*
* 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.http;
import org.redkale.util.AnyValue.DefaultAnyValue;
import java.io.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.function.*;
import java.util.logging.*;
import java.util.regex.*;
import org.redkale.net.*;
import org.redkale.util.*;
import org.redkale.watch.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext, HttpRequest, HttpResponse, HttpServlet> {
private SimpleEntry<Predicate<String>, HttpServlet>[] regArray = new SimpleEntry[0];
private HttpServlet resourceHttpServlet = new HttpResourceServlet();
@Override
public void init(HttpContext context, AnyValue config) {
this.servlets.forEach(s -> {
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).preInit(context, getServletConf(s));
} else if (s instanceof BasedHttpServlet) {
((BasedHttpServlet) s).preInit(context, getServletConf(s));
}
s.init(context, getServletConf(s));
});
final WatchFactory watch = context.getWatchFactory();
if (watch != null) {
this.servlets.forEach(s -> {
watch.inject(s);
});
}
if (config != null) {
AnyValue ssConfig = config.getAnyValue("servlets");
AnyValue resConfig = null;
if (ssConfig != null) {
resConfig = ssConfig.getAnyValue("resource-servlet");
if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot") == null) {
((DefaultAnyValue) resConfig).addValue("webroot", config.getValue("root"));
}
}
if (resConfig == null) {
DefaultAnyValue dresConfig = new DefaultAnyValue();
dresConfig.addValue("webroot", config.getValue("root"));
resConfig = dresConfig;
}
this.resourceHttpServlet.init(context, resConfig);
}
}
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
try {
final String uri = request.getRequestURI();
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = this.mappings.isEmpty() ? null : this.mappings.get(uri);
if (servlet == null && this.regArray != null) {
for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) {
if (en.getKey().test(uri)) {
servlet = en.getValue();
break;
}
}
}
if (servlet == null) servlet = this.resourceHttpServlet;
servlet.execute(request, response);
} catch (Exception e) {
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
response.finish(500, null);
}
}
@Override
public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappings) {
if (prefix == null) prefix = "";
for (String mapping : mappings) {
if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
if (contains(mapping, '.', '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //是否是正则表达式))
if (mapping.charAt(0) != '^') mapping = '^' + mapping;
if (mapping.endsWith("/*")) {
mapping = mapping.substring(0, mapping.length() - 1) + ".*";
} else {
mapping = mapping + "$";
}
if (regArray == null) {
regArray = new SimpleEntry[1];
regArray[0] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
} else {
regArray = Arrays.copyOf(regArray, regArray.length + 1);
regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
}
} else if (mapping != null && !mapping.isEmpty()) {
this.mappings.put(mapping, servlet);
}
}
setServletConf(servlet, conf);
servlet._prefix = prefix == null ? "" : prefix.toString();
this.servlets.add(servlet);
}
private static boolean contains(String string, char... values) {
if (string == null) return false;
for (char ch : Utility.charArray(string)) {
for (char ch2 : values) {
if (ch == ch2) return true;
}
}
return false;
}
public void setResourceServlet(HttpServlet servlet) {
if (servlet != null) {
this.resourceHttpServlet = servlet;
}
}
@Override
public void destroy(HttpContext context, AnyValue config) {
this.resourceHttpServlet.destroy(context, config);
this.servlets.forEach(s -> {
s.destroy(context, getServletConf(s));
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).postDestroy(context, getServletConf(s));
} else if (s instanceof BasedHttpServlet) {
((BasedHttpServlet) s).postDestroy(context, getServletConf(s));
}
});
}
}

View File

@@ -0,0 +1,813 @@
/*
* 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.http;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.charset.Charset;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.ByteArray;
/**
* Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。
* 同时提供json的解析接口: public Object getJsonParameter(Class clazz, String name)
* RedKale提倡带简单的参数的GET请求采用类似REST风格, 因此提供了 getRequstURIPath 系列接口。
* 例如简单的翻页查询 /pipes/record/query/page:2/size:20
* 获取页号: int page = request.getRequstURIPath("page:", 1);
* 获取行数: int size = request.getRequstURIPath("size:", 10);
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public class HttpRequest extends Request<HttpContext> {
protected static final Charset UTF8 = Charset.forName("UTF-8");
protected static final String SESSIONID_NAME = "JSESSIONID";
private String method;
private String protocol;
protected String requestURI;
private long contentLength = -1;
private String contentType;
private String host;
private String connection;
protected String cookiestr;
private HttpCookie[] cookies;
protected String newsessionid;
protected final DefaultAnyValue header = new DefaultAnyValue();
protected final DefaultAnyValue params = new DefaultAnyValue();
private final ByteArray array = new ByteArray();
private boolean bodyparsed = false;
protected boolean boundary = false;
private final String remoteAddrHeader;
public HttpRequest(HttpContext context, String remoteAddrHeader) {
super(context);
this.remoteAddrHeader = remoteAddrHeader;
}
protected void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
protected boolean isKeepAlive() {
return this.keepAlive;
}
protected AsyncConnection getChannel() {
return this.channel;
}
protected JsonConvert getJsonConvert() {
return this.jsonConvert;
}
@Override
protected int readHeader(final ByteBuffer buffer) {
if (!readLine(buffer, array)) return -1;
Charset charset = this.context.getCharset();
int index = 0;
int offset = array.find(index, ' ');
if (offset <= 0) return -1;
this.method = array.toString(index, offset, charset).trim();
index = ++offset;
offset = array.find(index, ' ');
if (offset <= 0) return -1;
int off = array.find(index, '#');
if (off > 0) offset = off;
int qst = array.find(index, offset, (byte) '?');
if (qst > 0) {
this.requestURI = array.toDecodeString(index, qst - index, charset).trim();
addParameter(array, qst + 1, offset - qst - 1);
} else {
this.requestURI = array.toDecodeString(index, offset - index, charset).trim();
}
if (this.requestURI.contains("../")) return -1;
index = ++offset;
this.protocol = array.toString(index, array.size() - index, charset).trim();
while (readLine(buffer, array)) {
if (array.size() < 2) break;
index = 0;
offset = array.find(index, ':');
if (offset <= 0) return -1;
String name = array.toString(index, offset, charset).trim();
index = offset + 1;
String value = array.toString(index, array.size() - index, charset).trim();
switch (name) {
case "Content-Type":
this.contentType = value;
break;
case "Content-Length":
this.contentLength = Long.decode(value);
break;
case "Host":
this.host = value;
break;
case "Cookie":
if (this.cookiestr == null || this.cookiestr.isEmpty()) {
this.cookiestr = value;
} else {
this.cookiestr += ";" + value;
}
break;
case "Connection":
this.connection = value;
this.setKeepAlive(!"close".equalsIgnoreCase(value));
break;
default:
header.addValue(name, value);
}
}
array.clear();
if (buffer.hasRemaining()) array.write(buffer, buffer.remaining());
if (this.contentType != null && this.contentType.contains("boundary=")) {
this.boundary = true;
}
if (this.boundary) this.keepAlive = false; //文件上传必须设置keepAlive为false因为文件过大时用户不一定会skip掉多余的数据
if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) {
if (this.contentLength > context.getMaxbody()) return -1;
int lr = (int) this.contentLength - array.size();
return lr > 0 ? lr : 0;
}
return 0;
}
@Override
protected int readBody(ByteBuffer buffer) {
int len = buffer.remaining();
array.write(buffer, len);
return len;
}
@Override
protected void prepare() {
}
private void parseBody() {
if (this.boundary || bodyparsed) return;
addParameter(array, 0, array.size());
bodyparsed = true;
}
private void addParameter(final ByteArray array, final int offset, final int len) {
if (len < 1) return;
Charset charset = this.context.getCharset();
int limit = offset + len;
int keypos = array.find(offset, limit, '=');
int valpos = array.find(offset, limit, '&');
if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) {
if (valpos > 0) addParameter(array, valpos + 1, limit - valpos - 1);
return;
}
String name = array.toDecodeString(offset, keypos - offset, charset);
++keypos;
String value = array.toDecodeString(keypos, (valpos < 0) ? (limit - keypos) : (valpos - keypos), charset);
this.params.addValue(name, value);
if (valpos >= 0) {
addParameter(array, valpos + 1, limit - valpos - 1);
}
}
private boolean readLine(ByteBuffer buffer, ByteArray bytes) {
byte lasted = '\r';
bytes.clear();
for (;;) {
if (!buffer.hasRemaining()) {
if (lasted != '\r') bytes.write(lasted);
return false;
}
byte b = buffer.get();
if (b == -1 || (lasted == '\r' && b == '\n')) break;
if (lasted != '\r') bytes.write(lasted);
lasted = b;
}
return true;
}
@Override
protected <T> T setProperty(String name, T value) {
return super.setProperty(name, value);
}
@Override
@SuppressWarnings("unchecked")
protected <T> T getProperty(String name) {
return super.getProperty(name);
}
@Override
protected <T> T removeProperty(String name) {
return super.removeProperty(name);
}
/**
* 获取客户端地址IP
*
* @return 地址
*/
public SocketAddress getRemoteAddress() {
return this.channel.getRemoteAddress();
}
/**
* 获取客户端地址IP, 与getRemoteAddres() 的区别在于本方法优先取header中指定为RemoteAddress名的值没有则返回getRemoteAddres()的getHostAddress()。
* 本方法适用于服务前端有如nginx的代理服务器进行中转通过getRemoteAddres()是获取不到客户端的真实IP。
*
* @return 地址
*/
public String getRemoteAddr() {
if (remoteAddrHeader != null) {
String val = getHeader(remoteAddrHeader);
if (val != null) return val;
}
SocketAddress addr = getRemoteAddress();
if (addr == null) return "";
if (addr instanceof InetSocketAddress) return ((InetSocketAddress) addr).getAddress().getHostAddress();
return String.valueOf(addr);
}
/**
* 获取请求内容指定的编码字符串
*
* @param charset 编码
* @return 内容
*/
public String getBody(final Charset charset) {
return charset == null ? array.toString() : array.toString(charset);
}
/**
* 获取请求内容的UTF-8编码字符串
*
* @return 内容
*/
public String getBodyUTF8() {
return array.toString(UTF8);
}
@Override
public String toString() {
parseBody();
return this.getClass().getSimpleName() + "{method:" + this.method + ", requestURI:" + this.requestURI
+ ", contentType:" + this.contentType + ", connection:" + this.connection + ", protocol:" + this.protocol
+ ", contentLength:" + this.contentLength + ", cookies:" + this.cookiestr
+ ", host:" + this.host + ", params:" + this.params + ", header:" + this.header + "}";
}
/**
* 获取文件上传对象
*
* @return 文件上传对象
*/
public final MultiContext getMultiContext() {
return new MultiContext(context.getCharset(), this.getContentType(), this.params,
new BufferedInputStream(Channels.newInputStream(this.channel), Math.max(array.size(), 8192)) {
{
array.copyTo(this.buf);
this.count = array.size();
}
}, null);
}
/**
* 获取文件上传信息列表
*
* @return 文件上传对象集合
* @throws IOException IO异常
*/
public final Iterable<MultiPart> multiParts() throws IOException {
return getMultiContext().parts();
}
@Override
protected void recycle() {
this.cookiestr = null;
this.cookies = null;
this.newsessionid = null;
this.method = null;
this.protocol = null;
this.requestURI = null;
this.contentType = null;
this.host = null;
this.connection = null;
this.contentLength = -1;
this.boundary = false;
this.bodyparsed = false;
this.header.clear();
this.params.clear();
this.array.clear();
super.recycle();
}
/**
* 获取sessionid
*
* @param create 无sessionid是否自动创建
* @return sessionid
*/
public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid();
this.newsessionid = sessionid;
}
return sessionid;
}
/**
* 更新sessionid
*
* @return 新的sessionid值
*/
public String changeSessionid() {
this.newsessionid = context.createSessionid();
return newsessionid;
}
/**
* 使sessionid失效
*/
public void invalidateSession() {
this.newsessionid = ""; //为空表示删除sessionid
}
/**
* 获取所有Cookie对象
*
* @return cookie对象数组
*/
public HttpCookie[] getCookies() {
if (this.cookies == null) this.cookies = parseCookies(this.cookiestr);
return this.cookies;
}
/**
* 获取Cookie值
*
* @param name cookie名
* @return cookie值
*/
public String getCookie(String name) {
return getCookie(name, null);
}
/**
* 获取Cookie值 没有返回默认值
*
* @param name cookie名
* @param dfvalue 默认cookie值
* @return cookie值
*/
public String getCookie(String name, String dfvalue) {
for (HttpCookie cookie : getCookies()) {
if (name.equals(cookie.getName())) return cookie.getValue();
}
return dfvalue;
}
private static HttpCookie[] parseCookies(String cookiestr) {
if (cookiestr == null || cookiestr.isEmpty()) return new HttpCookie[0];
String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";");
if (str.isEmpty()) return new HttpCookie[0];
String[] strs = str.split(";");
HttpCookie[] cookies = new HttpCookie[strs.length];
for (int i = 0; i < strs.length; i++) {
String s = strs[i];
int pos = s.indexOf('=');
String v = (pos < 0 ? "" : s.substring(pos + 1));
if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) v = v.substring(1, v.length() - 1);
cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v);
}
return cookies;
}
/**
* 获取协议名 http、https、ws、wss等
*
* @return protocol
*/
public String getProtocol() {
return protocol;
}
/**
* 获取请求方法 GET、POST等
*
* @return method
*/
public String getMethod() {
return method;
}
/**
* 获取Content-Type的header值
*
* @return contentType
*/
public String getContentType() {
return contentType;
}
/**
* 获取请求内容的长度, 为-1表示内容长度不确定
*
* @return 内容长度
*/
public long getContentLength() {
return contentLength;
}
/**
* 获取Connection的Header值
*
* @return Connection
*/
public String getConnection() {
return connection;
}
/**
* 获取Host的Header值
*
* @return Host
*/
public String getHost() {
return host;
}
/**
* 获取请求的URL
*
* @return 请求的URL
*/
public String getRequestURI() {
return requestURI;
}
/**
* 截取getRequestURI最后的一个/后面的部分
*
* @return String
*/
public String getRequstURILastPath() {
if (requestURI == null) return "";
return requestURI.substring(requestURI.lastIndexOf('/') + 1);
}
/**
*
* 从prefix之后截取getRequestURI再对"/"进行分隔
* <p>
* @param prefix 前缀
* @return String[]
*/
public String[] getRequstURIPaths(String prefix) {
if (requestURI == null || prefix == null) return new String[0];
return requestURI.substring(requestURI.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)).split("/");
}
/**
* 获取请求URL分段中含prefix段的值
* 例如请求URL /pipes/record/query/name:hello
* 获取name参数: String name = request.getRequstURIPath("name:", "none");
*
* @param prefix prefix段前缀
* @param defvalue 默认值
* @return prefix截断后的值
*/
public String getRequstURIPath(String prefix, String defvalue) {
if (requestURI == null || prefix == null) return defvalue;
int pos = requestURI.indexOf(prefix);
if (pos < 0) return defvalue;
String sub = requestURI.substring(pos + prefix.length());
pos = sub.indexOf('/');
return pos < 0 ? sub : sub.substring(0, pos);
}
/**
* 获取请求URL分段中含prefix段的short值
* 例如请求URL /pipes/record/query/type:10
* 获取type参数: short type = request.getRequstURIPath("type:", (short)0);
*
* @param prefix prefix段前缀
* @param defvalue 默认short值
* @return short值
*/
public short getRequstURIPath(String prefix, short defvalue) {
String val = getRequstURIPath(prefix, null);
return val == null ? defvalue : Short.parseShort(val);
}
/**
* 获取请求URL分段中含prefix段的int值
* 例如请求URL /pipes/record/query/page:2/size:50
* 获取page参数: int page = request.getRequstURIPath("page:", 1);
* 获取size参数: int size = request.getRequstURIPath("size:", 20);
*
* @param prefix prefix段前缀
* @param defvalue 默认int值
* @return int值
*/
public int getRequstURIPath(String prefix, int defvalue) {
String val = getRequstURIPath(prefix, null);
return val == null ? defvalue : Integer.parseInt(val);
}
/**
* 获取请求URL分段中含prefix段的long值
* 例如请求URL /pipes/record/query/time:1453104341363/id:40
* 获取time参数: long time = request.getRequstURIPath("time:", 0L);
*
* @param prefix prefix段前缀
* @param defvalue 默认long值
* @return long值
*/
public long getRequstURIPath(String prefix, long defvalue) {
String val = getRequstURIPath(prefix, null);
return val == null ? defvalue : Long.parseLong(val);
}
//------------------------------------------------------------------------------
/**
* 获取所有的header名
*
* @return header名数组
*/
public String[] getHeaderNames() {
return header.getNames();
}
/**
* 获取指定的header值
*
* @param name header名
* @return header值
*/
public String getHeader(String name) {
return header.getValue(name);
}
/**
* 获取指定的header值, 没有返回默认值
*
* @param name header名
* @param defaultValue 默认值
* @return header值
*/
public String getHeader(String name, String defaultValue) {
return header.getValue(name, defaultValue);
}
/**
* 获取指定的header的json值
*
* @param <T> 泛型
* @param clazz 反序列化的类名
* @param name header名
* @return header值
*/
public <T> T getJsonHeader(Class<T> clazz, String name) {
String v = getHeader(name);
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(clazz, v);
}
/**
* 获取指定的header的json值
*
* @param <T> 泛型
* @param convert JsonConvert对象
* @param clazz 反序列化的类名
* @param name header名
* @return header值
*/
public <T> T getJsonHeader(JsonConvert convert, Class<T> clazz, String name) {
String v = getHeader(name);
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
}
/**
* 获取指定的header的boolean值, 没有返回默认boolean值
*
* @param name header名
* @param defaultValue 默认boolean值
* @return header值
*/
public boolean getBooleanHeader(String name, boolean defaultValue) {
return header.getBoolValue(name, defaultValue);
}
/**
* 获取指定的header的short值, 没有返回默认short值
*
* @param name header名
* @param defaultValue 默认short值
* @return header值
*/
public short getShortHeader(String name, short defaultValue) {
return header.getShortValue(name, defaultValue);
}
/**
* 获取指定的header的int值, 没有返回默认int值
*
* @param name header名
* @param defaultValue 默认int值
* @return header值
*/
public int getIntHeader(String name, int defaultValue) {
return header.getIntValue(name, defaultValue);
}
/**
* 获取指定的header的long值, 没有返回默认long值
*
* @param name header名
* @param defaultValue 默认long值
* @return header值
*/
public long getLongHeader(String name, long defaultValue) {
return header.getLongValue(name, defaultValue);
}
/**
* 获取指定的header的float值, 没有返回默认float值
*
* @param name header名
* @param defaultValue 默认float值
* @return header值
*/
public float getFloatHeader(String name, float defaultValue) {
return header.getFloatValue(name, defaultValue);
}
/**
* 获取指定的header的double值, 没有返回默认double值
*
* @param name header名
* @param defaultValue 默认double值
* @return header值
*/
public double getDoubleHeader(String name, double defaultValue) {
return header.getDoubleValue(name, defaultValue);
}
//------------------------------------------------------------------------------
/**
* 获取所有参数名
*
* @return 参数名数组
*/
public String[] getParameterNames() {
parseBody();
return params.getNames();
}
/**
* 获取指定的参数值
*
* @param name 参数名
* @return 参数值
*/
public String getParameter(String name) {
parseBody();
return params.getValue(name);
}
/**
* 获取指定的参数值, 没有返回默认值
*
* @param name 参数名
* @param defaultValue 默认值
* @return 参数值
*/
public String getParameter(String name, String defaultValue) {
parseBody();
return params.getValue(name, defaultValue);
}
/**
* 获取指定的参数json值
*
* @param <T> 泛型
* @param clazz 反序列化的类名
* @param name 参数名
* @return 参数值
*/
public <T> T getJsonParameter(Class<T> clazz, String name) {
String v = getParameter(name);
return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(clazz, v);
}
/**
* 获取指定的参数json值
*
* @param <T> 泛型
* @param convert JsonConvert对象
* @param clazz 反序列化的类名
* @param name 参数名
* @return 参数值
*/
public <T> T getJsonParameter(JsonConvert convert, Class<T> clazz, String name) {
String v = getParameter(name);
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
}
/**
* 获取指定的参数boolean值, 没有返回默认boolean值
*
* @param name 参数名
* @param defaultValue 默认boolean值
* @return 参数值
*/
public boolean getBooleanParameter(String name, boolean defaultValue) {
parseBody();
return params.getBoolValue(name, defaultValue);
}
/**
* 获取指定的参数short值, 没有返回默认short值
*
* @param name 参数名
* @param defaultValue 默认short值
* @return 参数值
*/
public short getShortParameter(String name, short defaultValue) {
parseBody();
return params.getShortValue(name, defaultValue);
}
/**
* 获取指定的参数int值, 没有返回默认int值
*
* @param name 参数名
* @param defaultValue 默认int值
* @return 参数值
*/
public int getIntParameter(String name, int defaultValue) {
parseBody();
return params.getIntValue(name, defaultValue);
}
/**
* 获取指定的参数long值, 没有返回默认long值
*
* @param name 参数名
* @param defaultValue 默认long值
* @return 参数值
*/
public long getLongParameter(String name, long defaultValue) {
parseBody();
return params.getLongValue(name, defaultValue);
}
/**
* 获取指定的参数float值, 没有返回默认float值
*
* @param name 参数名
* @param defaultValue 默认float值
* @return 参数值
*/
public float getFloatParameter(String name, float defaultValue) {
parseBody();
return params.getFloatValue(name, defaultValue);
}
/**
* 获取指定的参数double值, 没有返回默认double值
*
* @param name 参数名
* @param defaultValue 默认double值
* @return 参数值
*/
public double getDoubleParameter(String name, double defaultValue) {
parseBody();
return params.getDoubleValue(name, defaultValue);
}
}

View File

@@ -0,0 +1,262 @@
/*
* 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.http;
import java.io.*;
import java.nio.*;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import java.util.logging.*;
import java.util.regex.*;
import org.redkale.util.*;
/**
*
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public final class HttpResourceServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(HttpResourceServlet.class.getSimpleName());
protected class WatchThread extends Thread {
protected final File root;
protected final WatchService watcher;
public WatchThread(File root) throws IOException {
this.root = root;
this.setName("Servlet-ResourceWatch-Thread");
this.setDaemon(true);
this.watcher = this.root.toPath().getFileSystem().newWatchService();
}
@Override
public void run() {
try {
final String rootstr = root.getCanonicalPath();
while (!this.isInterrupted()) {
final WatchKey key = watcher.take();
final Path parent = keymaps.get(key);
if (parent == null) {
key.cancel();
continue;
}
key.pollEvents().stream().forEach((event) -> {
try {
Path path = parent.resolve((Path) event.context());
final String uri = path.toString().substring(rootstr.length()).replace('\\', '/');
//logger.log(Level.FINEST, "file(" + uri + ") happen " + event.kind() + " event");
if (event.kind() == ENTRY_DELETE) {
files.remove(uri);
} else if (event.kind() == ENTRY_MODIFY) {
FileEntry en = files.get(uri);
if (en != null) {
Thread.sleep(5000L); //等待update file完毕
en.update();
}
}
} catch (Exception ex) {
logger.log(Level.FINE, event.context() + " occur erroneous", ex);
}
});
key.reset();
}
} catch (Exception e) {
}
}
}
//缓存总大小, 默认128M
protected long cachelimit = 128 * 1024 * 1024L;
protected final LongAdder cachedLength = new LongAdder();
//最大可缓存的文件大小, 大于该值的文件将不被缓存
protected long cachelengthmax = 1 * 1024 * 1024;
protected File root = new File("./root/");
protected final ConcurrentHashMap<String, FileEntry> files = new ConcurrentHashMap<>();
protected final ConcurrentHashMap<WatchKey, Path> keymaps = new ConcurrentHashMap<>();
protected SimpleEntry<Pattern, String>[] locationRewrites;
protected WatchThread watchThread;
protected Predicate<String> ranges;
@Override
public void init(HttpContext context, AnyValue config) {
if (config != null) {
String rootstr = config.getValue("webroot", "root");
if (rootstr.indexOf(':') < 0 && rootstr.indexOf('/') != 0 && System.getProperty("APP_HOME") != null) {
rootstr = new File(System.getProperty("APP_HOME"), rootstr).getPath();
}
String rangesValue = config.getValue("ranges");
this.ranges = rangesValue != null ? Pattern.compile(rangesValue).asPredicate() : null;
try {
this.root = new File(rootstr).getCanonicalFile();
} catch (IOException ioe) {
this.root = new File(rootstr);
}
AnyValue cacheconf = config.getAnyValue("caches");
if (cacheconf != null) {
this.cachelimit = parseLenth(cacheconf.getValue("limit"), 0 * 1024 * 1024L);
this.cachelengthmax = parseLenth(cacheconf.getValue("lengthmax"), 1 * 1024 * 1024L);
}
List<SimpleEntry<Pattern, String>> locations = new ArrayList<>();
for (AnyValue av : config.getAnyValues("rewrite")) {
if ("location".equals(av.getValue("type"))) {
String m = av.getValue("match");
String f = av.getValue("forward");
if (m != null && f != null) {
locations.add(new SimpleEntry<>(Pattern.compile(m), f));
}
}
}
this.locationRewrites = locations.isEmpty() ? null : locations.toArray(new SimpleEntry[locations.size()]);
}
if (this.cachelimit < 1) return; //不缓存不需要开启WatchThread监听
if (this.root != null) {
try {
this.watchThread = new WatchThread(this.root);
this.watchThread.start();
} catch (IOException ex) {
logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " start watch-thread error", ex);
}
}
}
@Override
public void destroy(HttpContext context, AnyValue config) {
if (this.watchThread != null) {
try {
this.watchThread.watcher.close();
} catch (IOException ex) {
logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " close watch-thread error", ex);
}
if (this.watchThread.isAlive()) this.watchThread.interrupt();
}
}
private static long parseLenth(String value, long defValue) {
if (value == null) return defValue;
value = value.toUpperCase().replace("B", "");
if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024;
if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024;
if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024;
return Long.decode(value);
}
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
String uri = request.getRequestURI();
if (locationRewrites != null) {
for (SimpleEntry<Pattern, String> entry : locationRewrites) {
Matcher matcher = entry.getKey().matcher(uri);
if (matcher.find()) {
StringBuffer sb = new StringBuffer(uri.length());
matcher.appendReplacement(sb, entry.getValue());
matcher.appendTail(sb);
uri = sb.toString();
break;
}
}
}
if (uri.length() == 0 || uri.equals("/")) uri = "/index.html";
//System.out.println(request);
FileEntry entry;
if (watchThread == null) {
entry = createFileEntry(uri);
} else { //有缓存
entry = files.computeIfAbsent(uri, x -> createFileEntry(x));
}
if (entry == null) {
response.finish404();
} else {
response.finishFile(entry.file, entry.content);
}
}
private FileEntry createFileEntry(String uri) {
File file = new File(root, uri);
if (file.isDirectory()) file = new File(file, "index.html");
if (!file.isFile() || !file.canRead()) return null;
FileEntry en = new FileEntry(this, file);
if (watchThread == null) return en;
try {
Path p = file.getParentFile().toPath();
keymaps.put(p.register(watchThread.watcher, ENTRY_MODIFY, ENTRY_DELETE), p);
} catch (IOException e) {
logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " watch FileEntry(" + uri + ") erroneous", e);
}
return en;
}
private static final class FileEntry {
final File file;
private final HttpResourceServlet servlet;
ByteBuffer content;
public FileEntry(final HttpResourceServlet servlet, File file) {
this.servlet = servlet;
this.file = file;
update();
}
public void update() {
if (this.content != null) {
this.servlet.cachedLength.add(0L - this.content.remaining());
this.content = null;
}
long length = this.file.length();
if (length > this.servlet.cachelengthmax) return;
if (this.servlet.cachedLength.longValue() + length > this.servlet.cachelimit) return; //超过缓存总容量
try {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream((int) file.length());
byte[] bytes = new byte[10240];
int pos;
while ((pos = in.read(bytes)) != -1) {
out.write(bytes, 0, pos);
}
in.close();
byte[] bs = out.toByteArray();
ByteBuffer buf = ByteBuffer.allocateDirect(bs.length);
buf.put(bs);
buf.flip();
this.content = buf.asReadOnlyBuffer();
this.servlet.cachedLength.add(this.content.remaining());
} catch (Exception e) {
logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " update FileEntry(" + file + ") erroneous", e);
}
}
@Override
protected void finalize() throws Throwable {
if (this.content != null) this.servlet.cachedLength.add(0L - this.content.remaining());
super.finalize();
}
public long getCachedLength() {
return this.content == null ? 0L : this.content.remaining();
}
}
}

Some files were not shown because too many files have changed in this diff Show More