2.7.0-SNAPSHOT

This commit is contained in:
Redkale
2022-05-27 10:39:58 +08:00
parent 6e21fe56e9
commit 8d1b9a18b4
182 changed files with 8970 additions and 3173 deletions

View File

@@ -1,7 +0,0 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

7
bin/apidoc.cmd Normal file
View File

@@ -0,0 +1,7 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application apidoc

View File

@@ -6,7 +6,7 @@ APP_HOME=`dirname "$0"`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/.. APP_HOME="$APP_HOME"/..
fi fi
lib='.' lib='.'
for jar in `ls $APP_HOME/lib/*.jar` for jar in `ls $APP_HOME/lib/*.jar`
@@ -15,4 +15,4 @@ do
done done
export CLASSPATH=$CLASSPATH:$lib export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME" echo "$APP_HOME"
java -DCMD=APIDOC -DAPP_HOME="$APP_HOME" org.redkale.boot.Application java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application apidoc

View File

@@ -1,7 +0,0 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

7
bin/redkale.cmd Normal file
View File

@@ -0,0 +1,7 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application %*

View File

@@ -20,4 +20,4 @@ done
export CLASSPATH=$CLASSPATH:$lib export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME" echo "$APP_HOME"
java -DCMD=$1 -DAPP_HOME="$APP_HOME" org.redkale.boot.Application java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application $@ &

View File

@@ -4,6 +4,6 @@ SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
call "%APP_HOME%\bin\shutdown.bat" call "%APP_HOME%\bin\shutdown.cmd"
call "%APP_HOME%\bin\start.bat" call "%APP_HOME%\bin\start.cmd"

View File

@@ -2,16 +2,17 @@
<application nodeid="10000" port="2020"> <application nodeid="10000" port="2020">
<resources> <resources>
<properties load="config.properties">
<property name="system.property.redkale.convert.protobuf.enumtostring" value="true"/>
</properties>
</resources> </resources>
<server protocol="HTTP" port="5050"> <server protocol="HTTP" port="5050">
<request> <request>
<remoteaddr value="request.headers.X-RemoteAddress"/> <remoteaddr value="request.headers.X-RemoteAddress"/>
</request> </request>
<response> <response>
<defcookie domain="" path="/"/> <defcookie domain="" path="/"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
@@ -24,8 +25,7 @@
<rest path="/pipes" /> <rest path="/pipes" />
<servlets path="/pipes" autoload="true" /> <servlets path="/pipes" autoload="true" />
</server> </server>
</application> </application>

2
conf/config.properties Normal file
View File

@@ -0,0 +1,2 @@
#

View File

@@ -18,8 +18,8 @@ java.util.logging.FileHandler.level = FINER
java.util.logging.FileHandler.limit = 10M java.util.logging.FileHandler.limit = 10M
java.util.logging.FileHandler.count = 20 java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log
java.util.logging.FileHandler.append = true java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINEST java.util.logging.ConsoleHandler.level = FINEST

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0">
<persistence-unit name="" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
<!--
<persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
-->
</persistence>

13
conf/source.properties Normal file
View File

@@ -0,0 +1,13 @@
############ DataSource @Resource(name="platf") ############
#redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
#redkale.datasource[platf].user = root
#redkale.datasource[platf].password = 12345678
### true: auto ddl;
#redkale.datasource[platf].table-autoddl = true
############ CacheSource @Resource(name="usersession") ############
#redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363
#redkale.cachesource[usersession].node[0].password = 12345678
#redkale.cachesource[usersession].node[0].db = 0

18
my/gitrun.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
export LC_ALL="zh_CN.UTF-8"
rm -fr redkale
rm -fr src
rm -fr bin
rm -fr conf
git clone https://gitee.com/redkale/redkale.git
cp -fr redkale/src ./
cp -fr redkale/bin ./
cp -fr redkale/conf ./
mvn clean
mvn deploy

View File

@@ -7,19 +7,26 @@
<name>RedkaleProject</name> <name>RedkaleProject</name>
<url>http://redkale.org</url> <url>http://redkale.org</url>
<description>redkale -- java framework</description> <description>redkale -- java framework</description>
<version>2.5.0</version> <version>2.7.0-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source> <maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target> <maven.compiler.target>11</maven.compiler.target>
<junit.version>5.7.0</junit.version>
<maven-plugin.version>3.2.0</maven-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>5.7.0</version> <version>${junit.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -74,7 +81,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version> <version>${maven-compiler-plugin.version}</version>
<configuration> <configuration>
<compilerArgument>-parameters</compilerArgument> <compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
@@ -87,7 +94,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version> <version>${maven-plugin.version}</version>
<configuration> <configuration>
<archive> <archive>
<addMavenDescriptor>false</addMavenDescriptor> <addMavenDescriptor>false</addMavenDescriptor>
@@ -101,7 +108,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version> <version>${maven-gpg-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<id>sign-artifacts</id> <id>sign-artifacts</id>
@@ -116,7 +123,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version> <version>${maven-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@@ -129,7 +136,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version> <version>${maven-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@@ -142,7 +149,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>3.2.0</version> <version>${maven-plugin.version}</version>
<configuration> <configuration>
<appendAssemblyId>false</appendAssemblyId> <appendAssemblyId>false</appendAssemblyId>
<descriptors> <descriptors>

View File

@@ -1 +1,9 @@
<EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD>
ʹ<EFBFBD><EFBFBD>gpg<EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatype<EFBFBD><EFBFBD>Կ:
1<EFBFBD><EFBFBD> gpg <20>C-gen-key
2<EFBFBD><EFBFBD> gpg --keyserver keys.openpgp.org --send-keys <20><><EFBFBD>Ĺ<EFBFBD>Կ(һ<><D2BB>ʮ<EFBFBD><CAAE><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD>DE346FA5)
<20><>ʾ<EFBFBD><CABE> gpg: <20>ӹ<EFBFBD>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD>Server indicated a failure <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -20,7 +20,7 @@
</profile> </profile>
<profile> <profile>
<id>release</id> <id>release</id>
<!-- <!--
<build> <build>
<plugins> <plugins>

View File

@@ -7,7 +7,7 @@
<name>RedkaleProject</name> <name>RedkaleProject</name>
<url>https://redkale.org</url> <url>https://redkale.org</url>
<description>redkale -- java framework</description> <description>redkale -- java framework</description>
<version>2.6.0</version> <version>2.7.0-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -125,6 +125,10 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version> <version>${maven-surefire-plugin.version}</version>
<configuration>
<forkMode>once</forkMode>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -0,0 +1,51 @@
redkale.nodeid = 1000
redkale.port = 6560
redkale.lib = ./
#\u3010resources\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
#\u3010executor\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.executor.threads = 4
redkale.resources.executor.hash = false
#\u3010transport\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.transport.bufferCapacity = 32k
redkale.resources.transport.bufferPoolSize = 32
#\u3010excludelibs\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.excludelibs.value = ^.*mysql.*$;^.*kafka.*$
#\u3010cluster\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.cluster.type = org.redkalex.cluster.consul.ConsulClusterAgent
redkale.resources.cluster.waits= = false
redkale.resources.cluster.protocols = SNCP
redkale.resources.cluster.ports = 7070;7071
redkale.resources.mq[0].name =
redkale.resources.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent
redkale.resources.mq[0].servers.value = 127.0.0.1:9101
redkale.resources.group[0].name =
redkale.resources.group[0].protocol = TCP
redkale.resources.group[0].node[0].addr = 127.0.0.1
redkale.resources.group[0].node[0].port = 7070
#\u3010listener\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.listener.value = org.redkalex.xxx.XXXApplicationListener
#\u3010properties\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.resources.properties.load = config.properties
redkale.resources.properties.property[0].name = system.property.yyyy
redkale.resources.properties.property[0].value = YYYYYY
redkale.resources.properties.property[1].name = xxxxxxx
redkale.resources.properties.property[1].value = YYYYYY
redkale.server[0].protocol = HTTP
redkale.server[0].host = 127.0.0.1
redkale.server[0].port = 6060
redkale.server[0].root = root
redkale.server[0].lib =
#\u3010\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011
redkale.server[0].ssl.build = org.redkale.net.SSLBuilder\u5b50\u7c7b
redkale.server[0].services[0].autoload = true

View File

@@ -63,29 +63,29 @@
<!-- <!--
【节点全局唯一】 【节点全局唯一】
第三方服务发现管理接口 第三方服务发现管理接口
value 类名必须是org.redkale.cluster.ClusterAgent的子类 type 类名必须是org.redkale.cluster.ClusterAgent的子类
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false
当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的 当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。 需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true 如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开 protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
ports: 服务发现可以处理的端口, 多个端口用分号;隔开 ports: 服务发现可以处理的端口, 多个端口用分号;隔开
--> ttls: 心跳频率,多少秒一次
<!-- xxxx: 自定义的字段属性例如CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;
<cluster value="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071">
<property name="xxxxxx" value="XXXXXXXX"/>
</cluster>
--> -->
<cluster type="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071" xxx="xxx" />
<!-- <!--
MQ管理接口配置 MQ管理接口配置
不同MQ节点所配置的MQ集群不能重复。 不同MQ节点所配置的MQ集群不能重复。
MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上 MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上
name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线 name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线
value 实现类名必须是org.redkale.mq.MessageAgent的子类 type 实现类名必须是org.redkale.mq.MessageAgent的子类
coder: MessageRecord的解析器类必须是org.redkale.mq.MessageCoder<MessageRecord>的实现类,
可对数据包进行加密解密默认值org.redkale.mq.MessageRecordCoder
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置 MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
--> -->
<!-- <mq name="" type="org.redkalex.mq.kafka.KafkaMessageAgent">
<mq name="" value="org.redkalex.mq.kafka.KafkaMessageAgent">
<servers value="127.0.0.1:9101"/> <servers value="127.0.0.1:9101"/>
<consumer> <consumer>
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
@@ -94,7 +94,7 @@
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
</producer> </producer>
</mq> </mq>
-->
<!-- <!--
一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内 一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
一个group节点对应一个 Transport 对象。 一个group节点对应一个 Transport 对象。
@@ -111,18 +111,7 @@
--> -->
<node addr="127.0.0.1" port="7070"/> <node addr="127.0.0.1" port="7070"/>
</group> </group>
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value 类名必须是CacheSource或DataSource的子类且必须实现Service接口。如果是DataSource.class系统自动映射成DataJdbcSource.class
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
</source>
<!-- <!--
Application启动的监听事件,可配置多个节点 Application启动的监听事件,可配置多个节点
value: 类名必须是ApplicationListener的子类 value: 类名必须是ApplicationListener的子类
@@ -134,6 +123,8 @@
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class 全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。 如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。 如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
先加载子节点property再加载load文件 最后加载agent的实现子类。
agent: 实现类名必须是org.redkale.boot.PropertiesAgent的子类
load: 加载文件,多个用;隔开。 load: 加载文件,多个用;隔开。
默认置入的system.property.的有: 默认置入的system.property.的有:
System.setProperty("redkale.net.transport.poolmaxconns", "100"); System.setProperty("redkale.net.transport.poolmaxconns", "100");
@@ -146,7 +137,7 @@
<properties>节点下也可包含非<property>节点. <properties>节点下也可包含非<property>节点.
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[] 非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
--> -->
<properties load="config.properties"> <properties load="config.properties" agent="">
<property name="system.property.yyyy" value="YYYYYY"/> <property name="system.property.yyyy" value="YYYYYY"/>
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/> <property name="xxxxxx" value="XXXXXXXX"/>
@@ -286,6 +277,7 @@
--> -->
<request> <request>
<remoteaddr value="request.headers.X-RemoteAddress"/> <remoteaddr value="request.headers.X-RemoteAddress"/>
<rpc authenticator="org.redkale.net.http.HttpRpcAuthenticator的实现类"/>
</request> </request>
<!-- <!--

View File

@@ -15,11 +15,16 @@ com.sun.level = INFO
java.util.logging.FileHandler.limit = 20M java.util.logging.FileHandler.limit = 20M
java.util.logging.FileHandler.count = 100 java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8 java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d #java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log
#\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f #\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f
java.util.logging.FileHandler.denyreg = java.util.logging.FileHandler.denyreg =
java.util.logging.FileHandler.append = true java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE #java.util.logging.ConsoleHandler.level = FINE
#\u5c06\u65e5\u5fd7\u5199\u8fdbSearchSource, \u5fc5\u987b\u6307\u5b9asource\u8d44\u6e90\u540d\uff0c\u5728source.properties\u4e2d\u5b9a\u4e49
#java.util.logging.SearchHandler.source = platfsearch
#\u6307\u5b9a\u5199\u8fdbSearchSource\u7684\u8868\u540d\uff0c\u9ed8\u8ba4\u503c\u4e3alog-record
#java.util.logging.SearchHandler.tag = log-${APP_NAME}-%tY%tm%td

View File

@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- 其配置算是标准的JPA配置文件的缩略版 --> <!--
【已废弃】,建议使用 source.properties
其配置算是标准的JPA配置文件的缩略版
-->
<persistence> <persistence>
<!-- 系统基本库 --> <!-- 系统基本库 -->
<persistence-unit name="demouser"> <persistence-unit name="demouser">
@@ -38,7 +41,7 @@
<!-- IM消息库 --> <!-- IM消息库 -->
<persistence-unit name="demoim"> <persistence-unit name="demoim">
<properties> <properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 --> <!-- jdbc:mysql://127.0.0.1:3306/dbim?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/> <property name="javax.persistence.jdbc.password" value="123456"/>

View File

@@ -0,0 +1,50 @@
# CacheSource @Resource(name="usersession")
# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aCacheSource\u5b9e\u73b0\u7c7b
redkale.cachesource[usersession].type = org.redkalex.cache.redis.RedisCacheSource
# \u6700\u5927\u8fde\u63a5\u6570
redkale.cachesource[usersession].maxconns = 16
# \u8282\u70b9\u5730\u5740
redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363
# \u8282\u70b9\u5bc6\u7801
redkale.cachesource[usersession].node[0].password = 12345678
# \u8282\u70b9db
redkale.cachesource[usersession].node[0].db = 0
#\u7b80\u5316\u5199\u6cd5: \u53ef\u4ee5\u4e0d\u7528.node[0], \u5c06\u53c2\u6570\u90fd\u5408\u5e76\u5230url\u4e2d
redkale.cachesource[usersession].url = redis://user:123456@127.0.0.1:6363?db=0
# DataSource @Resource(name="platf")
# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aDataSource\u5b9e\u73b0\u7c7b\uff0c\u9ed8\u8ba4\u503c: org.redkale.source.DataJdbcSource
redkale.datasource[platf].type = org.redkale.source.DataJdbcSource
# \u662f\u5426\u5f00\u542f\u7f13\u5b58(\u6807\u8bb0\u4e3a@Cacheable\u7684Entity\u7c7b)\uff0c\u503c\u76ee\u524d\u53ea\u652f\u6301\u4e24\u79cd\uff1a ALL: \u6240\u6709\u5f00\u542f\u7f13\u5b58\u3002 NONE: \u5173\u95ed\u6240\u6709\u7f13\u5b58\uff0c \u975eNONE\u5b57\u6837\u7edf\u4e00\u89c6\u4e3aALL
redkale.datasource[platf].cachemode = ALL
# \u662f\u5426\u81ea\u52a8\u5efa\u8868\u5f53\u8868\u4e0d\u5b58\u5728\u7684\u65f6\u5019\uff0c \u76ee\u524d\u53ea\u652f\u6301mysql\u3001postgres\uff0c \u9ed8\u8ba4\u4e3afalse
redkale.datasource[platf].table-autoddl = false
# \u7528\u6237
redkale.datasource[platf].user = root
# \u5bc6\u7801
redkale.datasource[platf].password = 12345678
# \u591a\u4e2aURL\u7528;\u9694\u5f00\uff0c\u5982\u5206\u5e03\u5f0fSearchSource\u9700\u8981\u914d\u591a\u4e2aURL
redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
# \u6700\u5927\u8fde\u63a5\u6570\uff0c\u9ed8\u8ba4\u503c\uff1aCPU\u6570
redkale.datasource[platf].maxconns = 16
# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource[platf].contain-sqltemplate = LOCATE(${keystr}, ${column}) > 0
# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource[platf].notcontain-sqltemplate = LOCATE(${keystr}, ${column}) = 0
# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource[platf].tablenotexist-sqlstates = 42000;42S02
# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource[platf].tablecopy-sqltemplate = CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}
# DataSource \u8bfb\u5199\u5206\u79bb
redkale.datasource[platf].read.url = jdbc:mysql://127.0.0.1:3306/platf_r?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
redkale.datasource[platf].read.user = root
redkale.datasource[platf].read.password = 12345678
redkale.datasource[platf].write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
redkale.datasource[platf].write.user = root
redkale.datasource[platf].write.password = 12345678

View File

@@ -17,20 +17,20 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Resource { public @interface Resource {
/** // /**
* AuthenticationType // * AuthenticationType
*/ // */
@Deprecated // @Deprecated
public enum AuthenticationType { // public enum AuthenticationType {
/** // /**
* @deprecated // * @deprecated
*/ // */
CONTAINER, // CONTAINER,
/** // /**
* @deprecated // * @deprecated
*/ // */
APPLICATION // APPLICATION
} // }
/** /**
* 资源名称 * 资源名称
@@ -45,39 +45,39 @@ public @interface Resource {
* @return Class * @return Class
*/ */
public Class<?> type() default Object.class; public Class<?> type() default Object.class;
//
/** // /**
* // *
* @return AuthenticationType // * @return AuthenticationType
*/ // */
@Deprecated // @Deprecated
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; // public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
//
/** // /**
* // *
* @return boolean // * @return boolean
*/ // */
@Deprecated // @Deprecated
public boolean shareable() default true; // public boolean shareable() default true;
//
/** // /**
* // *
* @return String // * @return String
*/ // */
@Deprecated // @Deprecated
public String description() default ""; // public String description() default "";
//
/** // /**
* // *
* @return String // * @return String
*/ // */
@Deprecated // @Deprecated
public String mappedName() default ""; // public String mappedName() default "";
//
/** // /**
* // *
* @return String // * @return String
*/ // */
@Deprecated // @Deprecated
public String lookup() default ""; // public String lookup() default "";
} }

View File

@@ -89,11 +89,11 @@ public @interface Column {
/** /**
* for OpenAPI Specification 3 * for OpenAPI Specification 3
* *
* @return String * @return String
*/ */
String example() default ""; String example() default "";
/** /**
* (Optional) Whether the column is included in SQL INSERT * (Optional) Whether the column is included in SQL INSERT
* statements generated by the persistence provider. * statements generated by the persistence provider.
@@ -122,7 +122,12 @@ public @interface Column {
/** /**
* (Optional) The column length. (Applies only if a * (Optional) The column length. (Applies only if a
* string-valued column is used.) * string-valued column is used.)
* if type==String and length == 65535 then sqltype is text * if type==String and length == 65535 then sqltype is TEXT <br>
* if type==String and length &#60;= 16777215 then sqltype is MEDIUMTEXT <br>
* if type==String and length &#62; 16777215 then sqltype is LONGTEXT <br>
* if type==byte[] and length &#60;= 65535 then sqltype is BLOB <br>
* if type==byte[] and length &#60;= 16777215 then sqltype is MEDIUMBLOB <br>
* if type==byte[] and length &#62; 16777215 then sqltype is LONGBLOB <br>
* *
* @return int * @return int
*/ */

View File

@@ -39,6 +39,6 @@ module redkale {
uses org.redkale.convert.ConvertProvider; uses org.redkale.convert.ConvertProvider;
uses org.redkale.source.CacheSourceProvider; uses org.redkale.source.CacheSourceProvider;
uses org.redkale.source.DataSourceProvider; uses org.redkale.source.DataSourceProvider;
uses org.redkale.util.ResourceInjectLoader; uses org.redkale.util.ResourceAnnotationProvider;
} }

View File

@@ -10,6 +10,7 @@ import java.lang.reflect.*;
import java.math.*; import java.math.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import java.util.logging.*; import java.util.logging.*;
import javax.persistence.*; import javax.persistence.*;
@@ -31,7 +32,7 @@ import org.redkale.util.*;
* *
* @author zhangjx * @author zhangjx
*/ */
public final class ApiDocsService { public final class ApiDocCommand {
private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() { private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() {
}.getType(); }.getType();
@@ -47,13 +48,26 @@ public final class ApiDocsService {
private final Application app; //Application全局对象 private final Application app; //Application全局对象
public ApiDocsService(Application app) { public ApiDocCommand(Application app) {
this.app = app; this.app = app;
} }
public void run(String[] args) throws Exception { public String command(String cmd, String[] params) throws Exception {
//是否跳过RPC接口 //是否跳过RPC接口
final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false"); boolean skipRPC = true;
String apiHost = "http://localhost";
if (params != null && params.length > 0) {
for (String param : params) {
if (param == null) continue;
param = param.toLowerCase();
if (param.startsWith("--api-skiprpc=")) {
skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length()));
} else if (param.startsWith("--api-host=")) {
apiHost = param.substring("--api-host=".length());
}
}
}
List<Map> serverList = new ArrayList<>(); List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix"); Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
@@ -70,7 +84,7 @@ public final class ApiDocsService {
serverList.add(map); serverList.add(map);
HttpServer server = node.getServer(); HttpServer server = node.getServer();
map.put("address", server.getSocketAddress()); map.put("address", server.getSocketAddress());
swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort())); swaggerServers.add(Utility.ofMap("url", apiHost + ":" + server.getSocketAddress().getPort()));
List<Map<String, Object>> servletsList = new ArrayList<>(); List<Map<String, Object>> servletsList = new ArrayList<>();
map.put("servlets", servletsList); map.put("servlets", servletsList);
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType; String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
@@ -200,7 +214,7 @@ public final class ApiDocsService {
f.setAccessible(true); f.setAccessible(true);
paramGenericType = (Type) f.get(servlet); paramGenericType = (Type) f.get(servlet);
} }
simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true); simpleSchemaType(null, node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
if (param.style() == HttpParam.HttpParameterStyle.BODY) { if (param.style() == HttpParam.HttpParameterStyle.BODY) {
swaggerRequestBody.put("description", param.comment()); swaggerRequestBody.put("description", param.comment());
swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap))); swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap)));
@@ -217,9 +231,10 @@ public final class ApiDocsService {
swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form"); swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form");
swaggerParamMap.put("explode", true); swaggerParamMap.put("explode", true);
swaggerParamMap.put("schema", paramSchemaMap); swaggerParamMap.put("schema", paramSchemaMap);
Object example = formatExample(param.example(), param.type(), paramGenericType); Object example = formatExample(null, param.example(), param.type(), paramGenericType);
if (example != null) swaggerParamMap.put("example", example); if (example != null) {
if (!param.example().isEmpty()) { swaggerParamMap.put("example", example);
} else if (!param.example().isEmpty()) {
swaggerParamMap.put("example", param.example()); swaggerParamMap.put("example", param.example());
} }
swaggerParamsList.add(swaggerParamMap); swaggerParamsList.add(swaggerParamMap);
@@ -276,12 +291,13 @@ public final class ApiDocsService {
swaggerOperatMap.put("deprecated", true); swaggerOperatMap.put("deprecated", true);
} }
Map<String, Object> respSchemaMap = new LinkedHashMap<>(); Map<String, Object> respSchemaMap = new LinkedHashMap<>();
simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true); JsonFactory returnFactory = Rest.createJsonFactory(false, method.getAnnotationsByType(RestConvert.class), method.getAnnotationsByType(RestConvertCoder.class));
simpleSchemaType(returnFactory, node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
Map<String, Object> respMap = new LinkedHashMap<>(); Map<String, Object> respMap = new LinkedHashMap<>();
respMap.put("schema", respSchemaMap); respMap.put("schema", respSchemaMap);
Object example = formatExample(action.example(), action.result(), resultType); Object example = formatExample(returnFactory, action.example(), action.result(), resultType);
if (example != null) swaggerOperatMap.put("example", example); if (example != null) respSchemaMap.put("example", example);
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody); if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
swaggerOperatMap.put("parameters", swaggerParamsList); swaggerOperatMap.put("parameters", swaggerParamsList);
String actiondesc = action.comment(); String actiondesc = action.comment();
@@ -335,16 +351,18 @@ public final class ApiDocsService {
if (doctemplate.isFile() && doctemplate.canRead()) { if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate); in = new FileInputStream(doctemplate);
} }
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html"); if (in != null) {
String content = Utility.read(in).replace("'${content}'", json); String content = Utility.read(in).replace("'${content}'", json);
in.close(); in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html")); FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes(StandardCharsets.UTF_8)); outhtml.write(content.getBytes(StandardCharsets.UTF_8));
outhtml.close(); outhtml.close();
}
} }
return "apidoc success";
} }
private static void simpleSchemaType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) { private static void simpleSchemaType(JsonFactory factory, Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) {
if (type == int.class || type == Integer.class || type == AtomicInteger.class) { if (type == int.class || type == Integer.class || type == AtomicInteger.class) {
schemaMap.put("type", "integer"); schemaMap.put("type", "integer");
schemaMap.put("format", "int32"); schemaMap.put("format", "int32");
@@ -368,13 +386,13 @@ public final class ApiDocsService {
schemaMap.put("type", "array"); schemaMap.put("type", "array");
Map<String, Object> sbumap = new LinkedHashMap<>(); Map<String, Object> sbumap = new LinkedHashMap<>();
if (type.isArray()) { if (type.isArray()) {
simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false); simpleSchemaType(factory, logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
} else if (genericType instanceof ParameterizedType) { } else if (genericType instanceof ParameterizedType) {
Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0]; Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (subpt instanceof Class) { if (subpt instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false); simpleSchemaType(factory, logger, componentsMap, (Class) subpt, subpt, sbumap, false);
} else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) { } else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false); simpleSchemaType(factory, logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
} else { } else {
sbumap.put("type", "object"); sbumap.put("type", "object");
} }
@@ -383,7 +401,7 @@ public final class ApiDocsService {
} }
schemaMap.put("items", sbumap); schemaMap.put("items", sbumap);
} else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) { } else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) {
String ct = simpleComponentType(logger, componentsMap, type, genericType); String ct = simpleComponentType(factory, logger, componentsMap, type, genericType);
if (ct == null) { if (ct == null) {
schemaMap.put("type", "object"); schemaMap.put("type", "object");
} else { } else {
@@ -394,10 +412,11 @@ public final class ApiDocsService {
} }
} }
private static String simpleComponentType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) { private static String simpleComponentType(JsonFactory factory, Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
try { try {
Set<Type> types = new HashSet<>();
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType); Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
String ct = componentKey(logger, componentsMap, null, encodeable, true); String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true);
if (ct == null || ct.length() == 0) return null; if (ct == null || ct.length() == 0) return null;
if (componentsMap.containsKey(ct)) return ct; if (componentsMap.containsKey(ct)) return ct;
Map<String, Object> cmap = new LinkedHashMap<>(); Map<String, Object> cmap = new LinkedHashMap<>();
@@ -409,7 +428,7 @@ public final class ApiDocsService {
if (encodeable instanceof ObjectEncoder) { if (encodeable instanceof ObjectEncoder) {
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
Map<String, Object> schemaMap = new LinkedHashMap<>(); Map<String, Object> schemaMap = new LinkedHashMap<>();
simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true); simpleSchemaType(factory, logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
String desc = ""; String desc = "";
if (member.getField() != null) { if (member.getField() != null) {
Column col = member.getField().getAnnotation(Column.class); Column col = member.getField().getAnnotation(Column.class);
@@ -455,35 +474,41 @@ public final class ApiDocsService {
} }
} }
private static String componentKey(Logger logger, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) { private static String componentKey(JsonFactory factory, Logger logger, Set<Type> types, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
if (encodeable instanceof ObjectEncoder) { if (encodeable instanceof ObjectEncoder) {
if (types.contains(encodeable.getType())) return "";
types.add(encodeable.getType());
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName()); sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
if (member.getEncoder() instanceof ArrayEncoder if (member.getEncoder() instanceof ArrayEncoder
|| member.getEncoder() instanceof CollectionEncoder) { || member.getEncoder() instanceof CollectionEncoder) {
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null; if (subsb == null) return null;
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue; if (real == null) continue;
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue; if (cz == ct) continue;
if (field == null && encodeable.getType() instanceof Class) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb); sb.append(subsb);
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) { } else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue; if (real == null) continue;
if (types.contains(member.getEncoder().getType())) continue;
types.add(member.getEncoder().getType());
if (member.getEncoder() instanceof SimpledCoder) { if (member.getEncoder() instanceof SimpledCoder) {
simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); simpleSchemaType(factory, logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
} else { } else {
simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); simpleSchemaType(factory, logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
} }
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue; if (cz == ct) continue;
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null; if (subsb == null) return null;
if (field == null && member.getEncoder().getType() instanceof Class) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb); sb.append(subsb);
} else if (member.getEncoder() instanceof MapEncoder) { } else if (member.getEncoder() instanceof MapEncoder) {
@@ -497,7 +522,7 @@ public final class ApiDocsService {
final boolean array = (encodeable instanceof ArrayEncoder); final boolean array = (encodeable instanceof ArrayEncoder);
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder(); Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
if (subEncodeable instanceof SimpledCoder && field != null) return ""; if (subEncodeable instanceof SimpledCoder && field != null) return "";
final String sb = componentKey(logger, componentsMap, null, subEncodeable, false); final String sb = componentKey(factory, logger, types, componentsMap, null, subEncodeable, false);
if (sb == null || sb.isEmpty()) return sb; if (sb == null || sb.isEmpty()) return sb;
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) { if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
return sb; return sb;
@@ -516,8 +541,9 @@ public final class ApiDocsService {
} }
} }
private static Object formatExample(String example, Class type, Type genericType) { private static Object formatExample(JsonFactory factory, String example, Class type, Type genericType) {
if (example == null || example.isEmpty()) return null; if (example != null && !example.isEmpty()) return example;
JsonFactory jsonFactory = factory == null || factory == JsonFactory.root() ? exampleFactory : factory;
if (type == Flipper.class) { if (type == Flipper.class) {
return new Flipper(); return new Flipper();
} else if (TYPE_RETRESULT_OBJECT.equals(genericType)) { } else if (TYPE_RETRESULT_OBJECT.equals(genericType)) {
@@ -528,8 +554,103 @@ public final class ApiDocsService {
return RetResult.success(0); return RetResult.success(0);
} else if (TYPE_RETRESULT_LONG.equals(genericType)) { } else if (TYPE_RETRESULT_LONG.equals(genericType)) {
return RetResult.success(0L); return RetResult.success(0L);
} else if (type == boolean.class || type == Boolean.class) {
return true;
} else if (type.isPrimitive()) {
return 0;
} else if (type == boolean[].class || type == Boolean[].class) {
return new boolean[]{true, false};
} else if (type == byte[].class || type == Byte[].class) {
return new byte[]{0, 0};
} else if (type == char[].class || type == Character[].class) {
return new char[]{'a', 'b'};
} else if (type == short[].class || type == Short[].class) {
return new short[]{0, 0};
} else if (type == int[].class || type == Integer[].class) {
return new int[]{0, 0};
} else if (type == long[].class || type == Long[].class) {
return new long[]{0, 0};
} else if (type == float[].class || type == Float[].class) {
return new float[]{0, 0};
} else if (type == double[].class || type == Double[].class) {
return new double[]{0, 0};
} else if (Number.class.isAssignableFrom(type)) {
return 0;
} else if (CharSequence.class.isAssignableFrom(type)) {
return "";
} else if (CompletableFuture.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
return formatExample(factory, example, valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : ((Class) valType), valType);
} catch (Throwable t) {
}
}
} else if (Sheet.class.isAssignableFrom(type)) { //要在Collection前面
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'rows':[" + val + "," + val + "]}")));
} catch (Throwable t) {
}
}
} else if (type.isArray()) {
try {
Object val = formatExample(factory, example, type.getComponentType(), type.getComponentType());
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]")));
} catch (Throwable t) {
}
} else if (Collection.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]")));
} catch (Throwable t) {
}
}
} else if (type == RetResult.class) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'result':" + val + "}")));
} catch (Throwable t) {
}
}
} else if (type != void.class) {
try {
Decodeable decoder = jsonFactory.loadDecoder(genericType);
if (decoder instanceof ObjectDecoder) {
StringBuilder json = new StringBuilder();
json.append("{");
int index = 0;
for (DeMember member : ((ObjectDecoder) decoder).getMembers()) {
if (!(member.getDecoder() instanceof ObjectDecoder)) continue;
if (index > 0) json.append(",");
json.append('"').append(member.getAttribute().field()).append("\":{}");
index++;
}
json.append("}");
Object val = jsonFactory.getConvert().convertFrom(genericType, json.toString());
return new StringWrapper(jsonFactory.getConvert().convertTo(val));
}
Creator creator = Creator.create(type);
return new StringWrapper(jsonFactory.getConvert().convertTo(creator.create()));
} catch (Throwable t) {
}
} }
return example; return example;
} }
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ import java.util.function.Predicate;
import java.util.jar.*; import java.util.jar.*;
import java.util.logging.*; import java.util.logging.*;
import java.util.regex.*; import java.util.regex.*;
import javax.annotation.Priority;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -103,11 +104,12 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt; * @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/ */
public final Set<FilterEntry<T>> getFilterEntrys() { public final Set<FilterEntry<T>> getFilterEntrys() {
HashSet<FilterEntry<T>> set = new HashSet<>(); List<FilterEntry<T>> list = new ArrayList<>();
set.addAll(entrys); list.addAll(entrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys())); if (ors != null) ors.forEach(f -> list.addAll(f.getFilterEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys())); if (ands != null) ands.forEach(f -> list.addAll(f.getFilterEntrys()));
return set; Collections.sort(list);
return new LinkedHashSet<>(list);
} }
/** /**
@@ -116,11 +118,12 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt; * @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/ */
public final Set<FilterEntry<T>> getFilterExpectEntrys() { public final Set<FilterEntry<T>> getFilterExpectEntrys() {
HashSet<FilterEntry<T>> set = new HashSet<>(); List<FilterEntry<T>> list = new ArrayList<>();
set.addAll(expectEntrys); list.addAll(expectEntrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys())); if (ors != null) ors.forEach(f -> list.addAll(f.getFilterExpectEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys())); if (ands != null) ands.forEach(f -> list.addAll(f.getFilterExpectEntrys()));
return set; Collections.sort(list);
return new LinkedHashSet<>(list);
} }
/** /**
@@ -129,7 +132,7 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt; * @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/ */
public final Set<FilterEntry<T>> getAllFilterEntrys() { public final Set<FilterEntry<T>> getAllFilterEntrys() {
HashSet<FilterEntry<T>> rs = new HashSet<>(); HashSet<FilterEntry<T>> rs = new LinkedHashSet<>();
rs.addAll(getFilterEntrys()); rs.addAll(getFilterEntrys());
rs.addAll(getFilterExpectEntrys()); rs.addAll(getFilterExpectEntrys());
return rs; return rs;
@@ -384,7 +387,7 @@ public final class ClassFilter<T> {
* *
* @param <T> 泛型 * @param <T> 泛型
*/ */
public static final class FilterEntry<T> { public static final class FilterEntry<T> implements Comparable<FilterEntry<T>> {
private final HashSet<String> groups = new LinkedHashSet<>(); private final HashSet<String> groups = new LinkedHashSet<>();
@@ -416,6 +419,14 @@ public final class ClassFilter<T> {
this.name = property == null ? "" : property.getValue("name", ""); this.name = property == null ? "" : property.getValue("name", "");
} }
@Override //@Priority值越大优先级越高, 需要排前面
public int compareTo(FilterEntry o) {
if (!(o instanceof FilterEntry)) return 1;
Priority p1 = this.type.getAnnotation(Priority.class);
Priority p2 = ((FilterEntry<T>) o).type.getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
}
@Override @Override
public String toString() { public String toString() {
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName() return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
@@ -465,6 +476,7 @@ public final class ClassFilter<T> {
public boolean isExpect() { public boolean isExpect() {
return expect; return expect;
} }
} }
/** /**

View File

@@ -0,0 +1,20 @@
/*
*/
package org.redkale.boot;
import java.util.logging.Handler;
/**
* Handler基类
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
public abstract class LoggingBaseHandler extends Handler {
protected Application currentApplication() {
return Application.currentApplication; //不能直接暴露外界访问
}
}

View File

@@ -10,13 +10,13 @@ import org.redkale.util.RedkaleClassLoader;
import java.io.*; import java.io.*;
import java.nio.file.*; import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*; import static java.nio.file.StandardCopyOption.*;
import java.time.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import java.util.logging.*; import java.util.logging.*;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.redkale.util.*;
/** /**
* 自定义的日志输出类 * 自定义的日志输出类
@@ -26,11 +26,13 @@ import java.util.regex.Pattern;
* @author zhangjx * @author zhangjx
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class LoggingFileHandler extends Handler { public class LoggingFileHandler extends LoggingBaseHandler {
//public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n"; //public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
public static final String FORMATTER_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"; public static final String FORMATTER_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";
static boolean traceflag = false; //防止设置system.property前调用Traces类导致enable提前初始化
/** /**
* SNCP的日志输出Handler * SNCP的日志输出Handler
*/ */
@@ -42,6 +44,46 @@ public class LoggingFileHandler extends Handler {
} }
} }
public static class LoggingConsoleHandler extends ConsoleHandler {
private Pattern denyreg;
public LoggingConsoleHandler() {
super();
configure();
}
private void configure() {
LogManager manager = LogManager.getLogManager();
String denyregstr = manager.getProperty("java.util.logging.ConsoleHandler.denyreg");
try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
denyreg = Pattern.compile(denyregstr);
}
} catch (Exception e) {
}
}
@Override
public void publish(LogRecord log) {
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
if (traceflag && Traces.enable()) {
String traceid = Traces.currTraceid();
if (traceid == null || traceid.isEmpty()) {
traceid = "[TID:N/A] ";
} else {
traceid = "[TID:" + traceid + "] ";
}
if (log.getMessage() == null) {
log.setMessage(traceid);
} else {
log.setMessage(traceid + log.getMessage());
}
}
super.publish(log);
}
}
/** /**
* 默认的日志时间格式化类 * 默认的日志时间格式化类
* 与SimpleFormatter的区别在于level不使用本地化 * 与SimpleFormatter的区别在于level不使用本地化
@@ -51,6 +93,9 @@ public class LoggingFileHandler extends Handler {
@Override @Override
public String format(LogRecord log) { public String format(LogRecord log) {
if (log.getThrown() == null && log.getMessage() != null && log.getMessage().startsWith("------")) {
return formatMessage(log) + "\r\n";
}
String source; String source;
if (log.getSourceClassName() != null) { if (log.getSourceClassName() != null) {
source = log.getSourceClassName(); source = log.getSourceClassName();
@@ -104,9 +149,13 @@ public class LoggingFileHandler extends Handler {
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue(); protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
private String pattern; protected String pattern;
private String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中 protected String patternDateFormat; //需要时间格式化
protected String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
protected String unusualDateFormat; //需要时间格式化
private int limit; //文件大小限制 private int limit; //文件大小限制
@@ -118,9 +167,9 @@ public class LoggingFileHandler extends Handler {
private long tomorrow; private long tomorrow;
private boolean append; protected boolean append;
private Pattern denyreg; protected Pattern denyreg;
private final AtomicLong loglength = new AtomicLong(); private final AtomicLong loglength = new AtomicLong();
@@ -198,16 +247,14 @@ public class LoggingFileHandler extends Handler {
} }
if (logstream == null) { if (logstream == null) {
logindex.incrementAndGet(); logindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now(); logfile = new File(patternDateFormat == null ? pattern : Utility.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
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(); logfile.getParentFile().mkdirs();
loglength.set(logfile.length()); loglength.set(logfile.length());
logstream = new FileOutputStream(logfile, append); logstream = new FileOutputStream(logfile, append);
} }
if (unusual != null && logunusualstream == null) { if (unusual != null && logunusualstream == null) {
logunusualindex.incrementAndGet(); logunusualindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now(); logunusualfile = new File(unusualDateFormat == null ? unusual : Utility.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logunusualfile.getParentFile().mkdirs(); logunusualfile.getParentFile().mkdirs();
logunusuallength.set(logunusualfile.length()); logunusuallength.set(logunusualfile.length());
logunusualstream = new FileOutputStream(logunusualfile, append); logunusualstream = new FileOutputStream(logunusualfile, append);
@@ -241,7 +288,7 @@ public class LoggingFileHandler extends Handler {
String cname = LoggingFileHandler.class.getName(); String cname = LoggingFileHandler.class.getName();
this.pattern = manager.getProperty(cname + ".pattern"); this.pattern = manager.getProperty(cname + ".pattern");
if (this.pattern == null) { if (this.pattern == null) {
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log"; this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log";
} else { } else {
int pos = this.pattern.lastIndexOf('/'); int pos = this.pattern.lastIndexOf('/');
if (pos > 0) { if (pos > 0) {
@@ -250,6 +297,10 @@ public class LoggingFileHandler extends Handler {
this.pattern = getPrefix() + this.pattern; this.pattern = getPrefix() + this.pattern;
} }
} }
if (this.pattern != null && this.pattern.contains("%")) { //需要时间格式化
this.patternDateFormat = this.pattern;
Utility.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
String unusualstr = manager.getProperty(cname + ".unusual"); String unusualstr = manager.getProperty(cname + ".unusual");
if (unusualstr != null) { if (unusualstr != null) {
int pos = unusualstr.lastIndexOf('/'); int pos = unusualstr.lastIndexOf('/');
@@ -259,6 +310,10 @@ public class LoggingFileHandler extends Handler {
this.unusual = getPrefix() + unusualstr; this.unusual = getPrefix() + unusualstr;
} }
} }
if (this.unusual != null && this.unusual.contains("%")) { //需要时间格式化
this.unusualDateFormat = this.unusual;
Utility.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
String limitstr = manager.getProperty(cname + ".limit"); String limitstr = manager.getProperty(cname + ".limit");
try { try {
if (limitstr != null) { if (limitstr != null) {
@@ -333,6 +388,7 @@ public class LoggingFileHandler extends Handler {
@Override @Override
public void publish(LogRecord log) { public void publish(LogRecord log) {
if (!isLoggable(log)) return;
final String sourceClassName = log.getSourceClassName(); final String sourceClassName = log.getSourceClassName();
if (sourceClassName == null || true) { if (sourceClassName == null || true) {
StackTraceElement[] ses = new Throwable().getStackTrace(); StackTraceElement[] ses = new Throwable().getStackTrace();
@@ -346,6 +402,19 @@ public class LoggingFileHandler extends Handler {
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName); log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
} }
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
if (traceflag && Traces.enable()) {
String traceid = Traces.currTraceid();
if (traceid == null || traceid.isEmpty()) {
traceid = "[TID:N/A] ";
} else {
traceid = "[TID:" + traceid + "] ";
}
if (log.getMessage() == null) {
log.setMessage(traceid);
} else {
log.setMessage(traceid + log.getMessage());
}
}
logqueue.offer(log); logqueue.offer(log);
} }

View File

@@ -0,0 +1,303 @@
/*
*/
package org.redkale.boot;
import java.io.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.regex.Pattern;
import javax.persistence.*;
import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* 基于SearchSource的日志输出类
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
public class LoggingSearchHandler extends LoggingBaseHandler {
protected static final String DEFAULT_TABLE_NAME = "log-record";
protected final LinkedBlockingQueue<SearchLogRecord> logqueue = new LinkedBlockingQueue();
protected final AtomicInteger retryCount = new AtomicInteger(3);
protected String tag = DEFAULT_TABLE_NAME; //用于表前缀, 默认是
protected String tagDateFormat; //需要时间格式化
protected String pattern;
protected Pattern denyreg;
protected String sourceResourceName;
protected SearchSource source;
public LoggingSearchHandler() {
configure();
open();
}
private void open() {
final String name = "Redkale-" + getClass().getSimpleName() + "-Thread";
final int batchSize = 100; //批量最多100条
final List<SearchLogRecord> logList = new ArrayList<>();
final SimpleFormatter formatter = new SimpleFormatter();
final PrintStream outStream = System.out;
new Thread() {
{
setName(name);
setDaemon(true);
}
@Override
public void run() {
while (true) {
try {
SearchLogRecord log = logqueue.take();
while (source == null && retryCount.get() > 0) initSource();
//----------------------写日志-------------------------
if (source == null) { //source加载失败
outStream.print(formatter.format(log.rawLog));
} else {
logList.add(log);
int size = batchSize;
while (--size > 0) {
log = logqueue.poll();
if (log == null) break;
logList.add(log);
}
source.insert(logList);
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
} finally {
logList.clear();
}
}
}
}.start();
}
private synchronized void initSource() {
if (retryCount.get() < 1) return;
try {
Utility.sleep(3000); //如果SearchSource自身在打印日志需要停顿一点时间让SearchSource初始化完成
Application application = currentApplication();
this.source = (SearchSource) application.loadDataSource(sourceResourceName, false);
if (retryCount.get() == 1 && this.source == null) System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
} catch (Exception t) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, t, ErrorManager.WRITE_FAILURE);
} finally {
retryCount.decrementAndGet();
}
}
private static boolean checkTagName(String name) { //只能是字母、数字、短横、点、%、$和下划线
if (name.isEmpty()) return false;
for (char ch : name.toCharArray()) {
if (ch >= '0' && ch <= '9') continue;
if (ch >= 'a' && ch <= 'z') continue;
if (ch >= 'A' && ch <= 'Z') continue;
if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') continue;
return false;
}
return true;
}
private void configure() {
LogManager manager = LogManager.getLogManager();
String cname = getClass().getName();
this.sourceResourceName = manager.getProperty(cname + ".source");
if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) {
throw new RuntimeException("not found logging.property " + cname + ".source");
}
String tagstr = manager.getProperty(cname + ".tag");
if (tagstr != null && !tagstr.isEmpty()) {
if (!checkTagName(tagstr.replaceAll("\\$\\{.+\\}", ""))) throw new RuntimeException("found illegal logging.property " + cname + ".tag = " + tagstr);
this.tag = tagstr;
if (tagstr.contains("%")) {
this.tagDateFormat = this.tag;
Utility.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
}
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);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
String formatterstr = manager.getProperty(cname + ".formatter");
try {
if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFormatter((Formatter) clz.getDeclaredConstructor().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) {
}
String denyregstr = manager.getProperty(cname + ".denyreg");
try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
denyreg = Pattern.compile(denyregstr);
}
} catch (Exception e) {
}
}
@Override
public void publish(LogRecord log) {
if (!isLoggable(log)) return;
final String sourceClassName = log.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;
log.setSourceClassName(ses[i].getClassName());
log.setSourceMethodName(ses[i].getMethodName());
break;
}
}
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
String rawTag = tagDateFormat == null ? tag : Utility.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli());
logqueue.offer(new SearchLogRecord(rawTag, log));
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
@Entity
@Table(name = DEFAULT_TABLE_NAME)
@DistributeTable(strategy = SearchLogRecord.TableStrategy.class)
public static class SearchLogRecord {
@Id
@ConvertColumn(index = 1)
@SearchColumn(options = "false")
public String logid;
@ConvertColumn(index = 2)
@SearchColumn(options = "false")
public String level;
@ConvertColumn(index = 3)
@SearchColumn(date = true)
public long timestamp;
@ConvertColumn(index = 4)
@SearchColumn(options = "false")
public String traceid;
@ConvertColumn(index = 5)
public String threadName;
@ConvertColumn(index = 6)
@SearchColumn(text = true, options = "offsets")
public String loggerName;
@ConvertColumn(index = 7)
@SearchColumn(text = true, options = "offsets")
public String methodName;
@ConvertColumn(index = 8)
@SearchColumn(text = true, options = "offsets") //, analyzer = "ik_max_word"
public String message; //log.message +"\r\n"+ log.thrown
@Transient
@ConvertDisabled
LogRecord rawLog;
@Transient
@ConvertDisabled
String rawTag;
public SearchLogRecord() {
}
protected SearchLogRecord(String tag, LogRecord log) {
this.rawLog = log;
this.rawTag = tag;
this.threadName = Thread.currentThread().getName();
this.traceid = LoggingFileHandler.traceflag ? Traces.currTraceid() : null;
String msg = log.getMessage();
if (log.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println();
log.getThrown().printStackTrace(pw);
pw.close();
String throwable = sw.toString();
this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable;
} else {
this.message = msg;
}
this.level = log.getLevel().toString();
this.loggerName = log.getLoggerName();
this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName();
this.timestamp = log.getInstant().toEpochMilli();
this.logid = Utility.format36time(timestamp) + "_" + Utility.uuid();
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> {
@Override
public String getTable(String table, SearchLogRecord bean) {
return bean.rawTag;
}
@Override
public String getTable(String table, Serializable primary) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getTable(String table, FilterNode node) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
}

View File

@@ -90,7 +90,7 @@ public class NodeHttpServer extends NodeServer {
@Override @Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception { protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter); if (httpServer != null) loadHttpFilter(filterFilter);
} }
@Override @Override
@@ -102,19 +102,19 @@ public class NodeHttpServer extends NodeServer {
private void initWebSocketService() { private void initWebSocketService() {
final NodeServer self = this; final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory(); final ResourceFactory regFactory = application.getResourceFactory();
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务 resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof WebSocketServlet)) return; if (!(srcObj instanceof WebSocketServlet)) return;
ResourceFactory.ResourceLoader loader = null; ResourceTypeLoader loader = null;
ResourceFactory sncpResFactory = null; ResourceFactory sncpResFactory = null;
for (NodeServer ns : application.servers) { for (NodeServer ns : application.servers) {
if (!ns.isSNCP()) continue; if (!ns.isSNCP()) continue;
sncpResFactory = ns.resourceFactory; sncpResFactory = ns.resourceFactory;
loader = sncpResFactory.findLoader(WebSocketNode.class, field); loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field);
if (loader != null) break; if (loader != null) break;
} }
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment); if (loader != null) loader.load(sncpResFactory, srcResourceName, srcObj, resourceName, field, attachment);
synchronized (regFactory) { synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) { if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
@@ -127,15 +127,15 @@ public class NodeHttpServer extends NodeServer {
try { try {
Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); Field c = WebSocketServlet.class.getDeclaredField("messageAgent");
c.setAccessible(true); c.setAccessible(true);
messageAgent = (MessageAgent) c.get(src); messageAgent = (MessageAgent) c.get(srcObj);
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex);
} }
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null); nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService); regFactory.register(resourceName, WebSocketNode.class, nodeService);
} }
resourceFactory.inject(nodeService, self); resourceFactory.inject(resourceName, nodeService, self);
field.set(src, nodeService); field.set(srcObj, nodeService);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService); logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -145,7 +145,7 @@ public class NodeHttpServer extends NodeServer {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception { protected void loadHttpFilter(final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String localThreadName = "[" + Thread.currentThread().getName() + "] "; final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys()); List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());

View File

@@ -14,7 +14,6 @@ import java.lang.reflect.*;
import java.net.*; import java.net.*;
import java.nio.file.*; import java.nio.file.*;
import java.util.*; import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.function.*; import java.util.function.*;
import java.util.logging.*; import java.util.logging.*;
@@ -212,66 +211,13 @@ public abstract class NodeServer {
final ResourceFactory appResFactory = application.getResourceFactory(); final ResourceFactory appResFactory = application.getResourceFactory();
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory(); final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
final AnyValue resources = application.config.getAnyValue("resources"); final AnyValue resources = application.config.getAnyValue("resources");
final String confURI = appResFactory.find(RESNAME_APP_CONF, String.class); final String confURI = appResFactory.find(RESNAME_APP_CONF_DIR, String.class);
final Map<String, SimpleEntry<Class, AnyValue>> cacheResource = new HashMap<>();
final Map<String, SimpleEntry<Class, AnyValue>> dataResources = new HashMap<>();
if (resources != null) {
for (AnyValue sourceConf : resources.getAnyValues("source")) {
try {
String classval = sourceConf.getValue("value");
Class type = null;
if (classval == null || classval.isEmpty()) {
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
List<CacheSourceProvider> providers = new ArrayList<>();
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
while (it.hasNext()) {
CacheSourceProvider s = it.next();
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
if (s != null && s.acceptsConf(sourceConf)) {
providers.add(s);
}
}
Collections.sort(providers, (a, b) -> {
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
});
for (CacheSourceProvider provider : providers) {
type = provider.sourceClass();
if (type != null) break;
}
} else {
type = serverClassLoader.loadClass(classval);
}
if (type == DataSource.class) {
type = DataMemorySource.class;
for (AnyValue itemConf : sourceConf.getAnyValues("property")) {
if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) {
type = DataJdbcSource.class;
break;
}
}
}
if (!Service.class.isAssignableFrom(type)) {
logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf);
} else if (CacheSource.class.isAssignableFrom(type)) {
cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
} else if (DataSource.class.isAssignableFrom(type)) {
dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf));
} else {
logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e);
}
}
}
//------------------------------------- 注册 Resource -------------------------------------------------------- //------------------------------------- 注册 Resource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
try { try {
Resource res = field.getAnnotation(Resource.class); Resource res = field.getAnnotation(Resource.class);
if (res == null || !res.name().startsWith("properties.")) return; if (res == null || !res.name().startsWith("properties.")) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //远程模式不得注入 DataSource
Class type = field.getType(); Class type = field.getType();
if (type != AnyValue.class && type != AnyValue[].class) return; if (type != AnyValue.class && type != AnyValue[].class) return;
Object resource = null; Object resource = null;
@@ -283,18 +229,18 @@ public abstract class NodeServer {
resource = properties.getAnyValues(res.name().substring("properties.".length())); resource = properties.getAnyValues(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue[].class, resource); appResFactory.register(resourceName, AnyValue[].class, resource);
} }
field.set(src, resource); field.set(srcObj, resource);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e); logger.log(Level.SEVERE, "Resource inject error", e);
} }
}, AnyValue.class, AnyValue[].class); }, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册 Local AutoLoad(false) Service -------------------------------------------------------- //------------------------------------- 注册 Local AutoLoad(false) Service --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
Class<Service> resServiceType = Service.class; Class<Service> resServiceType = Service.class;
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 AutoLoad Service if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //远程模式不得注入 AutoLoad Service
if (!Service.class.isAssignableFrom(field.getType())) return; if (!Service.class.isAssignableFrom(field.getType())) return;
resServiceType = (Class) field.getType(); resServiceType = (Class) field.getType();
if (resServiceType.getAnnotation(Local.class) == null) return; if (resServiceType.getAnnotation(Local.class) == null) return;
@@ -302,150 +248,56 @@ public abstract class NodeServer {
if (al == null || al.value()) return; if (al == null || al.value()) return;
//ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
SncpClient client = src instanceof Service ? Sncp.getSncpClient((Service) src) : null; SncpClient client = srcObj instanceof Service ? Sncp.getSncpClient((Service) srcObj) : null;
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final Set<String> groups = new HashSet<>(); final Set<String> groups = new HashSet<>();
Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null); Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null);
appResFactory.register(resourceName, resServiceType, service); appResFactory.register(resourceName, resServiceType, service);
field.set(src, service); field.set(srcObj, service);
rf.inject(service, self); // 给其可能包含@Resource的字段赋值; rf.inject(resourceName, service, self); // 给其可能包含@Resource的字段赋值;
if (!application.isCompileMode()) service.init(null); if (!application.isCompileMode()) service.init(null);
logger.info("[" + Thread.currentThread().getName() + "] Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')"); logger.info("[" + Thread.currentThread().getName() + "] Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')");
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + src + " error", e); logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + srcObj + " error", e);
} }
}, Service.class); }, Service.class);
//------------------------------------- 注册 DataSource -------------------------------------------------------- //------------------------------------- 注册 DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //远程模式不得注入 DataSource
SimpleEntry<Class, AnyValue> resEntry = dataResources.get(resourceName); DataSource source = application.loadDataSource(resourceName, false);
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue(); field.set(srcObj, source);
DataSource source = null;
if (sourceConf != null) {
final Class sourceType = resEntry.getKey();
if (sourceType == DataJdbcSource.class) {
source = DataSources.createDataSource(resourceName, sourceConf);
} else {
boolean can = false;
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
for (Constructor cr : sourceType.getConstructors()) {
if (cr.getParameterCount() == 0) {
can = true;
break;
}
}
if (DataSource.class.isAssignableFrom(sourceType) && can) { // 必须有空构造函数
if (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) {
source = (DataSource) sourceType.getConstructor().newInstance();
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
} else {
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final Set<String> groups = new HashSet<>();
source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService));
}
}
}
}
if (source == null) {
source = DataSources.createDataSource(confURI, resourceName); //从persistence.xml配置中创建
}
RedkaleClassLoader.putReflectionPublicConstructors(source.getClass(), source.getClass().getName());
application.dataSources.add(source);
ResourceType rt = source.getClass().getAnnotation(ResourceType.class);
if (rt != null && rt.value() != DataSource.class) {
appResFactory.register(resourceName, rt.value(), source);
} else if (source instanceof SearchSource) {
appResFactory.register(resourceName, SearchSource.class, source);
}
appResFactory.register(resourceName, DataSource.class, source);
field.set(src, source);
rf.inject(source, self); // 给AsyncGroup和其他@Resource的字段赋值;
//NodeServer.this.watchFactory.inject(src);
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
logger.info("[" + Thread.currentThread().getName() + "] Load DataSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')");
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + src + " error", e); logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + srcObj + " error", e);
} }
}, DataSource.class); }, DataSource.class);
//------------------------------------- 注册 CacheSource -------------------------------------------------------- //------------------------------------- 注册 CacheSource --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() { resourceFactory.register(new ResourceTypeLoader() {
@Override @Override
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) { public void load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src); if (!(srcObj instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + srcObj);
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src; final Service srcService = (Service) srcObj;
SncpClient client = Sncp.getSncpClient(srcService); SncpClient client = Sncp.getSncpClient(srcService);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
SimpleEntry<Class, AnyValue> resEntry = cacheResource.get(resourceName); final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null;
AnyValue sourceConf = resEntry == null ? null : resEntry.getValue(); CacheSource source = application.loadCacheSource(resourceName, ws);
if (sourceConf == null) { field.set(srcObj, source);
SimpleEntry<Class, AnyValue> resEntry2 = dataResources.get(resourceName);
sourceConf = resEntry2 == null ? null : resEntry2.getValue();
}
Class sourceType0 = CacheMemorySource.class;
if (sourceConf != null) {
String classval = sourceConf.getValue("value");
if (classval == null || classval.isEmpty()) {
RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class);
List<CacheSourceProvider> providers = new ArrayList<>();
Iterator<CacheSourceProvider> it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator();
while (it.hasNext()) {
CacheSourceProvider s = it.next();
if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName());
if (s != null && s.acceptsConf(sourceConf)) {
providers.add(s);
}
}
Collections.sort(providers, (a, b) -> {
Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class);
Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
});
for (CacheSourceProvider provider : providers) {
sourceType0 = provider.sourceClass();
if (sourceType0 != null) break;
}
} else {
sourceType0 = serverClassLoader.loadClass(classval);
}
}
final Class sourceType = sourceType0;
Object source = null;
if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource
RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName());
source = sourceType == CacheMemorySource.class ? new CacheMemorySource(resourceName)
: (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) ? sourceType.getConstructor().newInstance()
: (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, null, Sncp.getConf(srcService));
Type genericType = field.getGenericType();
application.cacheSources.add((CacheSource) source);
appResFactory.register(resourceName, CacheSource.class, source);
if (genericType != CacheSource.class) {
appResFactory.register(resourceName, genericType, source);
}
}
field.set(src, source);
rf.inject(source, self); //
if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf);
if ((src instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource if (ws) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
if (source != null && source.getClass().getAnnotation(Local.class) == null) { //本地模式的Service不生成SncpServlet if (source != null && source.getClass().getAnnotation(Local.class) == null) { //本地模式的Service不生成SncpServlet
sncpServer.getSncpServer().addSncpServlet((Service) source); sncpServer.getSncpServer().addSncpServlet((Service) source);
} }
//logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source); //logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
} }
logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')"); logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e); logger.log(Level.SEVERE, "DataSource inject error", e);
} }
@@ -458,28 +310,28 @@ public abstract class NodeServer {
}, CacheSource.class); }, CacheSource.class);
//------------------------------------- 注册 WebSocketNode -------------------------------------------------------- //------------------------------------- 注册 WebSocketNode --------------------------------------------------------
resourceFactory.register(new ResourceFactory.ResourceLoader() { resourceFactory.register(new ResourceTypeLoader() {
@Override @Override
public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) { public void load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
try { try {
if (field.getAnnotation(Resource.class) == null) return; if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 WebSocketNode if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //远程模式不需要注入 WebSocketNode
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) { if (nodeService == null) {
final HashSet<String> groups = new HashSet<>(); final HashSet<String> groups = new HashSet<>();
if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup); if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, Sncp.getMessageAgent((Service) src), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null); nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, Sncp.getMessageAgent((Service) srcObj), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null);
(isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService); (isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService);
((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName); ((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName);
} }
resourceFactory.inject(nodeService, self); resourceFactory.inject(resourceName, nodeService, self);
MessageAgent messageAgent = Sncp.getMessageAgent((Service) src); MessageAgent messageAgent = Sncp.getMessageAgent((Service) srcObj);
if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) Sncp.setMessageAgent(nodeService, messageAgent); if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) Sncp.setMessageAgent(nodeService, messageAgent);
field.set(src, nodeService); field.set(srcObj, nodeService);
if (Sncp.isRemote(nodeService)) { if (Sncp.isRemote(nodeService)) {
remoteServices.add(nodeService); remoteServices.add(nodeService);
} else { } else {
rf.inject(nodeService); //动态加载的Service也存在按需加载的注入资源 rf.inject(resourceName, nodeService); //动态加载的Service也存在按需加载的注入资源
localServices.add(nodeService); localServices.add(nodeService);
interceptorServices.add(nodeService); interceptorServices.add(nodeService);
if (consumer != null) consumer.accept(null, nodeService); if (consumer != null) consumer.accept(null, nodeService);
@@ -529,7 +381,7 @@ public abstract class NodeServer {
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置 || (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| serviceImplClass.getAnnotation(Local.class) != null;//本地模式 || serviceImplClass.getAnnotation(Local.class) != null;//本地模式
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类 if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { final ResourceTypeLoader resourceLoader = (ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) -> {
try { try {
if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的 通常为BaseService if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class没有可用的方法且没有标记启动优先级的 通常为BaseService
if (!serviceImplClass.getName().startsWith("org.redkale.") && !serviceImplClass.getSimpleName().contains("Base")) { if (!serviceImplClass.getName().startsWith("org.redkale.") && !serviceImplClass.getSimpleName().contains("Base")) {
@@ -545,7 +397,7 @@ public abstract class NodeServer {
} }
Service service; Service service;
final boolean ws = src instanceof WebSocketServlet; final boolean ws = srcObj instanceof WebSocketServlet;
if (ws || localed) { //本地模式 if (ws || localed) { //本地模式
service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty()); service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty());
} else { } else {
@@ -565,7 +417,7 @@ public abstract class NodeServer {
remoteServices.add(service); remoteServices.add(service);
if (agent != null) sncpRemoteAgents.put(agent.getName(), agent); if (agent != null) sncpRemoteAgents.put(agent.getName(), agent);
} else { } else {
if (field != null) rf.inject(service); //动态加载的Service也存在按需加载的注入资源 if (field != null) rf.inject(resourceName, service); //动态加载的Service也存在按需加载的注入资源
localServices.add(service); localServices.add(service);
interceptorServices.add(service); interceptorServices.add(service);
if (consumer != null) consumer.accept(agent, service); if (consumer != null) consumer.accept(agent, service);
@@ -577,10 +429,12 @@ public abstract class NodeServer {
} }
}; };
if (entry.isExpect()) { if (entry.isExpect()) {
ResourceType rty = entry.getType().getAnnotation(ResourceType.class); Class t = ResourceFactory.getResourceType(entry.getType());
resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value()); if (resourceFactory.findResourceTypeLoader(t) == null) {
resourceFactory.register(resourceLoader, t);
}
} else { } else {
resourceLoader.load(resourceFactory, null, entry.getName(), null, false); resourceLoader.load(resourceFactory, null, null, entry.getName(), null, false);
} }
} }
@@ -591,10 +445,10 @@ public abstract class NodeServer {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ---------------- //---------------- inject ----------------
new ArrayList<>(localServices).forEach(y -> { new ArrayList<>(localServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this); resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this);
}); });
new ArrayList<>(remoteServices).forEach(y -> { new ArrayList<>(remoteServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this); resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this);
calcMaxLength(y); calcMaxLength(y);
}); });
@@ -852,9 +706,9 @@ public abstract class NodeServer {
server.shutdown(); server.shutdown();
} }
public void command(String cmd) throws IOException { public List<Object> command(String cmd, String[] params) throws IOException {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final boolean finest = logger.isLoggable(Level.FINEST); List<Object> results = new ArrayList<>();
localServices.forEach(y -> { localServices.forEach(y -> {
Set<Method> methods = new HashSet<>(); Set<Method> methods = new HashSet<>();
Class loop = y.getClass(); Class loop = y.getClass();
@@ -862,10 +716,23 @@ public abstract class NodeServer {
for (Method m : loop.getMethods()) { for (Method m : loop.getMethods()) {
Command c = m.getAnnotation(Command.class); Command c = m.getAnnotation(Command.class);
if (c == null) continue; if (c == null) continue;
if (Modifier.isStatic(m.getModifiers())) continue; if (Modifier.isStatic(m.getModifiers())) {
if (m.getReturnType() != void.class) continue; logger.log(Level.WARNING, m + " is static on @Command");
if (m.getParameterCount() != 1) continue; continue;
if (m.getParameterTypes()[0] != String.class) continue; }
if (m.getParameterCount() != 1 && m.getParameterCount() != 2) {
logger.log(Level.WARNING, m + " parameter count = " + m.getParameterCount() + " on @Command");
continue;
}
if (m.getParameterTypes()[0] != String.class) {
logger.log(Level.WARNING, m + " parameters[0] type is not String.class on @Command");
continue;
}
if (m.getParameterCount() == 2 && m.getParameterTypes()[1] != String[].class) {
logger.log(Level.WARNING, m + " parameters[1] type is not String[].class on @Command");
continue;
}
if (!c.value().isEmpty() && !c.value().equalsIgnoreCase(cmd)) continue;
methods.add(m); methods.add(m);
} }
//} while ((loop = loop.getSuperclass()) != Object.class); //} while ((loop = loop.getSuperclass()) != Object.class);
@@ -875,7 +742,8 @@ public abstract class NodeServer {
try { try {
for (Method method : methods) { for (Method method : methods) {
one = method; one = method;
method.invoke(y, cmd); Object r = method.getParameterCount() == 2 ? method.invoke(y, cmd, params) : method.invoke(y, cmd);
if (r != null) results.add(r);
} }
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex); logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex);
@@ -886,6 +754,7 @@ public abstract class NodeServer {
} }
}); });
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
return results;
} }
public <T extends Server> T getServer() { public <T extends Server> T getServer() {

View File

@@ -0,0 +1,26 @@
/*
*/
package org.redkale.boot;
import java.util.Properties;
import org.redkale.util.*;
/**
* 配置源Agent, 在init方法内需要实现读取配置信息如果支持配置更改通知也需要在init里实现监听
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.7.0
*/
public abstract class PropertiesAgent {
public void compile(AnyValue conf) {
}
public abstract void init(ResourceFactory factory, Properties appProperties, AnyValue conf);
public abstract void destroy(AnyValue conf);
}

View File

@@ -37,24 +37,26 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
protected ScheduledThreadPoolExecutor scheduler; protected ScheduledThreadPoolExecutor scheduler;
//可能被HttpMessageClient用到的服务 key: servicename //可能被HttpMessageClient用到的服务 key: serviceName
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
//可能被mqtp用到的服务 key: servicename //可能被mqtp用到的服务 key: serviceName
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>();
@Override @Override
public void init(AnyValue config) { public void init(ResourceFactory factory, AnyValue config) {
super.init(config); super.init(factory, config);
this.sourceName = getSourceName(); this.sourceName = getSourceName();
AnyValue[] properties = config.getAnyValues("property"); this.ttls = config.getIntValue("ttls", 10);
for (AnyValue property : properties) { if (this.ttls < 5) this.ttls = 10;
if ("ttls".equalsIgnoreCase(property.getValue("name"))) { }
this.ttls = Integer.parseInt(property.getValue("value", "").trim());
if (this.ttls < 5) this.ttls = 10; @Override
} public void setConfig(AnyValue config) {
} super.setConfig(config);
this.sourceName = getSourceName();
} }
@Override @Override
@@ -63,15 +65,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
} }
public String getSourceName() { public String getSourceName() {
AnyValue[] properties = config.getAnyValues("property"); return config.getValue("source");
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) {
this.sourceName = property.getValue("value");
return this.sourceName;
}
}
return null;
} }
@Override @Override
@@ -82,13 +76,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Override //ServiceLoader时判断配置是否符合当前实现类 @Override //ServiceLoader时判断配置是否符合当前实现类
public boolean acceptsConf(AnyValue config) { public boolean acceptsConf(AnyValue config) {
if (config == null) return false; if (config == null) return false;
AnyValue[] properties = config.getAnyValues("property"); return config.getValue("source") != null;
if (properties == null || properties.length == 0) return false;
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) return true;
}
return false;
} }
@Override @Override
@@ -120,22 +108,22 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
protected void loadMqtpAddressHealth() { protected void loadMqtpAddressHealth() {
List<String> keys = source.queryKeysStartsWith("cluster.mqtp:"); List<String> keys = source.queryKeysStartsWith("cluster.mqtp:");
keys.forEach(servicename -> { keys.forEach(serviceName -> {
try { try {
this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); this.mqtpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e); logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + serviceName + " error", e);
} }
}); });
} }
protected void checkHttpAddressHealth() { protected void checkHttpAddressHealth() {
try { try {
this.httpAddressMap.keySet().stream().forEach(servicename -> { this.httpAddressMap.keySet().stream().forEach(serviceName -> {
try { try {
this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); this.httpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e); logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e);
} }
}); });
} catch (Exception ex) { } catch (Exception ex) {
@@ -148,10 +136,10 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
newaddr.addr = entry.address; newaddr.addr = entry.address;
newaddr.nodeid = this.nodeid; newaddr.nodeid = this.nodeid;
newaddr.time = System.currentTimeMillis(); newaddr.time = System.currentTimeMillis();
source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr); source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr);
} }
@Override //获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段 @Override //获取MQTP的HTTP远程服务的可用ip列表, key = serviceName的后半段
public CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) { public CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) {
final Map<String, Collection<InetSocketAddress>> rsmap = new ConcurrentHashMap<>(); final Map<String, Collection<InetSocketAddress>> rsmap = new ConcurrentHashMap<>();
final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":"; final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":";
@@ -162,22 +150,22 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Override //获取HTTP远程服务的可用ip列表 @Override //获取HTTP远程服务的可用ip列表
public CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) { public CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
final String servicename = generateHttpServiceName(protocol, module, resname); final String serviceName = generateHttpServiceName(protocol, module, resname);
Collection<InetSocketAddress> rs = httpAddressMap.get(servicename); Collection<InetSocketAddress> rs = httpAddressMap.get(serviceName);
if (rs != null) return CompletableFuture.completedFuture(rs); if (rs != null) return CompletableFuture.completedFuture(rs);
return queryAddress(servicename).thenApply(t -> { return queryAddress(serviceName).thenApply(t -> {
httpAddressMap.put(servicename, t); httpAddressMap.put(serviceName, t);
return t; return t;
}); });
} }
@Override @Override
protected CompletableFuture<Collection<InetSocketAddress>> queryAddress(final ClusterEntry entry) { protected CompletableFuture<Collection<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
return queryAddress(entry.servicename); return queryAddress(entry.serviceName);
} }
private CompletableFuture<Collection<InetSocketAddress>> queryAddress(final String servicename) { private CompletableFuture<Collection<InetSocketAddress>> queryAddress(final String serviceName) {
final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000); final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(serviceName, AddressEntry.class, 0, 10000);
return future.thenApply(map -> { return future.thenApply(map -> {
final Set<InetSocketAddress> set = new HashSet<>(); final Set<InetSocketAddress> set = new HashSet<>();
map.forEach((n, v) -> { map.forEach((n, v) -> {
@@ -188,9 +176,9 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
} }
protected boolean isApplicationHealth() { protected boolean isApplicationHealth() {
String servicename = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
String serviceid = generateApplicationServiceId(); String serviceid = generateApplicationServiceId();
AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class); AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class);
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls; return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls;
} }
@@ -210,18 +198,18 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
deregister(application); deregister(application);
String serviceid = generateApplicationServiceId(); String serviceid = generateApplicationServiceId();
String servicename = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
AddressEntry entry = new AddressEntry(); AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress; entry.addr = this.appAddress;
entry.nodeid = this.nodeid; entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis(); entry.time = System.currentTimeMillis();
source.hset(servicename, serviceid, AddressEntry.class, entry); source.hset(serviceName, serviceid, AddressEntry.class, entry);
} }
@Override @Override
public void deregister(Application application) { public void deregister(Application application) {
String servicename = generateApplicationServiceName(); String serviceName = generateApplicationServiceName();
source.remove(servicename); source.remove(serviceName);
} }
@Override @Override
@@ -233,7 +221,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
entry.addr = clusterEntry.address; entry.addr = clusterEntry.address;
entry.nodeid = this.nodeid; entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis(); entry.time = System.currentTimeMillis();
source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry); source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry);
return clusterEntry; return clusterEntry;
} }
@@ -243,24 +231,24 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
} }
protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) { protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) {
String servicename = generateServiceName(ns, protocol, service); String serviceName = generateServiceName(ns, protocol, service);
String serviceid = generateServiceId(ns, protocol, service); String serviceid = generateServiceId(ns, protocol, service);
ClusterEntry currEntry = null; ClusterEntry currEntry = null;
for (final ClusterEntry entry : localEntrys.values()) { for (final ClusterEntry entry : localEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { if (entry.serviceName.equals(serviceName) && entry.serviceid.equals(serviceid)) {
currEntry = entry; currEntry = entry;
break; break;
} }
} }
if (currEntry == null) { if (currEntry == null) {
for (final ClusterEntry entry : remoteEntrys.values()) { for (final ClusterEntry entry : remoteEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { if (entry.serviceName.equals(serviceName) && entry.serviceid.equals(serviceid)) {
currEntry = entry; currEntry = entry;
break; break;
} }
} }
} }
source.hremove(servicename, serviceid); source.hremove(serviceName, serviceid);
if (realcanceled && currEntry != null) currEntry.canceled = true; if (realcanceled && currEntry != null) currEntry.canceled = true;
if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) { if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) {
deregister(ns, "mqtp", service, realcanceled); deregister(ns, "mqtp", service, realcanceled);

View File

@@ -6,13 +6,15 @@
package org.redkale.cluster; package org.redkale.cluster;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.net.InetSocketAddress; import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.*; import org.redkale.boot.*;
import static org.redkale.boot.Application.*; import static org.redkale.boot.Application.*;
import org.redkale.convert.ConvertDisabled;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.mq.MessageMultiConsumer; import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.*; import org.redkale.net.*;
@@ -60,7 +62,7 @@ public abstract class ClusterAgent {
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
public void init(AnyValue config) { public void init(ResourceFactory factory, AnyValue config) {
this.config = config; this.config = config;
this.name = config.getValue("name", ""); this.name = config.getValue("name", "");
this.waits = config.getBoolValue("waits", false); this.waits = config.getBoolValue("waits", false);
@@ -106,7 +108,7 @@ public abstract class ClusterAgent {
if (localServices.isEmpty()) return; if (localServices.isEmpty()) return;
//注册本地模式 //注册本地模式
for (Service service : localServices) { for (Service service : localServices) {
if (!canRegister(protocol, service)) continue; if (!canRegister(ns, protocol, service)) continue;
ClusterEntry htentry = register(ns, protocol, service); ClusterEntry htentry = register(ns, protocol, service);
localEntrys.put(htentry.serviceid, htentry); localEntrys.put(htentry.serviceid, htentry);
if (protocol.toLowerCase().startsWith("http")) { if (protocol.toLowerCase().startsWith("http")) {
@@ -132,19 +134,21 @@ public abstract class ClusterAgent {
public void deregister(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) { public void deregister(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
//注销本地模式 远程模式不注册 //注销本地模式 远程模式不注册
for (Service service : localServices) { for (Service service : localServices) {
if (!canRegister(protocol, service)) continue; if (!canRegister(ns, protocol, service)) continue;
deregister(ns, protocol, service); deregister(ns, protocol, service);
} }
afterDeregister(ns, protocol); afterDeregister(ns, protocol);
} }
protected boolean canRegister(String protocol, Service service) { protected boolean canRegister(NodeServer ns, String protocol, Service service) {
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false; if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false;
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false; if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false;
if (service instanceof WebSocketNode) { if (service instanceof WebSocketNode) {
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false; if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false;
} }
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
if (entry.serviceName.trim().endsWith(serviceSeparator())) return false;
return true; return true;
} }
@@ -167,7 +171,7 @@ public abstract class ClusterAgent {
return 10; return 10;
} }
//获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段 //获取MQTP的HTTP远程服务的可用ip列表, key = serviceName的后半段
public abstract CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname); public abstract CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname);
//获取HTTP远程服务的可用ip列表 //获取HTTP远程服务的可用ip列表
@@ -184,17 +188,25 @@ public abstract class ClusterAgent {
//格式: protocol:classtype-resourcename //格式: protocol:classtype-resourcename
protected void updateSncpTransport(ClusterEntry entry) { protected void updateSncpTransport(ClusterEntry entry) {
Service service = entry.serviceref.get(); Service service = entry.serviceRef.get();
if (service == null) return; if (service == null) return;
Collection<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join(); Collection<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs); Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netProtocol, entry.address, null, addrs);
}
protected String urlEncode(String value) {
return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8);
} }
protected String generateApplicationServiceName() { protected String generateApplicationServiceName() {
return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid; return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node." + this.nodeid;
} }
protected String generateApplicationServiceId() { //与servicename相同 protected String generateApplicationServiceType() {
return "application.nodes";
}
protected String generateApplicationServiceId() { //与serviceName相同
return generateApplicationServiceName(); return generateApplicationServiceName();
} }
@@ -206,9 +218,21 @@ public abstract class ClusterAgent {
return "check-" + generateApplicationServiceId(); return "check-" + generateApplicationServiceId();
} }
protected String generateApplicationHost() {
return this.appAddress.getHostString();
}
protected int generateApplicationPort() {
return this.appAddress.getPort();
}
protected String serviceSeparator() {
return "-";
}
//也会提供给HttpMessageClusterAgent适用 //也会提供给HttpMessageClusterAgent适用
public String generateHttpServiceName(String protocol, String module, String resname) { public String generateHttpServiceName(String protocol, String module, String resname) {
return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); return protocol.toLowerCase() + serviceSeparator() + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
} }
//格式: protocol:classtype-resourcename //格式: protocol:classtype-resourcename
@@ -216,21 +240,21 @@ public abstract class ClusterAgent {
if (protocol.toLowerCase().startsWith("http")) { //HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, 因为HTTP依靠的url中的module无法知道Service类名 if (protocol.toLowerCase().startsWith("http")) { //HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, 因为HTTP依靠的url中的module无法知道Service类名
String resname = Sncp.getResourceName(service); String resname = Sncp.getResourceName(service);
String module = Rest.getRestModule(service).toLowerCase(); String module = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname)); return protocol.toLowerCase() + serviceSeparator() + module + (resname.isEmpty() ? "" : ("-" + resname));
} }
if ("mqtp".equalsIgnoreCase(protocol)) { if ("mqtp".equalsIgnoreCase(protocol)) {
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
String selfmodule = Rest.getRestModule(service).toLowerCase(); String selfmodule = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule; return protocol.toLowerCase() + serviceSeparator() + mmc.module() + serviceSeparator() + selfmodule;
} }
if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName(); if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + serviceSeparator() + service.getClass().getName();
String resname = Sncp.getResourceName(service); String resname = Sncp.getResourceName(service);
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)); return protocol.toLowerCase() + serviceSeparator() + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname));
} }
//格式: protocol:classtype-resourcename:nodeid //格式: protocol:classtype-resourcename:nodeid
protected String generateServiceId(NodeServer ns, String protocol, Service service) { protected String generateServiceId(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service) + ":" + this.nodeid; return generateServiceName(ns, protocol, service) + serviceSeparator() + this.nodeid;
} }
protected String generateCheckName(NodeServer ns, String protocol, Service service) { protected String generateCheckName(NodeServer ns, String protocol, Service service) {
@@ -249,11 +273,6 @@ public abstract class ClusterAgent {
return remoteEntrys; return remoteEntrys;
} }
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
public TransportFactory getTransportFactory() { public TransportFactory getTransportFactory() {
return transportFactory; return transportFactory;
} }
@@ -296,19 +315,26 @@ public abstract class ClusterAgent {
public class ClusterEntry { public class ClusterEntry {
//serviceName+nodeid为主 服务的单个实例
public String serviceid; public String serviceid;
public String servicename; //以协议+Rest资源名为主 服务类名
public String serviceName;
public String serviceType;
public String checkid; public String checkid;
public String checkname; public String checkName;
//http or sncp or mqtp
public String protocol; public String protocol;
public String netprotocol; //TCP or UDP
public String netProtocol;
public WeakReference<Service> serviceref; @ConvertDisabled
public WeakReference<Service> serviceRef;
public InetSocketAddress address; public InetSocketAddress address;
@@ -318,9 +344,10 @@ public abstract class ClusterAgent {
public ClusterEntry(NodeServer ns, String protocol, Service service) { public ClusterEntry(NodeServer ns, String protocol, Service service) {
this.serviceid = generateServiceId(ns, protocol, service); this.serviceid = generateServiceId(ns, protocol, service);
this.servicename = generateServiceName(ns, protocol, service); this.serviceName = generateServiceName(ns, protocol, service);
this.checkid = generateCheckId(ns, protocol, service); this.checkid = generateCheckId(ns, protocol, service);
this.checkname = generateCheckName(ns, protocol, service); this.checkName = generateCheckName(ns, protocol, service);
this.serviceType = Sncp.getServiceType(service).getName();
this.protocol = protocol; this.protocol = protocol;
InetSocketAddress addr = ns.getSocketAddress(); InetSocketAddress addr = ns.getSocketAddress();
String host = addr.getHostString(); String host = addr.getHostString();
@@ -329,9 +356,9 @@ public abstract class ClusterAgent {
addr = new InetSocketAddress(host, addr.getPort()); addr = new InetSocketAddress(host, addr.getPort());
} }
this.address = addr; this.address = addr;
this.serviceref = new WeakReference(service); this.serviceRef = new WeakReference(service);
Server server = ns.getServer(); Server server = ns.getServer();
this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL; this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL;
} }
@Override @Override

View File

@@ -9,7 +9,7 @@ import java.lang.reflect.Type;
/** /**
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。 * 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
@@ -46,4 +46,8 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
return Object.class; return Object.class;
} }
@Override
public boolean specifyable() {
return false;
}
} }

View File

@@ -7,6 +7,8 @@ package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.function.IntFunction;
import org.redkale.util.Creator;
/** /**
* 数组的反序列化操作类 <br> * 数组的反序列化操作类 <br>
@@ -30,6 +32,8 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
protected final Decodeable<Reader, T> componentDecoder; protected final Decodeable<Reader, T> componentDecoder;
protected final IntFunction<T[]> componentArrayFunction;
protected volatile boolean inited = false; protected volatile boolean inited = false;
protected final Object lock = new Object(); protected final Object lock = new Object();
@@ -52,6 +56,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
} }
factory.register(type, this); factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType); this.componentDecoder = factory.loadDecoder(this.componentType);
this.componentArrayFunction = Creator.arrayFunction(this.componentClass);
} finally { } finally {
inited = true; inited = true;
synchronized (lock) { synchronized (lock) {
@@ -102,7 +107,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
} }
} }
in.readArrayE(); in.readArrayE();
T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); T[] rs = this.componentArrayFunction.apply(result.size());
return result.toArray(rs); return result.toArray(rs);
} }

View File

@@ -29,7 +29,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
protected final Encodeable<Writer, Object> componentEncoder; protected final Encodeable<Writer, Object> componentEncoder;
protected final boolean subtypefinal; protected final boolean subTypeFinal;
protected volatile boolean inited = false; protected volatile boolean inited = false;
@@ -49,7 +49,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
factory.register(type, this); factory.register(type, this);
this.componentEncoder = factory.loadEncoder(this.componentType); this.componentEncoder = factory.loadEncoder(this.componentType);
this.anyEncoder = factory.getAnyEncoder(); this.anyEncoder = factory.getAnyEncoder();
this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers()); this.subTypeFinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers());
} finally { } finally {
inited = true; inited = true;
synchronized (lock) { synchronized (lock) {
@@ -74,7 +74,8 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.componentEncoder == null) { Encodeable<Writer, Object> itemEncoder = this.componentEncoder;
if (itemEncoder == null) {
if (!this.inited) { if (!this.inited) {
synchronized (lock) { synchronized (lock) {
try { try {
@@ -85,8 +86,7 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
} }
} }
} }
Encodeable<Writer, Object> itemEncoder = this.componentEncoder; if (subTypeFinal) {
if (subtypefinal) {
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
for (int i = 0;; i++) { for (int i = 0;; i++) {
writeMemberValue(out, member, itemEncoder, value[i], i); writeMemberValue(out, member, itemEncoder, value[i], i);
@@ -122,6 +122,11 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
return type; return type;
} }
@Override
public boolean specifyable() {
return false;
}
public Type getComponentType() { public Type getComponentType() {
return componentType; return componentType;
} }
@@ -129,5 +134,4 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public Encodeable<Writer, Object> getComponentEncoder() { public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder; return componentEncoder;
} }
} }

View File

@@ -96,6 +96,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
return type; return type;
} }
@Override
public boolean specifyable() {
return false;
}
@Override @Override
public String toString() { public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}"; return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}";

View File

@@ -0,0 +1,77 @@
/*
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* 依附在setter、getter方法、字段进行简单的配置 <br>
* 优先使用coder字段
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Repeatable(ConvertCoder.ConvertCoders.class)
public @interface ConvertCoder {
/**
* 需要指定的字段类型指定了coder字段值则可以不设置此字段
*
* @return 字段类名
*/
Class column() default Object.class;
/**
* 解析/序列化定制化的SimpledCoder
*
* @return SimpledCoder类
*/
Class<? extends SimpledCoder> coder() default SimpledCoder.class;
/**
* 序列化定制化的 Encodeable
*
* @return Encodeable 类
*/
Class<? extends Encodeable> encoder() default Encodeable.class;
/**
* 反序列化定制化的 Decodeable
*
* @return Decodeable 类
*/
Class<? extends Decodeable> decoder() default Decodeable.class;
/**
* 解析/序列化定制化的TYPE
*
* @return JSON or BSON or ALL
*/
ConvertType type() default ConvertType.ALL;
/**
* ConvertCoder 的多用类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public static @interface ConvertCoders {
ConvertCoder[] value();
}
}

View File

@@ -12,7 +12,7 @@ import java.net.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler; import java.nio.channels.CompletionHandler;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.*; import java.util.stream.*;
@@ -248,7 +248,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
if (type instanceof Class) { if (type instanceof Class) {
Class<?> clazz = (Class) type; Class<?> clazz = (Class) type;
ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class); ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class);
if (ci != null) { if (ci != null && ci.value() != Object.class) {
if (!clazz.isAssignableFrom(ci.value())) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".value(" + ci.value() + ") must be " + clazz + "'s subclass");
}
if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) { if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not"); throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not");
} }
@@ -270,6 +273,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
return new ObjectDecoder(type); return new ObjectDecoder(type);
} }
protected <E> Decodeable<R, E> createMultiImplDecoder(Class[] types) {
return null;
}
protected <E> ObjectEncoder<W, E> createObjectEncoder(Type type) { protected <E> ObjectEncoder<W, E> createObjectEncoder(Type type) {
return new ObjectEncoder(type); return new ObjectEncoder(type);
} }
@@ -401,7 +408,9 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
static String readGetSetFieldName(Method method) { static String readGetSetFieldName(Method method) {
if (method == null) return null; if (method == null) return null;
String fname = method.getName(); String fname = method.getName();
if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; //record类会直接用field名作为method名 if (!(fname.startsWith("is") && fname.length() > 2)
&& !(fname.startsWith("get") && fname.length() > 3)
&& !(fname.startsWith("set") && fname.length() > 3)) return fname; //record类会直接用field名作为method名
fname = fname.substring(fname.startsWith("is") ? 2 : 3); fname = fname.substring(fname.startsWith("is") ? 2 : 3);
if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) {
fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1);
@@ -482,6 +491,175 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} }
} }
ConvertFactory columnFactory(Class type, ConvertCoder[] coders, boolean encode) {
if (coders == null || coders.length < 1) return this;
final ConvertType ct = this.getConvertType();
List<Encodeable> encoderList = null;
List<Decodeable> decoderList = null;
Class readerOrWriterClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[encode ? 1 : 0];
for (ConvertCoder ann : coders) {
if (!ann.type().contains(ct)) continue;
SimpledCoder coder = null;
Class<? extends SimpledCoder> clazz1 = ann.coder();
if (clazz1 != SimpledCoder.class) {
try {
boolean skip = false;
RedkaleClassLoader.putReflectionPublicMethods(clazz1.getName());
for (Method method : clazz1.getMethods()) {
if (method.isBridge()) continue;
if (encode) {
if ("convertTo".equals(method.getName()) && method.getParameterCount() == 2 && Writer.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
} else {
if ("convertFrom".equals(method.getName()) && method.getParameterCount() == 1 && Reader.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
}
}
if (skip) continue;
Field instanceField = clazz1.getField("instance");
if (Modifier.isStatic(instanceField.getModifiers()) && instanceField.getType() == clazz1) {
RedkaleClassLoader.putReflectionField(clazz1.getName(), instanceField);
coder = (SimpledCoder) instanceField.get(null);
}
} catch (Throwable t) {
}
if (coder == null) {
try {
coder = (SimpledCoder) clazz1.getConstructor().newInstance();
RedkaleClassLoader.putReflectionPublicConstructors(clazz1, clazz1.getName());
} catch (Throwable t) {
t.printStackTrace();
continue;
}
}
if (encode) {
if (encoderList == null) encoderList = new ArrayList<>();
encoderList.add(coder);
} else {
if (decoderList == null) decoderList = new ArrayList<>();
decoderList.add(coder);
}
}
if (coder == null) {
Class colType = type;
if (ann.column() != Object.class) colType = ann.column();
if (encode) {
Class<? extends Encodeable> clazz2 = ann.encoder();
if (clazz2 != Encodeable.class) {
try {
boolean skip = false;
RedkaleClassLoader.putReflectionPublicMethods(clazz2.getName());
for (Method method : clazz2.getMethods()) {
if (method.isBridge()) continue;
if ("convertTo".equals(method.getName()) && method.getParameterCount() == 2 && Writer.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
}
if (skip) continue;
Encodeable encoder = null;
Constructor constructor = clazz2.getConstructors()[0];
Parameter[] params = constructor.getParameters();
Class[] paramTypes = new Class[params.length];
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = params[i].getType();
}
if (params.length == 0) {
encoder = (Encodeable) constructor.newInstance();
} else if (params.length == 1) {
if (paramTypes[0] != Type.class) throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
encoder = (Encodeable) constructor.newInstance(colType);
} else if (params.length == 2) {
if (paramTypes[0] == ConvertFactory.class && paramTypes[1] == Type.class) {
encoder = (Encodeable) constructor.newInstance(this, colType);
} else if (paramTypes[0] == Type.class && paramTypes[1] == ConvertFactory.class) {
encoder = (Encodeable) constructor.newInstance(colType, this);
} else {
throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
}
} else {
throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
}
RedkaleClassLoader.putReflectionPublicConstructors(clazz2, clazz2.getName());
if (encoderList == null) encoderList = new ArrayList<>();
encoderList.add(encoder);
} catch (Throwable t) {
t.printStackTrace();
continue;
}
}
} else {
Class<? extends Decodeable> clazz2 = ann.decoder();
if (clazz2 != Decodeable.class) {
try {
boolean skip = false;
RedkaleClassLoader.putReflectionPublicMethods(clazz2.getName());
for (Method method : clazz2.getMethods()) {
if (method.isBridge()) continue;
if ("convertFrom".equals(method.getName()) && method.getParameterCount() == 1 && Reader.class.isAssignableFrom(method.getParameterTypes()[0])) {
skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass);
break;
}
}
if (skip) continue;
Decodeable decoder = null;
Constructor constructor = clazz2.getConstructors()[0];
Parameter[] params = constructor.getParameters();
Class[] paramTypes = new Class[params.length];
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = params[i].getType();
}
if (params.length == 0) {
decoder = (Decodeable) constructor.newInstance();
} else if (params.length == 1) {
if (paramTypes[0] != Type.class) throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
decoder = (Decodeable) constructor.newInstance(colType);
} else if (params.length == 2) {
if (paramTypes[0] == ConvertFactory.class && paramTypes[1] == Type.class) {
decoder = (Decodeable) constructor.newInstance(this, colType);
} else if (paramTypes[0] == Type.class && paramTypes[1] == ConvertFactory.class) {
decoder = (Decodeable) constructor.newInstance(colType, this);
} else {
throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
}
} else {
throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor");
}
RedkaleClassLoader.putReflectionPublicConstructors(clazz2, clazz2.getName());
if (decoderList == null) decoderList = new ArrayList<>();
decoderList.add(decoder);
} catch (Throwable t) {
t.printStackTrace();
continue;
}
}
}
}
}
if (encoderList == null && decoderList == null) return this;
ConvertFactory child = createChild();
if (encode) {
for (Encodeable item : encoderList) {
child.register(item.getType(), item);
if (item instanceof ObjectEncoder) {
((ObjectEncoder) item).init(child);
}
}
} else {
for (Decodeable item : decoderList) {
child.register(item.getType(), item);
if (item instanceof ObjectDecoder) {
((ObjectDecoder) item).init(child);
}
}
}
return child;
}
private Class findEntityAlias(String name) { private Class findEntityAlias(String name) {
Class clazz = entitys.get(name); Class clazz = entitys.get(name);
return parent == null ? clazz : parent.findEntityAlias(name); return parent == null ? clazz : parent.findEntityAlias(name);
@@ -600,8 +778,8 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} }
public final void reloadCoder(final Type type, final Class clazz) { public final void reloadCoder(final Type type, final Class clazz) {
this.register(type, this.createDecoder(type, clazz)); this.register(type, this.createDecoder(type, clazz, false));
this.register(type, this.createEncoder(type, clazz)); this.register(type, this.createEncoder(type, clazz, false));
} }
public final <E> void register(final Class<E> clazz, final Creator<? extends E> creator) { public final <E> void register(final Class<E> clazz, final Creator<? extends E> creator) {
@@ -717,10 +895,14 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
throw new ConvertException("not support the type (" + type + ")"); throw new ConvertException("not support the type (" + type + ")");
} }
//此处不能再findDecoder否则type与class不一致, 如: RetResult 和 RetResult<Integer> //此处不能再findDecoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createDecoder(type, clazz); return createDecoder(type, clazz, false);
} }
public final <E> Decodeable<R, E> createDecoder(final Type type) { public final <E> Decodeable<R, E> createDecoder(final Type type) {
return createDecoder(type, false);
}
public final <E> Decodeable<R, E> createDecoder(final Type type, boolean skipCustomMethod) {
Class clazz; Class clazz;
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type; final ParameterizedType pts = (ParameterizedType) type;
@@ -730,10 +912,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else { } else {
throw new ConvertException("not support the type (" + type + ")"); throw new ConvertException("not support the type (" + type + ")");
} }
return createDecoder(type, clazz); return createDecoder(type, clazz, skipCustomMethod);
} }
private <E> Decodeable<R, E> createDecoder(final Type type, final Class clazz) { private <E> Decodeable<R, E> createDecoder(final Type type, final Class clazz, boolean skipCustomMethod) {
Decodeable<R, E> decoder = null; Decodeable<R, E> decoder = null;
ObjectDecoder od = null; ObjectDecoder od = null;
if (clazz.isEnum()) { if (clazz.isEnum()) {
@@ -756,25 +938,47 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
|| java.util.AbstractMap.SimpleEntry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz
|| clazz.getName().startsWith("java.awt.geom.Point2D")) { || clazz.getName().startsWith("java.awt.geom.Point2D")) {
Decodeable simpleCoder = null; Decodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) { if (!skipCustomMethod) {
if (!Modifier.isStatic(method.getModifiers())) continue; for (Class subclazz : getSuperClasses(clazz)) {
Class[] paramTypes = method.getParameterTypes(); for (final Method method : subclazz.getDeclaredMethods()) {
if (paramTypes.length != 1) continue; if (!Modifier.isStatic(method.getModifiers())) continue;
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; Class[] paramTypes = method.getParameterTypes();
if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue; if (paramTypes.length != 1 && paramTypes.length != 2) continue;
try { if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue;
method.setAccessible(true); if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) continue;
simpleCoder = (Decodeable) method.invoke(null, this); if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue;
RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) continue; //声明private的只能被自身类使用
RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); try {
break; method.setAccessible(true);
} catch (Exception e) { simpleCoder = (Decodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this));
RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName());
RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
if (simpleCoder != null) break;
} }
} }
if (simpleCoder == null) { if (simpleCoder == null) {
Type impl = formatObjectType(type); if (type instanceof Class) {
od = createObjectDecoder(impl); Class<?> typeclz = (Class) type;
decoder = od; ConvertImpl ci = typeclz.getAnnotation(ConvertImpl.class);
if (ci != null && ci.types().length > 0) {
for (Class sub : ci.types()) {
if (!typeclz.isAssignableFrom(sub)) {
throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".types(" + sub + ") must be " + typeclz + "'s subclass");
}
}
decoder = createMultiImplDecoder(ci.types());
}
}
if (decoder == null) {
Type impl = formatObjectType(type);
od = createObjectDecoder(impl);
decoder = od;
}
} else { } else {
decoder = simpleCoder; decoder = simpleCoder;
} }
@@ -807,10 +1011,14 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
throw new ConvertException("not support the type (" + type + ")"); throw new ConvertException("not support the type (" + type + ")");
} }
//此处不能再findEncoder否则type与class不一致, 如: RetResult 和 RetResult<Integer> //此处不能再findEncoder否则type与class不一致, 如: RetResult 和 RetResult<Integer>
return createEncoder(type, clazz); return createEncoder(type, clazz, false);
} }
public final <E> Encodeable<W, E> createEncoder(final Type type) { public final <E> Encodeable<W, E> createEncoder(final Type type) {
return createEncoder(type, false);
}
public final <E> Encodeable<W, E> createEncoder(final Type type, boolean skipCustomMethod) {
Class clazz; Class clazz;
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final ParameterizedType pts = (ParameterizedType) type; final ParameterizedType pts = (ParameterizedType) type;
@@ -820,10 +1028,10 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else { } else {
throw new ConvertException("not support the type (" + type + ")"); throw new ConvertException("not support the type (" + type + ")");
} }
return createEncoder(type, clazz); return createEncoder(type, clazz, skipCustomMethod);
} }
private <E> Encodeable<W, E> createEncoder(final Type type, final Class clazz) { private <E> Encodeable<W, E> createEncoder(final Type type, final Class clazz, boolean skipCustomMethod) {
Encodeable<W, E> encoder = null; Encodeable<W, E> encoder = null;
ObjectEncoder oe = null; ObjectEncoder oe = null;
if (clazz.isEnum()) { if (clazz.isEnum()) {
@@ -843,19 +1051,27 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz } else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz
|| java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) { || java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) {
Encodeable simpleCoder = null; Encodeable simpleCoder = null;
for (final Method method : clazz.getDeclaredMethods()) { if (!skipCustomMethod) {
if (!Modifier.isStatic(method.getModifiers())) continue; for (Class subclazz : getSuperClasses(clazz)) {
Class[] paramTypes = method.getParameterTypes(); for (final Method method : subclazz.getDeclaredMethods()) {
if (paramTypes.length != 1) continue; if (!Modifier.isStatic(method.getModifiers())) continue;
if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; Class[] paramTypes = method.getParameterTypes();
if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue; if (paramTypes.length != 1 && paramTypes.length != 2) continue;
try { if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue;
method.setAccessible(true); if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) continue;
simpleCoder = (Encodeable) method.invoke(null, this); if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue;
RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) continue; //声明private的只能被自身类使用
RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); try {
break; method.setAccessible(true);
} catch (Exception e) { simpleCoder = (Encodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this));
RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName());
RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method);
break;
} catch (Exception e) {
e.printStackTrace();
}
}
if (simpleCoder != null) break;
} }
} }
if (simpleCoder == null) { if (simpleCoder == null) {
@@ -876,4 +1092,18 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
} }
private Set<Class> getSuperClasses(final Class clazz) {
Set<Class> set = new LinkedHashSet<>();
set.add(clazz);
Class recursClass = clazz;
while ((recursClass = recursClass.getSuperclass()) != null) {
if (recursClass == Object.class) break;
set.addAll(getSuperClasses(recursClass));
}
for (Class sub : clazz.getInterfaces()) {
set.addAll(getSuperClasses(sub));
}
return set;
}
} }

View File

@@ -19,18 +19,18 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* public String getName(); * public String getName();
* } * }
* *
* *
* public class OneImpl implements OneEntity { * public class OneImpl implements OneEntity {
* private String name; * private String name;
* public String getName(){return name;} * public String getName(){return name;}
* public void setName(String name){this.name=name;} * public void setName(String name){this.name=name;}
* } * }
* *
* *
* String json = "{'name':'hello'}"; * String json = "{'name':'hello'}";
* OneEntity one = JsonConvert.root.convertFrom(OneEntity.class, json); * OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json);
* //one instanceof OneImpl * //one instanceof OneImpl
* *
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
@@ -38,7 +38,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* @author zhangjx * @author zhangjx
* @since 2.5.0 * @since 2.5.0
*/ */
@Inherited //一定不能标记Inherited
@Documented @Documented
@Target({TYPE}) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
@@ -49,5 +49,12 @@ public @interface ConvertImpl {
* *
* @return String * @return String
*/ */
Class value(); Class value() default Object.class;
/**
* 实现类的集合
*
* @return Class[]
*/
Class[] types() default {};
} }

View File

@@ -88,26 +88,26 @@ public final class DeMember<R extends Reader, T, F> {
this.decoder = decoder; 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) { public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldName) {
try { try {
Field field = clazz.getDeclaredField(fieldname); Field field = clazz.getDeclaredField(fieldName);
return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()), field, null); return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()), field, null);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldname, final Class<F> fieldtype) { public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldName, final Class<F> fieldType) {
try { try {
Field field = clazz.getDeclaredField(fieldname); Field field = clazz.getDeclaredField(fieldName);
return new DeMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadDecoder(fieldtype), field, null); return new DeMember<>(Attribute.create(clazz, fieldName, fieldType), factory.loadDecoder(fieldType), field, null);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static <R extends Reader, T, F> DeMember<R, T, F> create(final Attribute<T, F> attribute, final ConvertFactory factory, final Class<F> fieldtype) { public static <R extends Reader, T, F> DeMember<R, T, F> create(final Attribute<T, F> attribute, final ConvertFactory factory, final Class<F> fieldType) {
return new DeMember<>(attribute, factory.loadDecoder(fieldtype), null, null); return new DeMember<>(attribute, factory.loadDecoder(fieldType), null, null);
} }
public final boolean accepts(String name) { public final boolean accepts(String name) {

View File

@@ -96,6 +96,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
return type; return type;
} }
@Override
public boolean specifyable() {
return false;
}
public Type getKeyType() { public Type getKeyType() {
return keyEncoder == null ? null : keyEncoder.getType(); return keyEncoder == null ? null : keyEncoder.getType();
} }

View File

@@ -34,6 +34,10 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
protected DeMember[] members; protected DeMember[] members;
protected Map<String, DeMember> memberFieldMap;
protected Map<Integer, DeMember> memberTagMap;
protected ConvertFactory factory; protected ConvertFactory factory;
protected volatile boolean inited = false; protected volatile boolean inited = false;
@@ -92,6 +96,7 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator); final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try { try {
ConvertColumnEntry ref; ConvertColumnEntry ref;
ConvertFactory colFactory;
RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); RedkaleClassLoader.putReflectionPublicFields(clazz.getName());
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue; if (Modifier.isStatic(field.getModifiers())) continue;
@@ -99,17 +104,18 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
ref = factory.findRef(clazz, field); ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), false);
Decodeable<R, ?> fieldCoder; Decodeable<R, ?> fieldCoder;
if (small != null && field.getType() == String.class) { if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else { } else {
fieldCoder = factory.findFieldCoder(clazz, field.getName()); fieldCoder = colFactory.findFieldCoder(clazz, field.getName());
} }
if (fieldCoder == null) { if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadDecoder(t); fieldCoder = colFactory.loadDecoder(t);
} }
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -153,17 +159,22 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); ConvertSmallString small = method.getAnnotation(ConvertSmallString.class);
Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getParameterTypes()[0], method.getAnnotationsByType(ConvertCoder.class), false);
if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), false);
}
Decodeable<R, ?> fieldCoder; Decodeable<R, ?> fieldCoder;
if (small != null && method.getReturnType() == String.class) { if (small != null && method.getParameterTypes()[0] == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else { } else {
fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); fieldCoder = colFactory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
} }
if (fieldCoder == null) { if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type); Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
fieldCoder = factory.loadDecoder(t); fieldCoder = colFactory.loadDecoder(t);
} }
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder, ConvertFactory.readGetSetField(method), method); DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, null, null, method), fieldCoder, maybeField, method);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -217,6 +228,12 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
this.members = list.toArray(new DeMember[list.size()]); this.members = list.toArray(new DeMember[list.size()]);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
this.memberFieldMap = new HashMap<>(this.members.length);
this.memberTagMap = new HashMap<>(this.members.length);
for (DeMember member : this.members) {
this.memberFieldMap.put(member.getAttribute().field(), member);
this.memberTagMap.put(member.getTag(), member);
}
if (cps != null) { if (cps != null) {
final String[] fields = cps; final String[] fields = cps;
@@ -231,6 +248,8 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
} }
this.creatorConstructorMembers = ms; this.creatorConstructorMembers = ms;
} }
afterInitDeMember(factory);
} catch (Exception ex) { } catch (Exception ex) {
throw new ConvertException(ex); throw new ConvertException(ex);
} }
@@ -242,13 +261,6 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
} }
} }
protected void initForEachDeMember(ConvertFactory factory, DeMember member) {
}
protected void setTag(DeMember member, int tag) {
member.tag = tag;
}
/** /**
* 对象格式: [0x1][short字段个数][字段名][字段值]...[0x2] * 对象格式: [0x1][short字段个数][字段名][字段值]...[0x2]
* *
@@ -276,37 +288,41 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator."); throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator.");
} }
} }
DeMember[] memberArray = this.members;
Map<String, DeMember> fieldMap = this.memberFieldMap;
Map<Integer, DeMember> tagMap = this.memberTagMap;
if (this.creatorConstructorMembers == null) { //空构造函数 if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator == null ? null : this.creator.create(); final T result = this.creator == null ? null : this.creator.create();
boolean first = true; boolean first = true;
while (hasNext(objin, first)) { while (objin.hasNext()) {
DeMember member = objin.readFieldName(members); DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap);
objin.readBlank(); objin.readBlank();
if (member == null) { if (member == null) {
objin.skipValue(); //跳过不存在的属性的值 objin.skipValue(); //跳过不存在的属性的值
} else { } else {
readMemberValue(objin, member, result, first); readDeMemberValue(objin, member, result, first);
} }
first = false; first = false;
} }
objin.readObjectE(typeClass); objin.readObjectE(typeClass);
return result; return result;
} else { //带参数的构造函数 } else { //带参数的构造函数
final DeMember<R, T, ?>[] fields = this.creatorConstructorMembers; final DeMember<R, T, ?>[] constructorFields = this.creatorConstructorMembers;
final Object[] constructorParams = new Object[fields.length]; final Object[] constructorParams = new Object[constructorFields.length];
final Object[][] otherParams = new Object[this.members.length][2]; final Object[][] otherParams = new Object[this.members.length][2];
int oc = 0; int oc = 0;
boolean first = true; boolean first = true;
while (hasNext(objin, first)) { while (objin.hasNext()) {
DeMember member = objin.readFieldName(members); DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap);
objin.readBlank(); objin.readBlank();
if (member == null) { if (member == null) {
objin.skipValue(); //跳过不存在的属性的值 objin.skipValue(); //跳过不存在的属性的值
} else { } else {
Object val = readMemberValue(objin, member, first); Object val = readDeMemberValue(objin, member, first);
boolean flag = true; boolean flag = true;
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < constructorFields.length; i++) {
if (member == fields[i]) { if (member == constructorFields[i]) {
constructorParams[i] = val; constructorParams[i] = val;
flag = false; flag = false;
break; break;
@@ -327,29 +343,69 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
} }
} }
protected R objectReader(R in) { //---------------------------------- 可定制方法 ----------------------------------
return in; protected void initForEachDeMember(ConvertFactory factory, DeMember member) {
}
protected void afterInitDeMember(ConvertFactory factory) {
} }
protected boolean hasNext(R in, boolean first) { protected boolean hasNext(R in, boolean first) {
return in.hasNext(); return in.hasNext();
} }
protected Object readMemberValue(R in, DeMember member, boolean first) { protected R objectReader(R in) {
return in;
}
protected Object readDeMemberValue(R in, DeMember member, boolean first) {
return member.read(in); return member.read(in);
} }
protected void readMemberValue(R in, DeMember member, T result, boolean first) { protected void readDeMemberValue(R in, DeMember member, T result, boolean first) {
member.read(in, result); member.read(in, result);
} }
//---------------------------------------------------------------------------------
protected void setTag(DeMember member, int tag) {
member.tag = tag;
}
protected void setIndex(DeMember member, int index) {
member.index = index;
}
protected void setPosition(DeMember member, int position) {
member.position = position;
}
@Override @Override
public Type getType() { public Type getType() {
return this.type; return this.type;
} }
public DeMember[] getMembers() { public DeMember[] getMembers() {
return Arrays.copyOf(members, members.length); return members;
}
public DeMember getMember(String fieldName) {
return memberFieldMap.get(fieldName);
}
public Map<String, DeMember> getMemberFieldMap() {
return memberFieldMap;
}
public Map<Integer, DeMember> getMemberTagMap() {
return memberTagMap;
}
public DeMember<R, T, ?>[] getConstructorMembers() {
return creatorConstructorMembers;
}
public Creator<T> getCreator() {
return creator;
} }
@Override @Override

View File

@@ -73,7 +73,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator); final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator);
try { try {
ConvertColumnEntry ref; ConvertColumnEntry ref;
ConvertFactory colFactory;
RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); RedkaleClassLoader.putReflectionPublicFields(clazz.getName());
for (final Field field : clazz.getFields()) { for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue; if (Modifier.isStatic(field.getModifiers())) continue;
@@ -81,17 +81,18 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
ref = factory.findRef(clazz, field); ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue; if (ref != null && ref.ignore()) continue;
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), true);
Encodeable<W, ?> fieldCoder; Encodeable<W, ?> fieldCoder;
if (small != null && field.getType() == String.class) { if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else { } else {
fieldCoder = factory.findFieldCoder(clazz, field.getName()); fieldCoder = colFactory.findFieldCoder(clazz, field.getName());
} }
if (fieldCoder == null) { if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t); fieldCoder = colFactory.loadEncoder(t);
} }
EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); EnMember member = new EnMember(createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -104,7 +105,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
if (method.getName().equals("getClass")) continue; if (method.getName().equals("getClass")) continue;
if (method.getReturnType() == void.class) continue; if (method.getReturnType() == void.class) continue;
if (method.getParameterCount() != 0) continue; if (method.getParameterCount() != 0) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get") && !Utility.isRecordGetter(clazz, method)) continue; if (!(method.getName().startsWith("is") && method.getName().length() > 2)
&& !(method.getName().startsWith("get") && method.getName().length() > 3)
&& !Utility.isRecordGetter(clazz, method)) continue;
if (factory.isConvertDisabled(method)) continue; if (factory.isConvertDisabled(method)) continue;
String convertname = ConvertFactory.readGetSetFieldName(method); String convertname = ConvertFactory.readGetSetFieldName(method);
if (reversible && (cps == null || !contains(cps, convertname))) { if (reversible && (cps == null || !contains(cps, convertname))) {
@@ -125,17 +128,22 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} catch (Exception e) { } catch (Exception e) {
} }
} }
Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getReturnType(), method.getAnnotationsByType(ConvertCoder.class), true);
if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), true);
}
Encodeable<W, ?> fieldCoder; Encodeable<W, ?> fieldCoder;
if (small != null && method.getReturnType() == String.class) { if (small != null && method.getReturnType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else { } else {
fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); fieldCoder = colFactory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
} }
if (fieldCoder == null) { if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t); fieldCoder = colFactory.loadEncoder(t);
} }
EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder, ConvertFactory.readGetSetField(method), method); EnMember member = new EnMember(createAttribute(colFactory, type, clazz, null, method, null), fieldCoder, maybeField, method);
if (ref != null) member.index = ref.getIndex(); if (ref != null) member.index = ref.getIndex();
list.add(member); list.add(member);
} }
@@ -197,6 +205,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
this.members = list.toArray(new EnMember[list.size()]); this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
afterInitEnMember(factory);
} catch (Exception ex) { } catch (Exception ex) {
throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex); throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex);
} }
@@ -208,13 +217,6 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} }
} }
protected void initForEachEnMember(ConvertFactory factory, EnMember member) {
}
protected void setTag(EnMember member, int tag) {
member.tag = tag;
}
@Override @Override
public void convertTo(W out, T value) { public void convertTo(W out, T value) {
if (value == null) { if (value == null) {
@@ -258,10 +260,30 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
objout.writeObjectE(value); objout.writeObjectE(value);
} }
//---------------------------------- 可定制方法 ----------------------------------
protected void initForEachEnMember(ConvertFactory factory, EnMember member) {
}
protected void afterInitEnMember(ConvertFactory factory) {
}
protected W objectWriter(W out, T value) { protected W objectWriter(W out, T value) {
return out; return out;
} }
//---------------------------------------------------------------------------------
protected void setTag(EnMember member, int tag) {
member.tag = tag;
}
protected void setIndex(EnMember member, int index) {
member.index = index;
}
protected void setPosition(EnMember member, int position) {
member.position = position;
}
@Override @Override
public Type getType() { public Type getType() {
return this.type; return this.type;
@@ -272,7 +294,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} }
public EnMember[] getMembers() { public EnMember[] getMembers() {
return Arrays.copyOf(members, members.length); return members;
} }
@Override @Override
@@ -280,54 +302,6 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
} }
//
// 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) { static boolean contains(String[] values, String value) {
for (String str : values) { for (String str : values) {
if (str.equals(value)) return true; if (str.equals(value)) return true;
@@ -371,8 +345,12 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
} }
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
} }
Type subclass = realType;
return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null); if ((realType instanceof Class) && field != null && getter == null && setter == null) {
//修复父类含public fieldsubclass不传父类会导致java.lang.NoSuchFieldError的bug
subclass = field.getDeclaringClass();
}
return Attribute.create(subclass, clazz, fieldalias, null, field, getter, setter, null);
} }
} }

View File

@@ -5,6 +5,8 @@
*/ */
package org.redkale.convert; package org.redkale.convert;
import java.util.Map;
/** /**
* 反序列化的数据读取流 * 反序列化的数据读取流
* *
@@ -141,11 +143,13 @@ public abstract class Reader {
/** /**
* 根据字段读取字段对应的DeMember * 根据字段读取字段对应的DeMember
* *
* @param members DeMember的全量集合 * @param members DeMember的全量集合
* @param memberFieldMap DeMember的字段名map
* @param memberTagMap DeMember的tag map
* *
* @return 匹配的DeMember * @return 匹配的DeMember
*/ */
public abstract DeMember readFieldName(final DeMember[] members); public abstract DeMember readFieldName(final DeMember[] members, Map<String, DeMember> memberFieldMap, Map<Integer, DeMember> memberTagMap);
/** /**
* 读取一个boolean值 * 读取一个boolean值

View File

@@ -97,6 +97,11 @@ public class StreamEncoder<T> implements Encodeable<Writer, Stream<T>> {
return type; return type;
} }
@Override
public boolean specifyable() {
return false;
}
public Encodeable<Writer, Object> getComponentEncoder() { public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder; return componentEncoder;
} }

View File

@@ -28,6 +28,8 @@ public abstract class TextConvert<R extends Reader, W extends Writer> extends Co
return false; return false;
} }
public abstract <T> T convertFrom(final Type type, final String text);
public abstract String convertTo(final Object value); public abstract String convertTo(final Object value);
public abstract String convertTo(final Type type, final Object value); public abstract String convertTo(final Type type, final Object value);

View File

@@ -58,6 +58,10 @@ public final class BsonFactory extends ConvertFactory<BsonReader, BsonWriter> {
return this; return this;
} }
protected boolean tiny() {
return this.tiny;
}
@Override @Override
public BsonFactory skipAllIgnore(final boolean skipIgnore) { public BsonFactory skipAllIgnore(final boolean skipIgnore) {
this.registerSkipAllIgnore(skipIgnore); this.registerSkipAllIgnore(skipIgnore);

View File

@@ -6,6 +6,7 @@
package org.redkale.convert.bson; package org.redkale.convert.bson;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.redkale.convert.*; import org.redkale.convert.*;
import static org.redkale.convert.Reader.SIGN_NULL; import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
@@ -219,19 +220,19 @@ public class BsonReader extends Reader {
} }
@Override @Override
public final DeMember readFieldName(final DeMember[] members) { public final DeMember readFieldName(final DeMember[] members, Map<String, DeMember> memberFieldMap, Map<Integer, DeMember> memberTagMap) {
final String exceptedfield = readSmallString(); final String exceptedField = readSmallString();
this.typeval = readByte(); this.typeval = readByte();
final int len = members.length; final int len = members.length;
if (this.fieldIndex >= len) this.fieldIndex = 0; if (this.fieldIndex >= len) this.fieldIndex = 0;
for (int k = this.fieldIndex; k < len; k++) { for (int k = this.fieldIndex; k < len; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) { if (exceptedField.equals(members[k].getAttribute().field())) {
this.fieldIndex = k; this.fieldIndex = k;
return members[k]; return members[k];
} }
} }
for (int k = 0; k < this.fieldIndex; k++) { for (int k = 0; k < this.fieldIndex; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) { if (exceptedField.equals(members[k].getAttribute().field())) {
this.fieldIndex = k; this.fieldIndex = k;
return members[k]; return members[k];
} }

View File

@@ -27,7 +27,7 @@ public class BsonWriter extends Writer implements ByteTuple {
protected int count; protected int count;
protected boolean tiny; protected boolean tiny = BsonFactory.root().tiny();
public static ObjectPool<BsonWriter> createPool(int max) { public static ObjectPool<BsonWriter> createPool(int max) {
return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle()); return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle());

View File

@@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.redkale.convert.json.*;
import org.redkale.util.Utility; import org.redkale.util.Utility;
/** /**
@@ -41,4 +42,30 @@ public final class BigDecimalSimpledCoder<R extends Reader, W extends Writer> ex
return new BigDecimal(Utility.charArray(value)); return new BigDecimal(Utility.charArray(value));
} }
/**
* BigDecimal 的JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class BigDecimalJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, BigDecimal> {
public static final BigDecimalJsonSimpledCoder instance = new BigDecimalJsonSimpledCoder();
@Override
public void convertTo(final W out, final BigDecimal value) {
if (value == null) {
out.writeNull();
} else {
out.writeSmallString(value.toString());
}
}
@Override
public BigDecimal convertFrom(R in) {
final String str = in.readString();
if (str == null) return null;
return new BigDecimal(str);
}
}
} }

View File

@@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import java.math.BigInteger; import java.math.BigInteger;
import org.redkale.convert.json.*;
/** /**
* BigInteger 的SimpledCoder实现 * BigInteger 的SimpledCoder实现
@@ -47,24 +48,59 @@ public final class BigIntegerSimpledCoder<R extends Reader, W extends Writer> ex
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public static class BigIntegerJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, BigInteger> { public static class BigIntegerJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, BigInteger> {
public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder(); public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final BigInteger value) { public void convertTo(final W out, final BigInteger value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
out.writeString(value.toString()); out.writeSmallString(value.toString());
} }
} }
@Override @Override
public BigInteger convertFrom(Reader in) { public BigInteger convertFrom(R in) {
final String str = in.readString(); final String str = in.readString();
if (str == null) return null; if (str == null) return null;
return new BigInteger(str); return new BigInteger(str);
} }
} }
/**
* BigInteger 的十六进制JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class BigIntegerHexJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, BigInteger> {
public static final BigIntegerHexJsonSimpledCoder instance = new BigIntegerHexJsonSimpledCoder();
@Override
public void convertTo(final W out, final BigInteger value) {
if (value == null) {
out.writeNull();
} else {
String s = value.toString(16);
out.writeSmallString(s.charAt(0) == '-' ? ("-0x" + s.substring(1)) : ("0x" + s));
}
}
@Override
public BigInteger convertFrom(R in) {
final String str = in.readString();
if (str == null) return null;
if (str.length() > 2) {
if (str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) {
return new BigInteger(str.substring(2), 16);
} else if (str.charAt(0) == '-' && str.length() > 3 && str.charAt(1) == '0' && (str.charAt(2) == 'x' || str.charAt(2) == 'X')) {
return new BigInteger("-" + str.substring(3), 16);
}
}
return new BigInteger(str);
}
}
} }

View File

@@ -8,6 +8,7 @@ package org.redkale.convert.ext;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.SimpledCoder; import org.redkale.convert.SimpledCoder;
import org.redkale.convert.json.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
@@ -50,12 +51,12 @@ public final class DLongSimpledCoder<R extends Reader, W extends Writer> extends
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public static class DLongJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, DLong> { public static class DLongJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, DLong> {
public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder(); public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final DLong value) { public void convertTo(final W out, final DLong value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
@@ -64,7 +65,7 @@ public final class DLongSimpledCoder<R extends Reader, W extends Writer> extends
} }
@Override @Override
public DLong convertFrom(Reader in) { public DLong convertFrom(R in) {
final String str = in.readSmallString(); final String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
return DLong.create(Utility.hexToBin(str)); return DLong.create(Utility.hexToBin(str));

View File

@@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import java.net.*; import java.net.*;
import org.redkale.convert.json.*;
import org.redkale.util.StringWrapper; import org.redkale.util.StringWrapper;
/** /**
@@ -87,7 +88,7 @@ public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> e
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public final static class InetAddressJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetAddress> { public final static class InetAddressJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, InetAddress> {
public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder(); public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder();
@@ -119,7 +120,7 @@ public final class InetAddressSimpledCoder<R extends Reader, W extends Writer> e
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public final static class InetSocketAddressJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, InetSocketAddress> { public final static class InetSocketAddressJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, InetSocketAddress> {
public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder(); public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder();

View File

@@ -7,6 +7,7 @@ package org.redkale.convert.ext;
import java.time.*; import java.time.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.json.*;
/** /**
* java.time.Instant 的SimpledCoder实现 * java.time.Instant 的SimpledCoder实现
@@ -33,12 +34,12 @@ public class InstantSimpledCoder<R extends Reader, W extends Writer> extends Sim
return t == -1 ? null : Instant.ofEpochMilli(t); return t == -1 ? null : Instant.ofEpochMilli(t);
} }
public final static class InstantJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, Instant> { public final static class InstantJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, Instant> {
public static final InstantJsonSimpledCoder instance = new InstantJsonSimpledCoder(); public static final InstantJsonSimpledCoder instance = new InstantJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final Instant value) { public void convertTo(final W out, final Instant value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
@@ -47,7 +48,7 @@ public class InstantSimpledCoder<R extends Reader, W extends Writer> extends Sim
} }
@Override @Override
public Instant convertFrom(Reader in) { public Instant convertFrom(R in) {
final String str = in.readSmallString(); final String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
return Instant.parse(str); return Instant.parse(str);

View File

@@ -8,11 +8,14 @@ package org.redkale.convert.ext;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder; import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.json.*;
/** /**
* int 的SimpledCoder实现 * int 的SimpledCoder实现
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
@@ -31,4 +34,38 @@ public final class IntSimpledCoder<R extends Reader, W extends Writer> extends S
return in.readInt(); return in.readInt();
} }
/**
* int 的十六进制JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class IntHexJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, Integer> {
public static final IntHexJsonSimpledCoder instance = new IntHexJsonSimpledCoder();
@Override
public void convertTo(final W out, final Integer value) {
if (value == null) {
out.writeSmallString("0x0");
} else {
if (value < 0) throw new NumberFormatException("Negative values (" + value + ") are not supported");
out.writeSmallString("0x" + Integer.toHexString(value));
}
}
@Override
public Integer convertFrom(R in) {
final String str = in.readString();
if (str == null) return 0;
try {
if (str.length() > 2 && str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) {
return Integer.parseInt(str.substring(2), 16);
}
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return 0;
}
}
}
} }

View File

@@ -7,6 +7,7 @@ package org.redkale.convert.ext;
import java.time.*; import java.time.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.json.*;
/** /**
* java.time.LocalDate 的SimpledCoder实现 * java.time.LocalDate 的SimpledCoder实现
@@ -49,12 +50,12 @@ public final class LocalDateSimpledCoder<R extends Reader, W extends Writer> ext
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public final static class LocalDateJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, LocalDate> { public final static class LocalDateJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, LocalDate> {
public static final LocalDateJsonSimpledCoder instance = new LocalDateJsonSimpledCoder(); public static final LocalDateJsonSimpledCoder instance = new LocalDateJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final LocalDate value) { public void convertTo(final W out, final LocalDate value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
@@ -63,7 +64,7 @@ public final class LocalDateSimpledCoder<R extends Reader, W extends Writer> ext
} }
@Override @Override
public LocalDate convertFrom(Reader in) { public LocalDate convertFrom(R in) {
final String str = in.readSmallString(); final String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
return LocalDate.parse(str); return LocalDate.parse(str);

View File

@@ -7,6 +7,7 @@ package org.redkale.convert.ext;
import java.time.*; import java.time.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.json.*;
/** /**
* java.time.LocalDateTime 的SimpledCoder实现 * java.time.LocalDateTime 的SimpledCoder实现
@@ -62,12 +63,12 @@ public final class LocalDateTimeSimpledCoder<R extends Reader, W extends Writer>
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public final static class LocalDateTimeJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, LocalDateTime> { public final static class LocalDateTimeJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, LocalDateTime> {
public static final LocalDateTimeJsonSimpledCoder instance = new LocalDateTimeJsonSimpledCoder(); public static final LocalDateTimeJsonSimpledCoder instance = new LocalDateTimeJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final LocalDateTime value) { public void convertTo(final W out, final LocalDateTime value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
@@ -76,7 +77,7 @@ public final class LocalDateTimeSimpledCoder<R extends Reader, W extends Writer>
} }
@Override @Override
public LocalDateTime convertFrom(Reader in) { public LocalDateTime convertFrom(R in) {
final String str = in.readSmallString(); final String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
return LocalDateTime.parse(str); return LocalDateTime.parse(str);

View File

@@ -7,6 +7,7 @@ package org.redkale.convert.ext;
import java.time.*; import java.time.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.json.*;
/** /**
* java.time.LocalTime 的SimpledCoder实现 * java.time.LocalTime 的SimpledCoder实现
@@ -47,12 +48,12 @@ public final class LocalTimeSimpledCoder<R extends Reader, W extends Writer> ext
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
*/ */
public final static class LocalTimeJsonSimpledCoder<R extends Reader, W extends Writer> extends SimpledCoder<R, W, LocalTime> { public final static class LocalTimeJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, LocalTime> {
public static final LocalTimeJsonSimpledCoder instance = new LocalTimeJsonSimpledCoder(); public static final LocalTimeJsonSimpledCoder instance = new LocalTimeJsonSimpledCoder();
@Override @Override
public void convertTo(final Writer out, final LocalTime value) { public void convertTo(final W out, final LocalTime value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
} else { } else {
@@ -61,7 +62,7 @@ public final class LocalTimeSimpledCoder<R extends Reader, W extends Writer> ext
} }
@Override @Override
public LocalTime convertFrom(Reader in) { public LocalTime convertFrom(R in) {
final String str = in.readSmallString(); final String str = in.readSmallString();
if (str == null) return null; if (str == null) return null;
return LocalTime.parse(str); return LocalTime.parse(str);

View File

@@ -3,17 +3,19 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.convert.ext; package org.redkale.convert.ext;
import org.redkale.convert.Reader; import org.redkale.convert.Reader;
import org.redkale.convert.SimpledCoder; import org.redkale.convert.SimpledCoder;
import org.redkale.convert.Writer; import org.redkale.convert.Writer;
import org.redkale.convert.json.*;
/** /**
* long 的SimpledCoder实现 * long 的SimpledCoder实现
* *
* <p> 详情见: https://redkale.org * <p>
* 详情见: https://redkale.org
*
* @author zhangjx * @author zhangjx
* @param <R> Reader输入的子类型 * @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型 * @param <W> Writer输出的子类型
@@ -32,4 +34,38 @@ public final class LongSimpledCoder<R extends Reader, W extends Writer> extends
return in.readLong(); return in.readLong();
} }
/**
* long 的十六进制JsonSimpledCoder实现
*
* @param <R> Reader输入的子类型
* @param <W> Writer输出的子类型
*/
public static class LongHexJsonSimpledCoder<R extends JsonReader, W extends JsonWriter> extends SimpledCoder<R, W, Long> {
public static final LongHexJsonSimpledCoder instance = new LongHexJsonSimpledCoder();
@Override
public void convertTo(final W out, final Long value) {
if (value == null) {
out.writeSmallString("0x0");
} else {
if (value < 0) throw new NumberFormatException("Negative values (" + value + ") are not supported");
out.writeSmallString("0x" + Long.toHexString(value));
}
}
@Override
public Long convertFrom(R in) {
final String str = in.readString();
if (str == null) return 0L;
try {
if (str.length() > 2 && str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) {
return Long.parseLong(str.substring(2), 16);
}
return Long.parseLong(str);
} catch (NumberFormatException e) {
return 0L;
}
}
}
} }

View File

@@ -98,21 +98,6 @@ public class JsonByteBufferReader extends JsonReader {
} }
} }
/**
* 读取下一个有效字符
*
* @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;
}
}
/** /**
* 回退最后读取的字符 * 回退最后读取的字符
* *
@@ -130,7 +115,8 @@ public class JsonByteBufferReader extends JsonReader {
*/ */
@Override @Override
public final String readObjectB(final Class clazz) { public final String readObjectB(final Class clazz) {
char ch = nextGoodChar(); this.fieldIndex = 0; //必须要重置为0
char ch = nextGoodChar(true);
if (ch == '{') return ""; 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;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null; if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null;
@@ -155,7 +141,7 @@ public class JsonByteBufferReader extends JsonReader {
*/ */
@Override @Override
public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) { public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) {
char ch = nextGoodChar(); char ch = nextGoodChar(true);
if (ch == '[' || ch == '{') return SIGN_NOLENGTH; 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;
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL; if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL;
@@ -174,7 +160,7 @@ public class JsonByteBufferReader extends JsonReader {
*/ */
@Override @Override
public final void readBlank() { public final void readBlank() {
char ch = nextGoodChar(); char ch = nextGoodChar(true);
if (ch == ':') return; if (ch == ':') return;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(ch); sb.append(ch);
@@ -186,23 +172,6 @@ public class JsonByteBufferReader extends JsonReader {
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")"); throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")");
} }
/**
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
*
* @param startPosition 起始位置
* @param contentLength 内容大小, 不确定的传-1
*
* @return 是否存在
*/
@Override
public boolean hasNext(int startPosition, int contentLength) {
char ch = nextGoodChar();
if (ch == ',') return true;
if (ch == '}' || ch == ']' || ch == 0) return false;
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
return true;
}
/** /**
* 读取小字符串 * 读取小字符串
* *
@@ -210,7 +179,7 @@ public class JsonByteBufferReader extends JsonReader {
*/ */
@Override @Override
public final String readSmallString() { public final String readSmallString() {
char ch = nextGoodChar(); char ch = nextGoodChar(true);
if (ch == 0) return null; if (ch == 0) return null;
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
if (ch == '"' || ch == '\'') { if (ch == '"' || ch == '\'') {
@@ -300,80 +269,6 @@ public class JsonByteBufferReader extends JsonReader {
} }
} }
/**
* 读取一个int值
*
* @return int值
*/
@Override
public final int readInt() {
char firstchar = nextGoodChar();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = nextGoodChar();
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 (quote && 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();
boolean quote = false;
if (firstchar == '"' || firstchar == '\'') {
quote = true;
firstchar = nextGoodChar();
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 (quote && ch <= ' ') {
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
} else {
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
}
}
return negative ? -value : value;
}
/** /**
* 读取字符串, 必须是"或者'包围的字符串值 * 读取字符串, 必须是"或者'包围的字符串值
* *

View File

@@ -263,7 +263,7 @@ public class JsonByteBufferWriter extends JsonWriter {
} }
/** /**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String * <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger、BigDecimal转换的String
* *
* @param quote 是否写入双引号 * @param quote 是否写入双引号
* @param value String值 * @param value String值
@@ -622,6 +622,11 @@ public class JsonByteBufferWriter extends JsonWriter {
@Override @Override
public void writeString(String value) { public void writeString(String value) {
writeString(true, value);
}
@Override
public void writeString(final boolean quote, String value) {
if (value == null) { if (value == null) {
writeNull(); writeNull();
return; return;
@@ -654,7 +659,7 @@ public class JsonByteBufferWriter extends JsonWriter {
expandsize = expand(byteLength); expandsize = expand(byteLength);
if (expandsize == 0) { // 只需要一个buffer if (expandsize == 0) { // 只需要一个buffer
final ByteBuffer buffer = this.buffers[index]; final ByteBuffer buffer = this.buffers[index];
buffer.put((byte) '"'); if (quote) buffer.put((byte) '"');
for (int i = 0; i < chs.length; i++) { for (int i = 0; i < chs.length; i++) {
char c = chs[i]; char c = chs[i];
switch (c) { switch (c) {
@@ -689,7 +694,7 @@ public class JsonByteBufferWriter extends JsonWriter {
break; break;
} }
} }
buffer.put((byte) '"'); if (quote) buffer.put((byte) '"');
return; return;
} }
} }
@@ -711,7 +716,7 @@ public class JsonByteBufferWriter extends JsonWriter {
} }
} }
char[] cs = Utility.charArray(sb); char[] cs = Utility.charArray(sb);
writeTo(expandsize, true, cs, 0, sb.length()); writeTo(expandsize, quote, cs, 0, sb.length());
} }
@Override @Override

View File

@@ -137,7 +137,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
} }
/** /**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String * <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger、BigDecimal转换的String
* *
* @param quote 是否加双引号 * @param quote 是否加双引号
* @param value 非null且不含需要转义的字符的String值 * @param value 非null且不含需要转义的字符的String值
@@ -363,10 +363,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
return this.count; return this.count;
} }
private void writeEscapeLatinString(byte[] value) { private void writeEscapeLatinString(final boolean quote, byte[] value) {
byte[] bytes = expand(value.length * 2 + 2); byte[] bytes = expand(value.length * 2 + 2);
int curr = count; int curr = count;
bytes[curr++] = '"'; if (quote) bytes[curr++] = '"';
for (byte b : value) { for (byte b : value) {
if (b == '"') { if (b == '"') {
bytes[curr++] = '\\'; bytes[curr++] = '\\';
@@ -391,23 +391,28 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
bytes[curr++] = b; bytes[curr++] = b;
} }
} }
bytes[curr++] = '"'; if (quote) bytes[curr++] = '"';
count = curr; count = curr;
} }
@Override @Override
public void writeString(String value) { public void writeString(String value) {
writeString(true, value);
}
@Override
public void writeString(final boolean quote, String value) {
if (value == null) { if (value == null) {
writeNull(); writeNull();
return; return;
} }
if (Utility.isLatin1(value)) { if (Utility.isLatin1(value)) {
writeEscapeLatinString(Utility.latin1ByteArray(value)); writeEscapeLatinString(quote, Utility.latin1ByteArray(value));
return; return;
} }
byte[] bytes = expand(value.length() * 4 + 2); byte[] bytes = expand(value.length() * 4 + 2);
int curr = count; int curr = count;
bytes[curr++] = '"'; if (quote) bytes[curr++] = '"';
int len = value.length(); int len = value.length();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
char ch = value.charAt(i); char ch = value.charAt(i);
@@ -452,7 +457,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
break; break;
} }
} }
bytes[curr++] = '"'; if (quote) bytes[curr++] = '"';
count = curr; count = curr;
} }

View File

@@ -95,7 +95,7 @@ public class JsonCharsWriter extends JsonWriter {
} }
/** /**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String * <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger、BigDecimal转换的String
* *
* @param quote 是否加双引号 * @param quote 是否加双引号
* @param value 非null且不含需要转义的字符的String值 * @param value 非null且不含需要转义的字符的String值
@@ -308,12 +308,17 @@ public class JsonCharsWriter extends JsonWriter {
@Override @Override
public void writeString(String value) { public void writeString(String value) {
writeString(true, value);
}
@Override
public void writeString(final boolean quote, String value) {
if (value == null) { if (value == null) {
writeNull(); writeNull();
return; return;
} }
expand(value.length() * 2 + 2); expand(value.length() * 2 + 2);
content[count++] = '"'; if (quote) content[count++] = '"';
for (char ch : Utility.charArray(value)) { for (char ch : Utility.charArray(value)) {
switch (ch) { switch (ch) {
case '\n': case '\n':
@@ -341,7 +346,7 @@ public class JsonCharsWriter extends JsonWriter {
break; break;
} }
} }
content[count++] = '"'; if (quote) content[count++] = '"';
} }
@Override @Override

View File

@@ -27,6 +27,9 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() { public static final Type TYPE_MAP_STRING_STRING = new TypeToken<java.util.HashMap<String, String>>() {
}.getType(); }.getType();
public static final Type TYPE_LIST_STRING = new TypeToken<java.util.List<String>>() {
}.getType();
public static final Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() { public static final Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() {
}.getType(); }.getType();
@@ -100,6 +103,7 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
return convertFrom(type, new String(bytes, offset, length, StandardCharsets.UTF_8)); return convertFrom(type, new String(bytes, offset, length, StandardCharsets.UTF_8));
} }
@Override
public <T> T convertFrom(final Type type, final String text) { public <T> T convertFrom(final Type type, final String text) {
if (text == null) return null; if (text == null) return null;
return convertFrom(type, Utility.charArray(text)); return convertFrom(type, Utility.charArray(text));
@@ -211,6 +215,24 @@ public class JsonConvert extends TextConvert<JsonReader, JsonWriter> {
return (V) new AnyDecoder(factory).convertFrom(reader); return (V) new AnyDecoder(factory).convertFrom(reader);
} }
//json数据的数组长度必须和types个数相同
public Object[] convertFrom(final Type[] types, final String text) {
if (text == null) return null;
return new JsonMultiArrayDecoder(getFactory(), types).convertFrom(new JsonReader(text));
}
//json数据的数组长度必须和types个数相同
public Object[] convertFrom(final Type[] types, final byte[] bytes) {
if (bytes == null) return null;
return convertFrom(types, new String(bytes, StandardCharsets.UTF_8));
}
//json数据的数组长度必须和types个数相同
public Object[] convertFrom(final Type[] types, final byte[] bytes, final int offset, final int length) {
if (bytes == null) return null;
return convertFrom(types, new String(bytes, offset, length, StandardCharsets.UTF_8));
}
//------------------------------ convertTo ----------------------------------------------------------- //------------------------------ convertTo -----------------------------------------------------------
@Override @Override
public String convertTo(final Object value) { public String convertTo(final Object value) {

View File

@@ -129,7 +129,8 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
if (method.isSynthetic()) continue; if (method.isSynthetic()) continue;
if (method.getName().length() < 3) continue; if (method.getName().length() < 3) continue;
if (method.getName().equals("getClass")) continue; if (method.getName().equals("getClass")) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; if (!(method.getName().startsWith("is") && method.getName().length() > 2)
&& !(method.getName().startsWith("get") && method.getName().length() > 3)) continue;
if (factory.isConvertDisabled(method)) continue; if (factory.isConvertDisabled(method)) continue;
if (method.getParameterTypes().length != 0) continue; if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() == void.class) continue; if (method.getReturnType() == void.class) continue;
@@ -195,7 +196,9 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
Method method = (Method) element; Method method = (Method) element;
if (method == null) return null; if (method == null) return null;
String fname = method.getName(); String fname = method.getName();
if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; if (!(fname.startsWith("is") && fname.length() > 2)
&& !(fname.startsWith("get") && fname.length() > 3)
&& !(fname.startsWith("set") && fname.length() > 3)) return fname;
fname = fname.substring(fname.startsWith("is") ? 2 : 3); fname = fname.substring(fname.startsWith("is") ? 2 : 3);
if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) {
fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1);
@@ -206,6 +209,10 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
} }
protected static JsonDynEncoder generateDyncEncoder(final JsonFactory factory, final Class clazz, final List<AccessibleObject> members) { protected static JsonDynEncoder generateDyncEncoder(final JsonFactory factory, final Class clazz, final List<AccessibleObject> members) {
final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz);
selfObjEncoder.init(factory);
if (selfObjEncoder.getMembers().length != members.size()) return null; //存在ignore等定制配置
final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); final String supDynName = JsonDynEncoder.class.getName().replace('.', '/');
final String valtypeName = clazz.getName().replace('.', '/'); final String valtypeName = clazz.getName().replace('.', '/');
final String writerName = JsonWriter.class.getName().replace('.', '/'); final String writerName = JsonWriter.class.getName().replace('.', '/');
@@ -220,9 +227,11 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz);
Map<String, AccessibleObject> mixedNames0 = null; Map<String, AccessibleObject> mixedNames0 = null;
StringBuilder memberb = new StringBuilder();
for (AccessibleObject element : members) { for (AccessibleObject element : members) {
ConvertColumnEntry ref1 = factory.findRef(clazz, element); ConvertColumnEntry ref1 = factory.findRef(clazz, element);
final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name();
memberb.append(fieldname).append(',');
final Class fieldtype = readGetSetFieldType(element); final Class fieldtype = readGetSetFieldType(element);
if (fieldtype != String.class && !fieldtype.isPrimitive()) { if (fieldtype != String.class && !fieldtype.isPrimitive()) {
if (mixedNames0 == null) mixedNames0 = new HashMap<>(); if (mixedNames0 == null) mixedNames0 = new HashMap<>();
@@ -231,9 +240,8 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
} }
final Map<String, AccessibleObject> mixedNames = mixedNames0; final Map<String, AccessibleObject> mixedNames = mixedNames0;
final ClassLoader loader = Thread.currentThread().getContextClassLoader(); final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_'); final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName()
final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.tiny() + "_" + Utility.md5Hex(memberb.toString()); //tiny必须要加上, 同一个类会有多个字段定制Convert
selfObjEncoder.init(factory);
try { try {
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz;

View File

@@ -7,7 +7,7 @@ package org.redkale.convert.json;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.math.BigInteger; import java.math.*;
import java.net.*; import java.net.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.ext.*; import org.redkale.convert.ext.*;
@@ -24,7 +24,7 @@ import org.redkale.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> { public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkaleconvert.json.tiny", "redkale.convert.tiny", true)); private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", true));
static { static {
instance.register(Serializable.class, instance.loadEncoder(Object.class)); instance.register(Serializable.class, instance.loadEncoder(Object.class));
@@ -40,6 +40,7 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance);
this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance);
this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance); this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance);
this.register(BigDecimal.class, BigDecimalSimpledCoder.BigDecimalJsonSimpledCoder.instance);
this.register(java.time.Instant.class, InstantSimpledCoder.InstantJsonSimpledCoder.instance); this.register(java.time.Instant.class, InstantSimpledCoder.InstantJsonSimpledCoder.instance);
this.register(java.time.LocalDate.class, LocalDateSimpledCoder.LocalDateJsonSimpledCoder.instance); this.register(java.time.LocalDate.class, LocalDateSimpledCoder.LocalDateJsonSimpledCoder.instance);
this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.LocalTimeJsonSimpledCoder.instance); this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.LocalTimeJsonSimpledCoder.instance);
@@ -64,7 +65,7 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
} }
public static JsonFactory create() { public static JsonFactory create() {
return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "convert.tiny", true)); return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", true));
} }
@Override @Override
@@ -77,6 +78,11 @@ public final class JsonFactory extends ConvertFactory<JsonReader, JsonWriter> {
return super.createObjectEncoder(type); return super.createObjectEncoder(type);
} }
@Override
protected <E> Decodeable<JsonReader, E> createMultiImplDecoder(Class[] types) {
return new JsonMultiImplDecoder(this, types);
}
protected boolean tiny() { protected boolean tiny() {
return this.tiny; return this.tiny;
} }

View File

@@ -0,0 +1,62 @@
/*
*/
package org.redkale.convert.json;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.convert.*;
/**
* 数组数据中包含不同Type的反序列化解析器 <br>
* 如: ['aaa',{'name':'hahah'}], 需要两个Type来反序列化(String, Map&#60;String, String&#62;) <br>
* <b>注意: type的个数必须大于或等于结果数组元素个数 此解析器对象不会被缓存,每次都会创建新实例</b>
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.7.0
*/
public class JsonMultiArrayDecoder implements Decodeable<JsonReader, Object[]> {
protected final JsonFactory factory;
protected final Type[] types;
protected final Decodeable[] decoders;
public JsonMultiArrayDecoder(final JsonFactory factory, final Type[] types) {
this.factory = factory;
this.types = types;
this.decoders = new Decodeable[types.length];
for (int i = 0; i < types.length; i++) {
this.decoders[i] = factory.loadDecoder(types[i]);
}
}
@Override
public Object[] convertFrom(JsonReader in) {
return convertFrom(in, null);
}
public Object[] convertFrom(JsonReader in, DeMember member) {
int len = in.readArrayB(member, null, null);
if (len == Reader.SIGN_NULL) return null;
//len must be Reader.SIGN_NOLENGTH
final List<Object> result = new ArrayList();
int startPosition = in.position();
int index = -1;
final Decodeable[] coders = this.decoders;
while (in.hasNext(startPosition, -1)) {
result.add(coders[++index % coders.length].convertFrom(in));
}
in.readArrayE();
return result.toArray(new Object[result.size()]);
}
@Override
public Type getType() {
return Object[].class;
}
}

View File

@@ -0,0 +1,181 @@
/*
*/
package org.redkale.convert.json;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.convert.*;
import org.redkale.util.*;
/**
* 抽象或接口类存在多种实现类的反序列化解析器 <br>
*
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> 泛型
*
* @since 2.7.0
*/
public class JsonMultiImplDecoder<T> implements Decodeable<JsonReader, T> {
protected final JsonFactory factory;
protected final Class[] types;
protected final ObjectDecoder[] decoders;
protected final int maxMemberCount;
protected final ObjectDecoder firstDecoder;
protected final Map<String, ObjectDecoder> repeatFieldToDecoders = new HashMap<>();
protected final Map<String, ObjectDecoder> uniqueFieldToDecoders = new HashMap<>();
public JsonMultiImplDecoder(final JsonFactory factory, final Class[] types) {
this.factory = factory;
this.types = types;
this.decoders = new ObjectDecoder[types.length];
int max = 0;
Set<String>[] fields = new Set[types.length];
Set<String>[] movsets = new Set[types.length];
Map<String, Attribute> fieldTypes = new HashMap<>();
for (int i = 0; i < types.length; i++) {
movsets[i] = new HashSet();
fields[i] = new HashSet<>();
ObjectDecoder decoder = (ObjectDecoder) factory.loadDecoder(types[i]);
if (decoder.getMembers().length > max) {
max = decoder.getMembers().length;
}
for (DeMember member : decoder.getMembers()) {
String name = member.getAttribute().field();
this.repeatFieldToDecoders.put(name, decoder);
fields[i].add(name);
Attribute t = fieldTypes.get(name);
if (t == null) {
fieldTypes.put(name, member.getAttribute());
} else if (!member.getAttribute().genericType().equals(t.genericType())) {
throw new RuntimeException("Field(" + name + ")'s Type is not same in " + member.getAttribute().declaringClass() + " and " + t.declaringClass());
}
}
this.decoders[i] = decoder;
}
this.maxMemberCount = max;
for (int i = 0; i < fields.length; i++) {
Set<String> removes = movsets[i];
for (String s : fields[i]) {
boolean repeat = false;
for (int j = 0; j < fields.length; j++) {
if (j == i) continue;
if (fields[j].contains(s)) {
repeat = true;
break;
}
}
if (repeat) removes.add(s);
}
}
int min = max + 1;
ObjectDecoder first = null; //字段最少的类作为默认反解析器
for (int i = 0; i < fields.length; i++) {
Set<String> fieldSet = fields[i];
for (String s : movsets[i]) {
fieldSet.remove(s); //移除重复的字段
}
if (fieldSet.size() < min) {
first = this.decoders[i];
min = fieldSet.size();
}
for (String s : fieldSet) {
this.uniqueFieldToDecoders.put(s, this.decoders[i]);
this.repeatFieldToDecoders.remove(s);
}
}
this.firstDecoder = first;
}
@Override
public T convertFrom(JsonReader in) {
final String clazz = in.readObjectB(null);
if (clazz == null) return null;
ObjectDecoder decoder = this.firstDecoder;
Map<String, ObjectDecoder> uniques = this.uniqueFieldToDecoders;
Map<String, ObjectDecoder> repeats = this.repeatFieldToDecoders;
int index = -1;
boolean finaled = false;
final Object[][] params = new Object[this.maxMemberCount][2];
while (in.hasNext()) {
String fieldName = in.readFieldName();
DeMember member = decoder.getMember(fieldName);
//new Set[]{Utility.ofSet("1", "2", "3"), Utility.ofSet("2", "3"), Utility.ofSet("4", "2", "3"), Utility.ofSet("6", "7", "8"), Utility.ofSet("6", "9")};
if (member == null && !finaled) {
ObjectDecoder de = uniques.get(fieldName);
if (de == null) {
de = repeats.get(fieldName);
if (de != null) {
decoder = de;
member = de.getMember(fieldName);
for (int i = 0; i <= index; i++) { //迁移params中的DeMember.Attribute
if (params[i] != null) {
DeMember dm = de.getMember(((Attribute) params[i][0]).field());
params[i][0] = dm == null ? null : dm.getAttribute();
}
}
}
} else {
finaled = true;
decoder = de;
member = de.getMember(fieldName);
for (int i = 0; i <= index; i++) { //迁移params中的DeMember.Attribute
if (params[i] != null) {
DeMember dm = de.getMember(((Attribute) params[i][0]).field());
params[i][0] = dm == null ? null : dm.getAttribute();
}
}
}
}
in.readBlank();
if (member == null) {
in.skipValue(); //跳过不存在的属性的值
} else {
params[++index] = new Object[]{member.getAttribute(), member.read(in)};
}
}
in.readObjectE(null);
if (decoder.getConstructorMembers() == null) { //空构造函数
T result = (T) decoder.getCreator().create();
for (int i = 0; i <= index; i++) {
((Attribute) params[i][0]).set(result, params[i][1]);
}
return result;
} else {
final DeMember[] constructorFields = decoder.getConstructorMembers();
final Object[] constructorParams = new Object[constructorFields.length];
for (int i = 0; i < constructorFields.length; i++) {
for (int j = 0; j < params.length; j++) {
if (params[j] != null && params[j][0] != null
&& constructorFields[i].getAttribute().field().equals(((Attribute) params[j][0]).field())) {
constructorParams[i] = params[j][1];
params[j] = null;
break;
}
}
}
final T result = (T) decoder.getCreator().create(constructorParams);
for (int i = 0; i < params.length; i++) {
if (params[i] != null && params[i][0] != null) {
((Attribute) params[i][0]).set(result, params[i][1]);
}
}
return result;
}
}
@Override
public Type getType() {
return Object.class;
}
}

View File

@@ -5,6 +5,7 @@
*/ */
package org.redkale.convert.json; package org.redkale.convert.json;
import java.util.Map;
import org.redkale.convert.*; import org.redkale.convert.*;
import static org.redkale.convert.Reader.*; import static org.redkale.convert.Reader.*;
import org.redkale.util.*; import org.redkale.util.*;
@@ -76,7 +77,7 @@ public class JsonReader extends Reader {
public final void seek(String key) { public final void seek(String key) {
if (key == null || key.length() < 1) return; if (key == null || key.length() < 1) return;
final String[] keys = key.split("\\."); final String[] keys = key.split("\\.");
nextGoodChar(); //读掉 { [ nextGoodChar(true); //读掉 { [
for (String key1 : keys) { for (String key1 : keys) {
while (this.hasNext()) { while (this.hasNext()) {
String field = this.readSmallString(); String field = this.readSmallString();
@@ -93,7 +94,7 @@ public class JsonReader extends Reader {
*/ */
@Override @Override
public final void skipValue() { public final void skipValue() {
final char ch = nextGoodChar(); final char ch = nextGoodChar(true);
switch (ch) { switch (ch) {
case '"': case '"':
case '\'': case '\'':
@@ -131,20 +132,46 @@ public class JsonReader extends Reader {
* @return 空白字符或有效字符 * @return 空白字符或有效字符
*/ */
protected char nextChar() { protected char nextChar() {
return this.text[++this.position]; int p = ++this.position;
if (p >= text.length) return 0;
return this.text[p];
} }
/** /**
* 跳过空白字符, 返回一个非空白字符 * 跳过空白字符、单行或多行注释 返回一个非空白字符
*
* @param allowComment 是否容许含注释
* *
* @return 有效字符 * @return 有效字符
*/ */
protected char nextGoodChar() { protected char nextGoodChar(boolean allowComment) {
char c = nextChar(); char c;
if (c > ' ') return c;
for (;;) { for (;;) {
c = nextChar(); c = nextChar();
if (c > ' ') return c; if (c == 0) return c;// 0 表示buffer结尾了
if (c > ' ') {
if (allowComment && c == '/') { //支持单行和多行注释
char n = nextChar();
if (n == '/') {
for (;;) {
if (nextChar() == '\n') break;
}
return nextGoodChar(allowComment);
} else if (n == '*') {
char nc;
char lc = 0;
for (;;) {
nc = nextChar();
if (nc == '/' && lc == '*') break;
lc = nc;
}
return nextGoodChar(allowComment);
} else {
throw new ConvertException("illegal escape(" + n + ") (position = " + this.position + ") in '" + new String(text) + "'");
}
}
return c;
}
} }
} }
@@ -157,9 +184,31 @@ public class JsonReader extends Reader {
this.position--; this.position--;
} }
/**
* 是否{开头的对象字符
*
* @return 是否对象字符
*/
public boolean isNextObject() {
char ch = nextGoodChar(true);
backChar(ch);
return ch == '{';
}
/**
* 是否[开头的数组字符
*
* @return 是否数组字符
*/
public boolean isNextArray() {
char ch = nextGoodChar(true);
backChar(ch);
return ch == '[';
}
@Override @Override
public final ValueType readType() { public final ValueType readType() {
char ch = nextGoodChar(); char ch = nextGoodChar(true);
if (ch == '{') { if (ch == '{') {
backChar(ch); backChar(ch);
return ValueType.MAP; return ValueType.MAP;
@@ -183,15 +232,8 @@ public class JsonReader extends Reader {
public String readObjectB(final Class clazz) { public String readObjectB(final Class clazz) {
this.fieldIndex = 0; //必须要重置为0 this.fieldIndex = 0; //必须要重置为0
if (this.text.length == 0) return null; if (this.text.length == 0) return null;
char ch = this.text[++this.position]; char ch = nextGoodChar(true);
if (ch == '{') return ""; 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;
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) + ")"); throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")");
@@ -232,17 +274,9 @@ public class JsonReader extends Reader {
@Override @Override
public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) {
if (this.text.length == 0) return SIGN_NULL; if (this.text.length == 0) return SIGN_NULL;
char ch = this.text[++this.position]; char ch = nextGoodChar(true);
if (ch == '[') return SIGN_NOLENGTH; if (ch == '[') return SIGN_NOLENGTH;
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;
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) + ")"); throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")");
@@ -257,15 +291,8 @@ public class JsonReader extends Reader {
*/ */
@Override @Override
public void readBlank() { public void readBlank() {
char ch = this.text[++this.position]; char ch = nextGoodChar(true);
if (ch == ':') return; 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) + ")"); throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")");
} }
@@ -289,17 +316,14 @@ public class JsonReader extends Reader {
*/ */
@Override @Override
public boolean hasNext(int startPosition, int contentLength) { public boolean hasNext(int startPosition, int contentLength) {
char ch = this.text[++this.position]; char ch = nextGoodChar(true);
if (ch == ',') return true; if (ch == ',') {
if (ch == '}' || ch == ']') return false; char nt = nextGoodChar(true);
if (ch <= ' ') { if (nt == '}' || nt == ']') return false;
for (;;) { this.position--;
ch = this.text[++this.position]; return true;
if (ch > ' ') break;
}
if (ch == ',') return true;
if (ch == '}' || ch == ']') return false;
} }
if (ch == '}' || ch == ']') return false;
this.position--; // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取 this.position--; // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
return true; return true;
} }
@@ -313,15 +337,9 @@ public class JsonReader extends Reader {
public String readSmallString() { public String readSmallString() {
final int eof = this.limit; final int eof = this.limit;
if (this.position == eof) return null; if (this.position == eof) return null;
char ch = nextGoodChar(true); //需要跳过注释
final char[] text0 = this.text; final char[] text0 = this.text;
int currpos = this.position; int currpos = this.position;
char ch = text0[++currpos];
if (ch <= ' ') {
for (;;) {
ch = text0[++currpos];
if (ch > ' ') break;
}
}
if (ch == '"' || ch == '\'') { if (ch == '"' || ch == '\'') {
final char quote = ch; final char quote = ch;
final int start = currpos + 1; final int start = currpos + 1;
@@ -363,55 +381,84 @@ public class JsonReader extends Reader {
*/ */
@Override @Override
public int readInt() { public int readInt() {
final char[] text0 = this.text; char firstchar = nextGoodChar(true);
final int eof = this.limit;
int currpos = this.position;
char firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
boolean quote = false; boolean quote = false;
if (firstchar == '"' || firstchar == '\'') { if (firstchar == '"' || firstchar == '\'') {
quote = true; quote = true;
firstchar = text0[++currpos]; firstchar = nextGoodChar(false);
if (firstchar <= ' ') { if (firstchar == '"' || firstchar == '\'') return 0;
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0;
}
} }
int value = 0; int value = 0;
final boolean negative = firstchar == '-'; final boolean negative = firstchar == '-';
if (!negative) { if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); if (firstchar == '+') firstchar = nextChar(); //兼容+开头的
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
value = firstchar - '0'; value = firstchar - '0';
} }
if (firstchar == 'N') {
if (negative) throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
char c = nextChar();
if (c != 'a') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'N') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
if (quote) {
c = nextChar();
if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
}
return 0; //NaN 返回0;
} else if (firstchar == 'I') { //Infinity
char c = nextChar();
if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'f') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 't') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'y') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
if (quote) {
c = nextChar();
if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
}
return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
boolean hex = false;
boolean dot = false; boolean dot = false;
for (;;) { for (;;) {
if (currpos == eof) break; char ch = nextChar();
char ch = text0[++currpos]; if (ch == 0) break;
int val = digits[ch]; if (ch >= '0' && ch <= '9') {
if (quote && val == -3) continue; if (dot) continue;
if (val <= -3) break; value = (hex ? (value << 4) : ((value << 3) + (value << 1))) + digits[ch];
if (dot) continue; } else if (ch == '"' || ch == '\'') {
if (val == -1) { if (quote) break;
if (ch == '.') { throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
dot = true; } else if (ch == 'x' || ch == 'X') {
continue; if (value != 0) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
} hex = true;
throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); } else if (ch >= 'a' && ch <= 'f') {
if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
if (dot) continue;
value = (value << 4) + digits[ch];
} else if (ch >= 'A' && ch <= 'F') {
if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
if (dot) continue;
value = (value << 4) + digits[ch];
} else if (quote && ch <= ' ') {
} else if (ch == '.') {
dot = true;
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
} else {
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
} }
if (val != -2) value = value * 10 + val;
} }
this.position = currpos - 1;
return negative ? -value : value; return negative ? -value : value;
} }
@@ -422,72 +469,105 @@ public class JsonReader extends Reader {
*/ */
@Override @Override
public long readLong() { public long readLong() {
final char[] text0 = this.text; char firstchar = nextGoodChar(true);
final int eof = this.limit;
int currpos = this.position;
char firstchar = text0[++currpos];
if (firstchar <= ' ') {
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
boolean quote = false; boolean quote = false;
if (firstchar == '"' || firstchar == '\'') { if (firstchar == '"' || firstchar == '\'') {
quote = true; quote = true;
firstchar = text0[++currpos]; firstchar = nextGoodChar(false);
if (firstchar <= ' ') { if (firstchar == '"' || firstchar == '\'') return 0L;
for (;;) {
firstchar = text0[++currpos];
if (firstchar > ' ') break;
}
}
if (firstchar == '"' || firstchar == '\'') {
this.position = currpos;
return 0L;
}
} }
long value = 0; long value = 0;
final boolean negative = firstchar == '-'; final boolean negative = firstchar == '-';
if (!negative) { if (!negative) {
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); if (firstchar == '+') firstchar = nextChar(); //兼容+开头的
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
value = firstchar - '0'; value = firstchar - '0';
} }
if (firstchar == 'N') {
if (negative) throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
char c = nextChar();
if (c != 'a') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'N') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
if (quote) {
c = nextChar();
if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
}
return 0L; //NaN 返回0;
} else if (firstchar == 'I') { //Infinity
char c = nextChar();
if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'f') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 't') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
c = nextChar();
if (c != 'y') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
if (quote) {
c = nextChar();
if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")");
}
return negative ? Long.MIN_VALUE : Long.MAX_VALUE;
}
boolean hex = false;
boolean dot = false; boolean dot = false;
for (;;) { for (;;) {
if (currpos == eof) break; char ch = nextChar();
char ch = text0[++currpos]; if (ch == 0) break;
int val = digits[ch]; if (ch >= '0' && ch <= '9') {
if (quote && val == -3) continue; if (dot) continue;
if (val <= -3) break; value = (hex ? (value << 4) : ((value << 3) + (value << 1))) + digits[ch];
if (dot) continue; } else if (ch == '"' || ch == '\'') {
if (val == -1) { if (quote) break;
if (ch == '.') { throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
dot = true; } else if (ch == 'x' || ch == 'X') {
continue; if (value != 0) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
} hex = true;
throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); } else if (ch >= 'a' && ch <= 'f') {
if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
if (dot) continue;
value = (value << 4) + digits[ch];
} else if (ch >= 'A' && ch <= 'F') {
if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
if (dot) continue;
value = (value << 4) + digits[ch];
} else if (quote && ch <= ' ') {
} else if (ch == '.') {
dot = true;
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
backChar(ch);
break;
} else {
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
} }
if (val != -2) value = value * 10 + val;
} }
this.position = currpos - 1;
return negative ? -value : value; return negative ? -value : value;
} }
public final String readFieldName() {
return this.readSmallString();
}
@Override @Override
public final DeMember readFieldName(final DeMember[] members) { public final DeMember readFieldName(final DeMember[] members, Map<String, DeMember> memberFieldMap, Map<Integer, DeMember> memberTagMap) {
final String exceptedfield = this.readSmallString(); final String exceptedField = this.readSmallString();
if (exceptedfield == null) return null; if (exceptedField == null) return null;
final int len = members.length; final int len = members.length;
if (this.fieldIndex >= len) this.fieldIndex = 0; if (this.fieldIndex >= len) this.fieldIndex = 0;
for (int k = this.fieldIndex; k < len; k++) { for (int k = this.fieldIndex; k < len; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) { if (exceptedField.equals(members[k].getAttribute().field())) {
this.fieldIndex = k; this.fieldIndex = k;
return members[k]; return members[k];
} }
} }
for (int k = 0; k < this.fieldIndex; k++) { for (int k = 0; k < this.fieldIndex; k++) {
if (exceptedfield.equals(members[k].getAttribute().field())) { if (exceptedField.equals(members[k].getAttribute().field())) {
this.fieldIndex = k; this.fieldIndex = k;
return members[k]; return members[k];
} }
@@ -557,7 +637,11 @@ public class JsonReader extends Reader {
String chars = readSmallString(); String chars = readSmallString();
if (chars != null) chars = chars.trim(); if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.f; if (chars == null || chars.isEmpty()) return 0.f;
return Float.parseFloat(chars); switch (chars) {
case "Infinity": return (float) Double.POSITIVE_INFINITY;
case "-Infinity": return (float) Double.NEGATIVE_INFINITY;
default: return Float.parseFloat(chars); //Float.parseFloat能识别NaN
}
} }
@Override @Override
@@ -565,7 +649,11 @@ public class JsonReader extends Reader {
String chars = readSmallString(); String chars = readSmallString();
if (chars != null) chars = chars.trim(); if (chars != null) chars = chars.trim();
if (chars == null || chars.isEmpty()) return 0.0; if (chars == null || chars.isEmpty()) return 0.0;
return Double.parseDouble(chars); switch (chars) {
case "Infinity": return Double.POSITIVE_INFINITY;
case "-Infinity": return Double.NEGATIVE_INFINITY;
default: return Double.parseDouble(chars); //Double.parseDouble能识别NaN
}
} }
/** /**
@@ -576,14 +664,8 @@ public class JsonReader extends Reader {
@Override @Override
public String readString() { public String readString() {
final char[] text0 = this.text; final char[] text0 = this.text;
char expected = nextGoodChar(true);
int currpos = this.position; int currpos = this.position;
char expected = text0[++currpos];
if (expected <= ' ') {
for (;;) {
expected = text0[++currpos];
if (expected > ' ') break;
}
}
if (expected != '"' && expected != '\'') { if (expected != '"' && expected != '\'') {
if (expected == 'n' && text0.length > currpos + 3 && (text0[1 + currpos] == 'u' && text0[2 + currpos] == 'l' && text0[3 + currpos] == 'l')) { if (expected == 'n' && text0.length > currpos + 3 && (text0[1 + currpos] == 'u' && text0[2 + currpos] == 'l' && text0[3 + currpos] == 'l')) {
if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') { if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') {

View File

@@ -88,7 +88,7 @@ class JsonStreamWriter extends JsonByteBufferWriter {
} }
/** /**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String * <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger、BigDecimal转换的String
* *
* @param quote 是否写入双引号 * @param quote 是否写入双引号
* @param value String值 * @param value String值

View File

@@ -21,7 +21,7 @@ public abstract class JsonWriter extends Writer {
protected static final int defaultSize = Integer.getInteger("redkale.convert.json.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); protected static final int defaultSize = Integer.getInteger("redkale.convert.json.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024));
protected boolean tiny; protected boolean tiny = JsonFactory.root().tiny();
@Override @Override
public boolean tiny() { public boolean tiny() {
@@ -47,7 +47,7 @@ public abstract class JsonWriter extends Writer {
public abstract void writeTo(final byte[] chs, final int start, final int len); //只能是 0 - 127 的字符 public abstract void writeTo(final byte[] chs, final int start, final int len); //只能是 0 - 127 的字符
/** /**
* <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger转换的String * <b>注意:</b> 该String值不能为null且不会进行转义 只用于不含需要转义字符的字符串例如enum、double、BigInteger、BigDecimal转换的String
* *
* @param quote 是否加双引号 * @param quote 是否加双引号
* @param value 非null且不含需要转义的字符的String值 * @param value 非null且不含需要转义的字符的String值
@@ -85,6 +85,8 @@ public abstract class JsonWriter extends Writer {
@Override @Override
public abstract void writeLong(long value); public abstract void writeLong(long value);
public abstract void writeString(final boolean quote, String value);
@Override @Override
public abstract void writeString(String value); public abstract void writeString(String value);
@@ -156,7 +158,7 @@ public abstract class JsonWriter extends Writer {
@Override @Override
public final void writeWrapper(StringWrapper value) { public final void writeWrapper(StringWrapper value) {
writeLatin1To(false, String.valueOf(value)); writeString(false, String.valueOf(value));
} }
@Override @Override

View File

@@ -94,7 +94,7 @@ public class HttpMessageClusterClient extends HttpMessageClient {
} }
final Map<String, String> clientHeaders = new LinkedHashMap<>(); final Map<String, String> clientHeaders = new LinkedHashMap<>();
byte[] clientBody = null; byte[] clientBody = null;
if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC, "true");
if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true");
if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString());
if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString());
@@ -148,7 +148,7 @@ public class HttpMessageClusterClient extends HttpMessageClient {
} }
final Map<String, String> clientHeaders = new LinkedHashMap<>(); final Map<String, String> clientHeaders = new LinkedHashMap<>();
byte[] clientBody = null; byte[] clientBody = null;
if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC, "true");
if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true");
if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString());
if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString());

View File

@@ -16,6 +16,7 @@ import org.redkale.boot.*;
import org.redkale.convert.*; import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.util.Traces;
/** /**
* 没有配置MQ且也没有ClusterAgent的情况下实现的默认HttpMessageClient实例 * 没有配置MQ且也没有ClusterAgent的情况下实现的默认HttpMessageClient实例
@@ -100,8 +101,9 @@ public class HttpMessageLocalClient extends HttpMessageClient {
future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); future.completeExceptionally(new RuntimeException("404 Not Found " + topic));
return future; return future;
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, future); HttpResponse resp = new HttpMessageLocalResponse(req, future);
Traces.createTraceid();
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
@@ -117,9 +119,10 @@ public class HttpMessageLocalClient extends HttpMessageClient {
if (fine) logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet"); if (fine) logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet");
return CompletableFuture.completedFuture(new HttpResult().status(404)); return CompletableFuture.completedFuture(new HttpResult().status(404));
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
CompletableFuture future = new CompletableFuture(); CompletableFuture future = new CompletableFuture();
HttpResponse resp = new HttpMessageLocalResponse(req, future); HttpResponse resp = new HttpMessageLocalResponse(req, future);
Traces.createTraceid();
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
@@ -144,8 +147,9 @@ public class HttpMessageLocalClient extends HttpMessageClient {
if (fine) logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet"); if (fine) logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet");
return; return;
} }
HttpRequest req = new HttpMessageLocalRequest(context(), request); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, null); HttpResponse resp = new HttpMessageLocalResponse(req, null);
Traces.createTraceid();
try { try {
servlet.execute(req, resp); servlet.execute(req, resp);
} catch (Exception e) { } catch (Exception e) {
@@ -156,8 +160,9 @@ public class HttpMessageLocalClient extends HttpMessageClient {
@Override @Override
public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) {
HttpPrepareServlet ps = prepareServlet(); HttpPrepareServlet ps = prepareServlet();
HttpRequest req = new HttpMessageLocalRequest(context(), request); HttpRequest req = new HttpMessageLocalRequest(context(), request, userid);
HttpResponse resp = new HttpMessageLocalResponse(req, null); HttpResponse resp = new HttpMessageLocalResponse(req, null);
Traces.createTraceid();
ps.filterServletsByMmcTopic(topic).forEach(s -> { ps.filterServletsByMmcTopic(topic).forEach(s -> {
try { try {
s.execute(req, resp); s.execute(req, resp);
@@ -169,8 +174,9 @@ public class HttpMessageLocalClient extends HttpMessageClient {
public static class HttpMessageLocalRequest extends HttpRequest { public static class HttpMessageLocalRequest extends HttpRequest {
public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req) { public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req, Serializable userid) {
super(context, req); super(context, req);
if (userid != null) this.currentUserid = userid;
} }
} }
@@ -218,7 +224,17 @@ public class HttpMessageLocalClient extends HttpMessageClient {
@Override @Override
public void finish(final Convert convert, final Type type, Object obj) { public void finish(final Convert convert, final Type type, Object obj) {
if (future == null) return; if (future == null) return;
future.complete(obj); if (obj instanceof CompletableFuture) {
((CompletableFuture) obj).whenComplete((r, t) -> {
if (t == null) {
future.complete(r);
} else {
future.completeExceptionally((Throwable) t);
}
});
} else {
future.complete(obj);
}
} }
@Override @Override

View File

@@ -43,11 +43,11 @@ public class HttpMessageProcessor implements MessageProcessor {
protected final HttpServlet servlet; protected final HttpServlet servlet;
protected final boolean multiconsumer; protected final boolean multiConsumer;
protected final String restmodule; // 前后有/, 例如: /user/ protected final String restModule; // 前后有/, 例如: /user/
protected final String multimodule; // 前后有/, 例如: /userstat/ protected final String multiModule; // 前后有/, 例如: /userstat/
protected ThreadLocal<ObjectPool<HttpMessageResponse>> respPoolThreadLocal; protected ThreadLocal<ObjectPool<HttpMessageResponse>> respPoolThreadLocal;
@@ -57,7 +57,7 @@ public class HttpMessageProcessor implements MessageProcessor {
protected CountDownLatch cdl; protected CountDownLatch cdl;
protected long starttime; protected long startTime;
protected final Runnable innerCallback = () -> { protected final Runnable innerCallback = () -> {
if (cdl != null) cdl.countDown(); if (cdl != null) cdl.countDown();
@@ -74,9 +74,9 @@ public class HttpMessageProcessor implements MessageProcessor {
this.service = service; this.service = service;
this.servlet = servlet; this.servlet = servlet;
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
this.multiconsumer = mmc != null; this.multiConsumer = mmc != null;
this.restmodule = "/" + Rest.getRestModule(service) + "/"; this.restModule = "/" + Rest.getRestModule(service) + "/";
this.multimodule = mmc != null ? ("/" + mmc.module() + "/") : null; this.multiModule = mmc != null ? ("/" + mmc.module() + "/") : null;
this.respSupplier = () -> respPoolThreadLocal.get().get(); this.respSupplier = () -> respPoolThreadLocal.get().get();
this.respConsumer = resp -> respPoolThreadLocal.get().accept(resp); this.respConsumer = resp -> respPoolThreadLocal.get().accept(resp);
this.respPoolThreadLocal = ThreadLocal.withInitial(() -> ObjectPool.createUnsafePool(Utility.cpus(), this.respPoolThreadLocal = ThreadLocal.withInitial(() -> ObjectPool.createUnsafePool(Utility.cpus(),
@@ -85,7 +85,7 @@ public class HttpMessageProcessor implements MessageProcessor {
@Override @Override
public void begin(final int size, long starttime) { public void begin(final int size, long starttime) {
this.starttime = starttime; this.startTime = starttime;
this.cdl = size > 1 ? new CountDownLatch(size) : null; this.cdl = size > 1 ? new CountDownLatch(size) : null;
} }
@@ -97,15 +97,16 @@ public class HttpMessageProcessor implements MessageProcessor {
private void execute(final MessageRecord message, final Runnable callback) { private void execute(final MessageRecord message, final Runnable callback) {
HttpMessageRequest request = null; HttpMessageRequest request = null;
try { try {
Traces.currTraceid(message.getTraceid());
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long cha = now - message.createtime; long cha = now - message.createTime;
long e = now - starttime; long e = now - startTime;
if (multiconsumer) message.setResptopic(null); //不容许有响应 if (multiConsumer) message.setRespTopic(null); //不容许有响应
HttpMessageResponse response = respSupplier.get(); HttpMessageResponse response = respSupplier.get();
request = response.request(); request = response.request();
response.prepare(message, callback, producers.getProducer(message)); response.prepare(message, callback, producers.getProducer(message));
if (multiconsumer) request.setRequestURI(request.getRequestURI().replaceFirst(this.multimodule, this.restmodule)); if (multiConsumer) request.setRequestURI(request.getRequestURI().replaceFirst(this.multiModule, this.restModule));
server.getHttpServer().getContext().execute(servlet, request, response); server.getHttpServer().getContext().execute(servlet, request, response);
long o = System.currentTimeMillis() - now; long o = System.currentTimeMillis() - now;
@@ -117,9 +118,9 @@ public class HttpMessageProcessor implements MessageProcessor {
logger.log(Level.FINEST, "HttpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message); logger.log(Level.FINEST, "HttpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message);
} }
} catch (Throwable ex) { } catch (Throwable ex) {
if (message.getResptopic() != null && !message.getResptopic().isEmpty()) { if (message.getRespTopic() != null && !message.getRespTopic().isEmpty()) {
HttpMessageResponse.finishHttpResult(finest, request == null ? null : request.getRespConvert(), HttpMessageResponse.finishHttpResult(finest, request == null ? null : request.getRespConvert(),
null, message, callback, messageClient, producers.getProducer(message), message.getResptopic(), new HttpResult().status(500)); null, message, callback, messageClient, producers.getProducer(message), message.getRespTopic(), new HttpResult().status(500));
} }
logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex); logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex);
} }
@@ -131,7 +132,7 @@ public class HttpMessageProcessor implements MessageProcessor {
try { try {
this.cdl.await(30, TimeUnit.SECONDS); this.cdl.await(30, TimeUnit.SECONDS);
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restmodule, ex); logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restModule, ex);
} }
this.cdl = null; this.cdl = null;
} }

View File

@@ -30,7 +30,7 @@ public class HttpMessageRequest extends HttpRequest {
this.message = message; this.message = message;
this.hashid = this.message.hash(); this.hashid = this.message.hash();
this.currentUserid = message.getUserid(); this.currentUserid = message.getUserid();
this.createtime = System.currentTimeMillis(); this.createTime = System.currentTimeMillis();
return this; return this;
} }

View File

@@ -69,11 +69,11 @@ public class HttpMessageResponse extends HttpResponse {
} }
public void finishHttpResult(Type type, HttpResult result) { public void finishHttpResult(Type type, HttpResult result) {
finishHttpResult(this.finest, ((HttpMessageRequest) this.request).getRespConvert(), type, this.message, this.callback, this.messageClient, this.producer, message.getResptopic(), result); finishHttpResult(this.finest, ((HttpMessageRequest) this.request).getRespConvert(), type, this.message, this.callback, this.messageClient, this.producer, message.getRespTopic(), result);
} }
public void finishHttpResult(Type type, Convert respConvert, HttpResult result) { public void finishHttpResult(Type type, Convert respConvert, HttpResult result) {
finishHttpResult(this.finest, respConvert == null ? ((HttpMessageRequest) this.request).getRespConvert() : respConvert, type, this.message, this.callback, this.messageClient, this.producer, message.getResptopic(), result); finishHttpResult(this.finest, respConvert == null ? ((HttpMessageRequest) this.request).getRespConvert() : respConvert, type, this.message, this.callback, this.messageClient, this.producer, message.getRespTopic(), result);
} }
public static void finishHttpResult(boolean finest, Convert respConvert, Type type, MessageRecord msg, Runnable callback, MessageClient messageClient, MessageProducer producer, String resptopic, HttpResult result) { public static void finishHttpResult(boolean finest, Convert respConvert, Type type, MessageRecord msg, Runnable callback, MessageClient messageClient, MessageProducer producer, String resptopic, HttpResult result) {
@@ -120,7 +120,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finishJson(final JsonConvert convert, final Object obj) { public void finishJson(final JsonConvert convert, final Object obj) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -130,7 +130,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finishJson(final Type type, final Object obj) { public void finishJson(final Type type, final Object obj) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -139,7 +139,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finishJson(final JsonConvert convert, final Type type, final Object obj) { public void finishJson(final JsonConvert convert, final Type type, final Object obj) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -148,7 +148,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(Type type, org.redkale.service.RetResult ret) { public void finish(Type type, org.redkale.service.RetResult ret) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -158,7 +158,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) { public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -167,7 +167,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(final Convert convert, final Type type, Object obj) { public void finish(final Convert convert, final Type type, Object obj) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -176,7 +176,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(String obj) { public void finish(String obj) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -210,7 +210,7 @@ public class HttpMessageResponse extends HttpResponse {
} else if (finest) { } else if (finest) {
producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status); producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status);
} }
if (this.message.isEmptyResptopic()) { if (this.message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -219,7 +219,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(final Convert convert, Type type, HttpResult result) { public void finish(final Convert convert, Type type, HttpResult result) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -229,7 +229,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(boolean kill, final byte[] bs, int offset, int length) { public void finish(boolean kill, final byte[] bs, int offset, int length) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -242,7 +242,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -252,7 +252,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
protected <A> void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length, Consumer<A> consumer, A attachment) { protected <A> void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length, Consumer<A> consumer, A attachment) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -262,7 +262,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(boolean kill, ByteBuffer buffer) { public void finish(boolean kill, ByteBuffer buffer) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }
@@ -273,7 +273,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override @Override
public void finish(boolean kill, ByteBuffer... buffers) { public void finish(boolean kill, ByteBuffer... buffers) {
if (message.isEmptyResptopic()) { if (message.isEmptyRespTopic()) {
if (callback != null) callback.run(); if (callback != null) callback.run();
return; return;
} }

View File

@@ -58,14 +58,31 @@ public abstract class MessageAgent {
protected int producerCount = 1; protected int producerCount = 1;
protected MessageCoder<MessageRecord> messageCoder = MessageRecordCoder.getInstance();
//本地Service消息接收处理器 key:consumer //本地Service消息接收处理器 key:consumer
protected HashMap<String, MessageConsumerNode> messageNodes = new LinkedHashMap<>(); protected HashMap<String, MessageConsumerNode> messageNodes = new LinkedHashMap<>();
public void init(AnyValue config) { public void init(ResourceFactory factory, AnyValue config) {
this.name = checkName(config.getValue("name", "")); this.name = checkName(config.getValue("name", ""));
this.httpMessageClient = new HttpMessageClient(this); this.httpMessageClient = new HttpMessageClient(this);
this.sncpMessageClient = new SncpMessageClient(this); this.sncpMessageClient = new SncpMessageClient(this);
this.producerCount = config.getIntValue("producers", Utility.cpus()); this.producerCount = config.getIntValue("producers", Utility.cpus());
String coderType = config.getValue("coder", "");
if (!coderType.trim().isEmpty()) {
try {
Class<MessageCoder<MessageRecord>> coderClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(coderType);
RedkaleClassLoader.putReflectionPublicConstructors(coderClass, coderClass.getName());
MessageCoder<MessageRecord> coder = coderClass.getConstructor().newInstance();
if (factory != null) factory.inject(coder);
if (coder instanceof Service) ((Service) coder).init(config);
this.messageCoder = coder;
} catch (RuntimeException ex) {
throw ex;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// application (it doesn't execute completion handlers). // application (it doesn't execute completion handlers).
this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> {
Thread t = new Thread(r); Thread t = new Thread(r);
@@ -102,6 +119,7 @@ public abstract class MessageAgent {
if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown(); if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown();
if (this.sncpProducer != null) this.sncpProducer.shutdown().join(); if (this.sncpProducer != null) this.sncpProducer.shutdown().join();
if (this.httpProducer != null) this.httpProducer.shutdown().join(); if (this.httpProducer != null) this.httpProducer.shutdown().join();
if (this.messageCoder instanceof Service) ((Service) this.messageCoder).destroy(config);
} }
protected List<MessageConsumer> getAllMessageConsumer() { protected List<MessageConsumer> getAllMessageConsumer() {
@@ -125,6 +143,10 @@ public abstract class MessageAgent {
return producers; return producers;
} }
public MessageCoder<MessageRecord> getMessageCoder() {
return this.messageCoder;
}
public Logger getLogger() { public Logger getLogger() {
return logger; return logger;
} }

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.Convert;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import static org.redkale.mq.MessageRecord.*; import static org.redkale.mq.MessageRecord.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.util.*;
/** /**
* *
@@ -76,7 +77,7 @@ public abstract class MessageClient {
if (node.scheduledFuture != null) node.scheduledFuture.cancel(true); if (node.scheduledFuture != null) node.scheduledFuture.cancel(true);
AtomicLong ncer = node.getCounter(); AtomicLong ncer = node.getCounter();
if (ncer != null) ncer.decrementAndGet(); if (ncer != null) ncer.decrementAndGet();
final long cha = now - msg.createtime; final long cha = now - msg.createTime;
if (finest) messageAgent.logger.log(Level.FINEST, clazzName + ".MessageRespFutureNode.receive (mq.delay = " + cha + "ms, mq.seqid = " + msg.getSeqid() + ")"); if (finest) messageAgent.logger.log(Level.FINEST, clazzName + ".MessageRespFutureNode.receive (mq.delay = " + cha + "ms, mq.seqid = " + msg.getSeqid() + ")");
node.future.complete(msg); node.future.complete(msg);
long cha2 = System.currentTimeMillis() - now; long cha2 = System.currentTimeMillis() - now;
@@ -97,8 +98,8 @@ public abstract class MessageClient {
} }
} }
} }
if (needresp && (message.getResptopic() == null || message.getResptopic().isEmpty())) { if (needresp && (message.getRespTopic() == null || message.getRespTopic().isEmpty())) {
message.setResptopic(respTopic); message.setRespTopic(respTopic);
} }
if (counter != null) counter.incrementAndGet(); if (counter != null) counter.incrementAndGet();
getProducer().apply(message); getProducer().apply(message);
@@ -126,47 +127,59 @@ public abstract class MessageClient {
protected abstract MessageProducers getProducer(); protected abstract MessageProducers getProducer();
public MessageRecord createMessageRecord(String resptopic, String content) { public MessageRecord createMessageRecord(String resptopic, String content) {
return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, null, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, null, resptopic, Traces.createTraceid(), content == null ? null : content.getBytes(StandardCharsets.UTF_8));
} }
public MessageRecord createMessageRecord(String topic, String resptopic, String content) { public MessageRecord createMessageRecord(String topic, String resptopic, String content) {
return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, Traces.createTraceid(), content == null ? null : content.getBytes(StandardCharsets.UTF_8));
}
public MessageRecord createMessageRecord(String topic, String resptopic, String traceid, String content) {
return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, content == null ? null : content.getBytes(StandardCharsets.UTF_8));
} }
public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String content) { public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String content) {
return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, Traces.createTraceid(), content == null ? null : content.getBytes(StandardCharsets.UTF_8));
}
public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String traceid, String content) {
return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, traceid, content == null ? null : content.getBytes(StandardCharsets.UTF_8));
} }
public MessageRecord createMessageRecord(String topic, String resptopic, Convert convert, Object bean) { public MessageRecord createMessageRecord(String topic, String resptopic, Convert convert, Object bean) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, convert.convertToBytes(bean)); return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean));
}
public MessageRecord createMessageRecord(String topic, String resptopic, String traceid, Convert convert, Object bean) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, convert.convertToBytes(bean));
} }
public MessageRecord createMessageRecord(int userid, String topic, String resptopic, Convert convert, Object bean) { public MessageRecord createMessageRecord(int userid, String topic, String resptopic, Convert convert, Object bean) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, convert.convertToBytes(bean)); return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean));
} }
public MessageRecord createMessageRecord(int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { public MessageRecord createMessageRecord(int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, groupid, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean));
} }
public MessageRecord createMessageRecord(int flag, int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { public MessageRecord createMessageRecord(int flag, int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean));
} }
public MessageRecord createMessageRecord(String topic, String resptopic, byte[] content) { public MessageRecord createMessageRecord(String topic, String resptopic, byte[] content) {
return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, content); return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, Traces.createTraceid(), content);
} }
public MessageRecord createMessageRecord(long seqid, String topic, String resptopic, byte[] content) { public MessageRecord createMessageRecord(long seqid, String topic, String resptopic, byte[] content) {
return new MessageRecord(seqid, (byte) 0, topic, resptopic, content); return new MessageRecord(seqid, (byte) 0, topic, resptopic, Traces.createTraceid(), content);
} }
protected MessageRecord createMessageRecord(byte ctype, String topic, String resptopic, byte[] content) { protected MessageRecord createMessageRecord(byte ctype, String topic, String resptopic, byte[] content) {
return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, content); return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, Traces.createTraceid(), content);
} }
protected MessageRecord createMessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { protected MessageRecord createMessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) {
return new MessageRecord(seqid, ctype, topic, resptopic, content); return new MessageRecord(seqid, ctype, topic, resptopic, Traces.createTraceid(), content);
} }
private byte ctype(Convert convert, Object bean) { private byte ctype(Convert convert, Object bean) {

View File

@@ -52,7 +52,7 @@ public class MessageRecord implements Serializable {
@ConvertColumn(index = 4) @ConvertColumn(index = 4)
@Comment("创建时间") @Comment("创建时间")
protected long createtime; protected long createTime;
@ConvertColumn(index = 5) @ConvertColumn(index = 5)
@Comment("用户ID无用户信息视为null或0, 具体数据类型只能是int、long、String") //@since 2.5.0 由int改成Serializable @Comment("用户ID无用户信息视为null或0, 具体数据类型只能是int、long、String") //@since 2.5.0 由int改成Serializable
@@ -68,40 +68,45 @@ public class MessageRecord implements Serializable {
@ConvertColumn(index = 8) @ConvertColumn(index = 8)
@Comment("目标topic, 为空表示无目标topic") @Comment("目标topic, 为空表示无目标topic")
protected String resptopic; protected String respTopic;
@ConvertColumn(index = 9) @ConvertColumn(index = 9)
@Comment("链路ID")
protected String traceid;
@ConvertColumn(index = 10)
@Comment("消息内容") @Comment("消息内容")
protected byte[] content; protected byte[] content;
@ConvertColumn(index = 10) @ConvertColumn(index = 11)
@Comment("消息内容的类型") @Comment("消息内容的类型")
protected byte ctype; protected byte ctype;
@Comment("本地附加对象,不会被序列化") @Comment("本地附加对象,不会被序列化")
protected Object localattach; protected Object localAttach;
public MessageRecord() { public MessageRecord() {
} }
protected MessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { protected MessageRecord(long seqid, byte ctype, String topic, String resptopic, String traceid, byte[] content) {
this(seqid, ctype, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content); this(seqid, ctype, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, content);
} }
protected MessageRecord(long seqid, byte ctype, int flag, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { protected MessageRecord(long seqid, byte ctype, int flag, Serializable userid, String groupid, String topic, String resptopic, String traceid, byte[] content) {
this(seqid, ctype, 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, content); this(seqid, ctype, 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, traceid, content);
} }
protected MessageRecord(long seqid, byte ctype, int version, int flag, long createtime, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { protected MessageRecord(long seqid, byte ctype, int version, int flag, long createTime, Serializable userid, String groupid, String topic, String resptopic, String traceid, byte[] content) {
this.seqid = seqid; this.seqid = seqid;
this.ctype = ctype; this.ctype = ctype;
this.version = version; this.version = version;
this.flag = flag; this.flag = flag;
this.createtime = createtime; this.createTime = createTime;
this.userid = userid; this.userid = userid;
this.groupid = groupid; this.groupid = groupid;
this.topic = topic; this.topic = topic;
this.resptopic = resptopic; this.respTopic = resptopic;
this.traceid = traceid;
this.content = content; this.content = content;
} }
@@ -110,7 +115,7 @@ public class MessageRecord implements Serializable {
} }
public MessageRecord attach(Object attach) { public MessageRecord attach(Object attach) {
this.localattach = attach; this.localAttach = attach;
return this; return this;
} }
@@ -120,8 +125,13 @@ public class MessageRecord implements Serializable {
} }
@ConvertDisabled @ConvertDisabled
public boolean isEmptyResptopic() { public boolean isEmptyRespTopic() {
return this.resptopic == null || this.resptopic.isEmpty(); return this.respTopic == null || this.respTopic.isEmpty();
}
@ConvertDisabled
public boolean isEmptyTraceid() {
return this.traceid == null || this.traceid.isEmpty();
} }
public <T> T convertFromContent(Convert convert, java.lang.reflect.Type type) { public <T> T convertFromContent(Convert convert, java.lang.reflect.Type type) {
@@ -159,8 +169,8 @@ public class MessageRecord implements Serializable {
return this; return this;
} }
public MessageRecord createtime(long createtime) { public MessageRecord createTime(long createtime) {
this.createtime = createtime; this.createTime = createtime;
return this; return this;
} }
@@ -179,8 +189,8 @@ public class MessageRecord implements Serializable {
return this; return this;
} }
public MessageRecord resptopic(String resptopic) { public MessageRecord respTopic(String resptopic) {
this.resptopic = resptopic; this.respTopic = resptopic;
return this; return this;
} }
@@ -189,6 +199,11 @@ public class MessageRecord implements Serializable {
return this; return this;
} }
public MessageRecord traceid(String traceid) {
this.traceid = traceid;
return this;
}
public MessageRecord contentString(String content) { public MessageRecord contentString(String content) {
this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8); this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8);
return this; return this;
@@ -218,12 +233,12 @@ public class MessageRecord implements Serializable {
this.flag = flag; this.flag = flag;
} }
public long getCreatetime() { public long getCreateTime() {
return createtime; return createTime;
} }
public void setCreatetime(long createtime) { public void setCreateTime(long createTime) {
this.createtime = createtime; this.createTime = createTime;
} }
public Serializable getUserid() { public Serializable getUserid() {
@@ -234,6 +249,14 @@ public class MessageRecord implements Serializable {
this.userid = userid; this.userid = userid;
} }
public String getTraceid() {
return traceid;
}
public void setTraceid(String traceid) {
this.traceid = traceid;
}
public String getGroupid() { public String getGroupid() {
return groupid; return groupid;
} }
@@ -250,12 +273,12 @@ public class MessageRecord implements Serializable {
this.topic = topic; this.topic = topic;
} }
public String getResptopic() { public String getRespTopic() {
return resptopic; return respTopic;
} }
public void setResptopic(String resptopic) { public void setRespTopic(String respTopic) {
this.resptopic = resptopic; this.respTopic = respTopic;
} }
public byte[] getContent() { public byte[] getContent() {
@@ -273,11 +296,11 @@ public class MessageRecord implements Serializable {
sb.append("{\"seqid\":").append(this.seqid); sb.append("{\"seqid\":").append(this.seqid);
sb.append(",\"version\":").append(this.version); sb.append(",\"version\":").append(this.version);
if (this.flag != 0) sb.append(",\"flag\":").append(this.flag); if (this.flag != 0) sb.append(",\"flag\":").append(this.flag);
if (this.createtime != 0) sb.append(",\"createtime\":").append(this.createtime); if (this.createTime != 0) sb.append(",\"createTime\":").append(this.createTime);
if (this.userid != null) sb.append(",\"userid\":").append(this.userid); if (this.userid != null) sb.append(",\"userid\":").append(this.userid);
if (this.groupid != null) sb.append(",\"groupid\":\"").append(this.groupid).append("\""); if (this.groupid != null) sb.append(",\"groupid\":\"").append(this.groupid).append("\"");
if (this.topic != null) sb.append(",\"topic\":\"").append(this.topic).append("\""); if (this.topic != null) sb.append(",\"topic\":\"").append(this.topic).append("\"");
if (this.resptopic != null) sb.append(",\"resptopic\":\"").append(this.resptopic).append("\""); if (this.respTopic != null) sb.append(",\"respTopic\":\"").append(this.respTopic).append("\"");
if (this.content != null) { if (this.content != null) {
if (this.ctype == CTYPE_BSON_RESULT && this.content.length > SncpRequest.HEADER_SIZE) { if (this.ctype == CTYPE_BSON_RESULT && this.content.length > SncpRequest.HEADER_SIZE) {
int offset = SncpRequest.HEADER_SIZE + 1; //循环占位符 int offset = SncpRequest.HEADER_SIZE + 1; //循环占位符
@@ -292,8 +315,8 @@ public class MessageRecord implements Serializable {
sb.append(",\"content\":").append(req); sb.append(",\"content\":").append(req);
} else if (this.ctype == CTYPE_HTTP_RESULT) { } else if (this.ctype == CTYPE_HTTP_RESULT) {
sb.append(",\"content\":").append(HttpResultCoder.getInstance().decode(this.content)); sb.append(",\"content\":").append(HttpResultCoder.getInstance().decode(this.content));
} else if (localattach != null) { } else if (localAttach != null) {
sb.append(",\"attach\":").append(JsonConvert.root().convertTo(localattach)); sb.append(",\"attach\":").append(JsonConvert.root().convertTo(localAttach));
} else { } else {
sb.append(",\"content\":\"").append(new String(this.content, StandardCharsets.UTF_8)).append("\""); sb.append(",\"content\":\"").append(new String(this.content, StandardCharsets.UTF_8)).append("\"");
} }

View File

@@ -29,10 +29,11 @@ public class MessageRecordCoder implements MessageCoder<MessageRecord> {
@Override @Override
public byte[] encode(MessageRecord data) { public byte[] encode(MessageRecord data) {
if (data == null) return null; if (data == null) return null;
byte[] stopics = MessageCoder.getBytes(data.getTopic());
byte[] dtopics = MessageCoder.getBytes(data.getResptopic());
byte[] groupid = MessageCoder.getBytes(data.getGroupid());
byte[] userid = MessageCoder.encodeUserid(data.getUserid()); byte[] userid = MessageCoder.encodeUserid(data.getUserid());
byte[] groupid = MessageCoder.getBytes(data.getGroupid());
byte[] topic = MessageCoder.getBytes(data.getTopic());
byte[] resptopic = MessageCoder.getBytes(data.getRespTopic());
byte[] traceid = MessageCoder.getBytes(data.getTraceid());
int count = 8 //seqid int count = 8 //seqid
+ 1 //ctype + 1 //ctype
+ 4 //version + 4 //version
@@ -40,8 +41,9 @@ public class MessageRecordCoder implements MessageCoder<MessageRecord> {
+ 8 //createtime + 8 //createtime
+ 2 + userid.length + 2 + userid.length
+ 2 + groupid.length + 2 + groupid.length
+ 2 + stopics.length + 2 + topic.length
+ 2 + dtopics.length + 2 + resptopic.length
+ 2 + traceid.length
+ 4 + (data.getContent() == null ? 0 : data.getContent().length); + 4 + (data.getContent() == null ? 0 : data.getContent().length);
final byte[] bs = new byte[count]; final byte[] bs = new byte[count];
ByteBuffer buffer = ByteBuffer.wrap(bs); ByteBuffer buffer = ByteBuffer.wrap(bs);
@@ -49,15 +51,23 @@ public class MessageRecordCoder implements MessageCoder<MessageRecord> {
buffer.put(data.ctype); buffer.put(data.ctype);
buffer.putInt(data.getVersion()); buffer.putInt(data.getVersion());
buffer.putInt(data.getFlag()); buffer.putInt(data.getFlag());
buffer.putLong(data.getCreatetime()); buffer.putLong(data.getCreateTime());
buffer.putChar((char) userid.length); buffer.putChar((char) userid.length);
if (userid.length > 0) buffer.put(userid); if (userid.length > 0) buffer.put(userid);
buffer.putChar((char) groupid.length); buffer.putChar((char) groupid.length);
if (groupid.length > 0) buffer.put(groupid); if (groupid.length > 0) buffer.put(groupid);
buffer.putChar((char) stopics.length);
if (stopics.length > 0) buffer.put(stopics); buffer.putChar((char) topic.length);
buffer.putChar((char) dtopics.length); if (topic.length > 0) buffer.put(topic);
if (dtopics.length > 0) buffer.put(dtopics);
buffer.putChar((char) resptopic.length);
if (resptopic.length > 0) buffer.put(resptopic);
buffer.putChar((char) traceid.length);
if (traceid.length > 0) buffer.put(traceid);
if (data.getContent() == null) { if (data.getContent() == null) {
buffer.putInt(0); buffer.putInt(0);
} else { } else {
@@ -81,6 +91,7 @@ public class MessageRecordCoder implements MessageCoder<MessageRecord> {
String groupid = MessageCoder.getShortString(buffer); String groupid = MessageCoder.getShortString(buffer);
String topic = MessageCoder.getShortString(buffer); String topic = MessageCoder.getShortString(buffer);
String resptopic = MessageCoder.getShortString(buffer); String resptopic = MessageCoder.getShortString(buffer);
String traceid = MessageCoder.getShortString(buffer);
byte[] content = null; byte[] content = null;
int contentlen = buffer.getInt(); int contentlen = buffer.getInt();
@@ -88,7 +99,7 @@ public class MessageRecordCoder implements MessageCoder<MessageRecord> {
content = new byte[contentlen]; content = new byte[contentlen];
buffer.get(content); buffer.get(content);
} }
return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, content); return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, traceid, content);
} }
} }

View File

@@ -23,7 +23,7 @@ public class MessageRespFutureNode implements Runnable {
protected final long seqid; protected final long seqid;
protected final long createtime; protected final long createTime;
protected final AtomicLong counter; protected final AtomicLong counter;
@@ -44,14 +44,14 @@ public class MessageRespFutureNode implements Runnable {
this.respNodes = respNodes; this.respNodes = respNodes;
this.counter = counter; this.counter = counter;
this.future = future; this.future = future;
this.createtime = System.currentTimeMillis(); this.createTime = System.currentTimeMillis();
} }
@Override //超时后被timeoutExecutor调用 @Override //超时后被timeoutExecutor调用
public void run() { //timeout public void run() { //timeout
respNodes.remove(this.seqid); respNodes.remove(this.seqid);
future.completeExceptionally(new TimeoutException()); future.completeExceptionally(new TimeoutException());
logger.log(Level.WARNING, getClass().getSimpleName() + " wait msg: " + message + " timeout " + (System.currentTimeMillis() - createtime) + "ms" logger.log(Level.WARNING, getClass().getSimpleName() + " wait msg: " + message + " timeout " + (System.currentTimeMillis() - createTime) + "ms"
+ (message.userid != null || (message.groupid != null && !message.groupid.isEmpty()) ? (message.userid != null ? (", userid:" + message.userid) : (", groupid:" + message.groupid)) : "")); + (message.userid != null || (message.groupid != null && !message.groupid.isEmpty()) ? (message.userid != null ? (", userid:" + message.userid) : (", groupid:" + message.groupid)) : ""));
} }
@@ -59,8 +59,8 @@ public class MessageRespFutureNode implements Runnable {
return seqid; return seqid;
} }
public long getCreatetime() { public long getCreateTime() {
return createtime; return createTime;
} }
public AtomicLong getCounter() { public AtomicLong getCounter() {

View File

@@ -10,6 +10,7 @@ import java.util.logging.*;
import org.redkale.boot.NodeSncpServer; import org.redkale.boot.NodeSncpServer;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.Service; import org.redkale.service.Service;
import org.redkale.util.Traces;
/** /**
* 一个Service对应一个MessageProcessor * 一个Service对应一个MessageProcessor
@@ -75,8 +76,9 @@ public class SncpMessageProcessor implements MessageProcessor {
private void execute(final MessageRecord message, final Runnable callback) { private void execute(final MessageRecord message, final Runnable callback) {
SncpMessageResponse response = null; SncpMessageResponse response = null;
try { try {
Traces.currTraceid(message.getTraceid());
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long cha = now - message.createtime; long cha = now - message.createTime;
long e = now - starttime; long e = now - starttime;
SncpContext context = server.getSncpServer().getContext(); SncpContext context = server.getSncpServer().getContext();
SncpMessageRequest request = new SncpMessageRequest(context, message); SncpMessageRequest request = new SncpMessageRequest(context, message);

View File

@@ -29,13 +29,13 @@ public class SncpMessageRequest extends SncpRequest {
super(context); super(context);
this.message = message; this.message = message;
this.hashid = this.message.hash(); this.hashid = this.message.hash();
this.createtime = System.currentTimeMillis(); this.createTime = System.currentTimeMillis();
readHeader(ByteBuffer.wrap(message.getContent()), null); readHeader(ByteBuffer.wrap(message.getContent()), null);
} }
@Override //被SncpAsyncHandler.sncp_setParams调用 @Override //被SncpAsyncHandler.sncp_setParams调用
protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) {
if (message.localattach != null) return; if (message.localAttach != null) return;
if (logger.isLoggable(Level.FINER)) { if (logger.isLoggable(Level.FINER)) {
message.attach(Utility.append(new Object[]{action.actionName()}, params)); message.attach(Utility.append(new Object[]{action.actionName()}, params));
} else { } else {

View File

@@ -51,12 +51,12 @@ public class SncpMessageResponse extends SncpResponse {
if (out == null) { if (out == null) {
final ByteArray result = new ByteArray(SncpRequest.HEADER_SIZE); final ByteArray result = new ByteArray(SncpRequest.HEADER_SIZE);
fillHeader(result, 0, retcode); fillHeader(result, 0, retcode);
producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, (byte[]) null)); producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getRespTopic(), null, (byte[]) null));
return; return;
} }
final int respBodyLength = out.count(); //body总长度 final int respBodyLength = out.count(); //body总长度
final ByteArray result = out.toByteArray(); final ByteArray result = out.toByteArray();
fillHeader(result, respBodyLength - HEADER_SIZE, retcode); fillHeader(result, respBodyLength - HEADER_SIZE, retcode);
producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, result.getBytes())); producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getRespTopic(), null, result.getBytes()));
} }
} }

View File

@@ -138,6 +138,14 @@ public abstract class AsyncConnection implements ChannelContext, Channel, AutoCl
ioThread.execute(command); ioThread.execute(command);
} }
public final void execute(Runnable... commands) {
ioThread.execute(commands);
}
public final void execute(Collection<Runnable> commands) {
ioThread.execute(commands);
}
public final boolean inCurrThread() { public final boolean inCurrThread() {
return ioThread.inCurrThread(); return ioThread.inCurrThread();
} }

View File

@@ -67,6 +67,15 @@ public class AsyncIOThread extends AsyncThread {
selector.wakeup(); selector.wakeup();
} }
@Override
public void execute(Collection<Runnable> commands) {
if (commands == null) return;
for (Runnable command : commands) {
commandQueue.offer(command);
}
selector.wakeup();
}
public void register(Consumer<Selector> consumer) { public void register(Consumer<Selector> consumer) {
registerQueue.offer(consumer); registerQueue.offer(consumer);
selector.wakeup(); selector.wakeup();

View File

@@ -215,6 +215,7 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
public final void prepare(final R request, final P response) { public final void prepare(final R request, final P response) {
try { try {
Traces.createTraceid();
request.prepare(); request.prepare();
response.filter = this.headFilter; response.filter = this.headFilter;
response.servlet = this; response.servlet = this;

View File

@@ -13,6 +13,7 @@ import java.util.function.*;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
* 一个AsyncConnection绑定一个ProtocolCodec实例
* *
* @author zhangjx * @author zhangjx
*/ */

View File

@@ -8,6 +8,7 @@ package org.redkale.net;
import java.io.*; import java.io.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import org.redkale.convert.ConvertDisabled;
import org.redkale.convert.bson.BsonConvert; import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
@@ -28,7 +29,7 @@ public abstract class Request<C extends Context> {
protected final JsonConvert jsonConvert; protected final JsonConvert jsonConvert;
protected long createtime; protected long createTime;
protected boolean keepAlive; protected boolean keepAlive;
@@ -80,7 +81,7 @@ public abstract class Request<C extends Context> {
protected void recycle() { protected void recycle() {
hashid = 0; hashid = 0;
createtime = 0; createTime = 0;
pipelineIndex = 0; pipelineIndex = 0;
pipelineCount = 0; pipelineCount = 0;
pipelineOver = false; pipelineOver = false;
@@ -139,8 +140,14 @@ public abstract class Request<C extends Context> {
return this.context; return this.context;
} }
@Deprecated //since 2.7.0 replace by getCreateTime()
@ConvertDisabled
public long getCreatetime() { public long getCreatetime() {
return createtime; return createTime;
}
public long getCreateTime() {
return createTime;
} }
public int getHashid() { public int getHashid() {

View File

@@ -143,7 +143,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
protected void init(AsyncConnection channel) { protected void init(AsyncConnection channel) {
this.channel = channel; this.channel = channel;
this.request.channel = channel; this.request.channel = channel;
this.request.createtime = System.currentTimeMillis(); this.request.createTime = System.currentTimeMillis();
} }
protected void setFilter(Filter<C, R, Response<C, R>> filter) { protected void setFilter(Filter<C, R, Response<C, R>> filter) {

View File

@@ -269,8 +269,9 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
public void start() throws IOException { public void start() throws IOException {
this.prepare.init(this.context, config); //不能在init方法内执行因Server.init执行后会调用loadService,loadServlet, 再执行Server.start this.prepare.init(this.context, config); //不能在init方法内执行因Server.init执行后会调用loadService,loadServlet, 再执行Server.start
this.postPrepareInit();
this.serverChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader); this.serverChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader);
if (application != null) { //main函数调试时可能为nulli if (application != null) { //main函数调试时可能为null
application.getResourceFactory().inject(this.serverChannel); application.getResourceFactory().inject(this.serverChannel);
} }
this.serverChannel.open(config); this.serverChannel.open(config);
@@ -284,6 +285,9 @@ public abstract class Server<K extends Serializable, C extends Context, R extend
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms"); + ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
} }
protected void postPrepareInit() {
}
protected void postStart() { protected void postStart() {
} }

View File

@@ -5,6 +5,7 @@
*/ */
package org.redkale.net; package org.redkale.net;
import java.util.Collection;
import java.util.concurrent.*; import java.util.concurrent.*;
import org.redkale.util.ThreadHashExecutor; import org.redkale.util.ThreadHashExecutor;
@@ -62,6 +63,19 @@ public class WorkThread extends Thread implements Executor {
} }
} }
public void execute(Collection<Runnable> commands) {
if (commands == null) return;
if (workExecutor == null) {
for (Runnable command : commands) {
command.run();
}
} else {
for (Runnable command : commands) {
workExecutor.execute(command);
}
}
}
public void runAsync(Runnable command) { public void runAsync(Runnable command) {
if (workExecutor == null) { if (workExecutor == null) {
ForkJoinPool.commonPool().execute(command); ForkJoinPool.commonPool().execute(command);

View File

@@ -5,7 +5,6 @@
*/ */
package org.redkale.net.client; package org.redkale.net.client;
import java.net.SocketAddress;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
@@ -27,6 +26,8 @@ import org.redkale.util.*;
*/ */
public abstract class Client<R extends ClientRequest, P> { public abstract class Client<R extends ClientRequest, P> {
public static final int DEFAULT_MAX_PIPELINES = 256;
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
protected final boolean finest = logger.isLoggable(Level.FINEST); protected final boolean finest = logger.isLoggable(Level.FINEST);
@@ -35,15 +36,13 @@ public abstract class Client<R extends ClientRequest, P> {
protected final boolean tcp; //是否TCP协议 protected final boolean tcp; //是否TCP协议
protected final SocketAddress address; //连接的地址 protected final ClientAddress address; //连接的地址
protected final Creator<ClientCodec<R, P>> codecCreator;
protected final ScheduledThreadPoolExecutor timeoutScheduler; protected final ScheduledThreadPoolExecutor timeoutScheduler;
protected final LongAdder writeReqCounter = new LongAdder(); protected final LongAdder reqWritedCounter = new LongAdder();
protected final LongAdder pollRespCounter = new LongAdder(); protected final LongAdder respDoneCounter = new LongAdder();
private final AtomicInteger connSeqno = new AtomicInteger(); private final AtomicInteger connSeqno = new AtomicInteger();
@@ -53,15 +52,15 @@ public abstract class Client<R extends ClientRequest, P> {
protected ClientConnection<R, P>[] connArray; //连接池 protected ClientConnection<R, P>[] connArray; //连接池
protected LongAdder[] connResps; //连接当前处理数 protected LongAdder[] connRespWaitings; //连接当前处理数
protected AtomicBoolean[] connOpens; //conns的标记组当conn不存在或closed状态标记为false protected AtomicBoolean[] connOpenStates; //conns的标记组当conn不存在或closed状态标记为false
protected final Queue<CompletableFuture<ClientConnection>>[] connWaits; //连接等待池 protected final Queue<CompletableFuture<ClientConnection>>[] connAcquireWaitings; //连接等待池
protected int connLimit = Utility.cpus(); //最大连接数 protected int connLimit = Utility.cpus(); //最大连接数
protected int maxPipelines = 16; //单个连接最大并行处理数 protected int maxPipelines = DEFAULT_MAX_PIPELINES; //单个连接最大并行处理数
protected int readTimeoutSeconds; protected int readTimeoutSeconds;
@@ -79,36 +78,35 @@ public abstract class Client<R extends ClientRequest, P> {
//创建连接后进行的登录鉴权操作 //创建连接后进行的登录鉴权操作
protected Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate; protected Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate;
protected Client(AsyncGroup group, SocketAddress address, Creator<ClientCodec<R, P>> responseCreator) { protected Client(AsyncGroup group, ClientAddress address) {
this(group, true, address, Utility.cpus(), 16, responseCreator, null, null, null); this(group, true, address, Utility.cpus(), 16, null, null, null);
} }
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, Creator<ClientCodec<R, P>> codecCreator) { protected Client(AsyncGroup group, boolean tcp, ClientAddress address) {
this(group, tcp, address, Utility.cpus(), 16, codecCreator, null, null, null); this(group, tcp, address, Utility.cpus(), 16, null, null, null);
} }
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator<ClientCodec<R, P>> codecCreator) { protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns) {
this(group, tcp, address, maxconns, 16, codecCreator, null, null, null); this(group, tcp, address, maxconns, 16, null, null, null);
} }
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, int maxPipelines, Creator<ClientCodec<R, P>> codecCreator) { protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns, int maxPipelines) {
this(group, tcp, address, maxconns, maxPipelines, codecCreator, null, null, null); this(group, tcp, address, maxconns, maxPipelines, null, null, null);
} }
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator<ClientCodec<R, P>> codecCreator, protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns,
Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) { Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) {
this(group, tcp, address, maxconns, 16, codecCreator, null, null, authenticate); this(group, tcp, address, maxconns, 16, null, null, authenticate);
} }
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator<ClientCodec<R, P>> codecCreator, protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns,
R closeRequest, Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) { R closeRequest, Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) {
this(group, tcp, address, maxconns, 16, codecCreator, null, closeRequest, authenticate); this(group, tcp, address, maxconns, 16, null, closeRequest, authenticate);
} }
@SuppressWarnings("OverridableMethodCallInConstructor") @SuppressWarnings("OverridableMethodCallInConstructor")
protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns,
int maxPipelines, Creator<ClientCodec<R, P>> codecCreator, R pingRequest, R closeRequest, int maxPipelines, R pingRequest, R closeRequest, Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) {
Function<CompletableFuture<ClientConnection>, CompletableFuture<ClientConnection>> authenticate) {
if (maxPipelines < 1) throw new IllegalArgumentException("maxPipelines must bigger 0"); if (maxPipelines < 1) throw new IllegalArgumentException("maxPipelines must bigger 0");
this.group = group; this.group = group;
this.tcp = tcp; this.tcp = tcp;
@@ -117,16 +115,15 @@ public abstract class Client<R extends ClientRequest, P> {
this.maxPipelines = maxPipelines; this.maxPipelines = maxPipelines;
this.pingRequest = pingRequest; this.pingRequest = pingRequest;
this.closeRequest = closeRequest; this.closeRequest = closeRequest;
this.codecCreator = codecCreator;
this.authenticate = authenticate; this.authenticate = authenticate;
this.connArray = new ClientConnection[connLimit]; this.connArray = new ClientConnection[connLimit];
this.connOpens = new AtomicBoolean[connLimit]; this.connOpenStates = new AtomicBoolean[connLimit];
this.connResps = new LongAdder[connLimit]; this.connRespWaitings = new LongAdder[connLimit];
this.connWaits = new Queue[connLimit]; this.connAcquireWaitings = new Queue[connLimit];
for (int i = 0; i < connOpens.length; i++) { for (int i = 0; i < connOpenStates.length; i++) {
this.connOpens[i] = new AtomicBoolean(); this.connOpenStates[i] = new AtomicBoolean();
this.connResps[i] = new LongAdder(); this.connRespWaitings[i] = new LongAdder();
this.connWaits[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque(); this.connAcquireWaitings[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque();
} }
//timeoutScheduler 不仅仅给超时用, 还给write用 //timeoutScheduler 不仅仅给超时用, 还给write用
this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
@@ -151,11 +148,13 @@ public abstract class Client<R extends ClientRequest, P> {
} }
} catch (Throwable t) { } catch (Throwable t) {
} }
}, pingInterval(), pingInterval(), TimeUnit.SECONDS); }, pingIntervalSeconds(), pingIntervalSeconds(), TimeUnit.SECONDS);
} }
} }
protected int pingInterval() { protected abstract ClientConnection createClientConnection(final int index, AsyncConnection channel);
protected int pingIntervalSeconds() {
return 30; return 30;
} }
@@ -205,80 +204,84 @@ public abstract class Client<R extends ClientRequest, P> {
if (cflag) { if (cflag) {
ClientConnection cc = context.getAttribute(connectionContextName); ClientConnection cc = context.getAttribute(connectionContextName);
if (cc != null && cc.isOpen()) return CompletableFuture.completedFuture(cc); if (cc != null && cc.isOpen()) return CompletableFuture.completedFuture(cc);
} }
int connIndex = -1; int connIndex;
final int size = this.connArray.length; final int size = this.connArray.length;
WorkThread workThread = WorkThread.currWorkThread(); WorkThread workThread = WorkThread.currWorkThread();
if (workThread != null && workThread.threads() == size) { if (workThread != null && workThread.threads() == size) {
connIndex = workThread.index(); connIndex = workThread.index();
} else {
connIndex = (int) Math.abs(Thread.currentThread().getId() % size);
} }
if (connIndex >= 0) { // if (connIndex >= 0) {
ClientConnection cc = this.connArray[connIndex]; ClientConnection cc = this.connArray[connIndex];
if (cc != null && cc.isOpen()) { if (cc != null && cc.isOpen()) {
if (cflag) context.setAttribute(connectionContextName, cc); if (cflag) context.setAttribute(connectionContextName, cc);
return CompletableFuture.completedFuture(cc); return CompletableFuture.completedFuture(cc);
}
final int index = connIndex;
final Queue<CompletableFuture<ClientConnection>> waitQueue = this.connWaits[index];
if (this.connOpens[index].compareAndSet(false, true)) {
CompletableFuture<ClientConnection> future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds)
.thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines));
return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> {
c.authenticated = true;
this.connArray[index] = c;
CompletableFuture<ClientConnection> f;
if (cflag) context.setAttribute(connectionContextName, c);
while ((f = waitQueue.poll()) != null) {
f.complete(c);
}
return c;
}).whenComplete((r, t) -> {
if (t != null) this.connOpens[index].set(false);
});
} else {
CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS);
waitQueue.offer(rs);
return rs;
}
} }
ClientConnection minRunningConn = null; final int index = connIndex;
for (int i = 0; i < size; i++) { final Queue<CompletableFuture<ClientConnection>> waitQueue = this.connAcquireWaitings[index];
final int index = i; if (this.connOpenStates[index].compareAndSet(false, true)) {
final ClientConnection conn = this.connArray[index]; CompletableFuture<ClientConnection> future = address.createClient(tcp, group, readTimeoutSeconds, writeTimeoutSeconds)
if (conn == null || !conn.isOpen()) { .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines));
if (this.connOpens[index].compareAndSet(false, true)) { return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> {
CompletableFuture<ClientConnection> future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) c.authenticated = true;
.thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); this.connArray[index] = c;
return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { CompletableFuture<ClientConnection> f;
c.authenticated = true; if (cflag) context.setAttribute(connectionContextName, c);
this.connArray[index] = c; while ((f = waitQueue.poll()) != null) {
return c; f.complete(c);
}).whenComplete((r, t) -> {
if (t != null) this.connOpens[index].set(false);
});
} }
} else if (conn.runningCount() < 1) { return c;
return CompletableFuture.completedFuture(conn); }).whenComplete((r, t) -> {
} else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) { if (t != null) this.connOpenStates[index].set(false);
minRunningConn = conn; });
} } else {
CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS);
waitQueue.offer(rs);
return rs;
} }
if (minRunningConn != null && minRunningConn.runningCount() < maxPipelines) { // }
ClientConnection minConn = minRunningConn; // ClientConnection minRunningConn = null;
return CompletableFuture.completedFuture(minConn); // for (int i = 0; i < size; i++) {
} // final int index = i;
return waitClientConnection(); // final ClientConnection conn = this.connArray[index];
// if (conn == null || !conn.isOpen()) {
// if (this.connOpenStates[index].compareAndSet(false, true)) {
// CompletableFuture<ClientConnection> future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds)
// .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines));
// return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> {
// c.authenticated = true;
// this.connArray[index] = c;
// return c;
// }).whenComplete((r, t) -> {
// if (t != null) this.connOpenStates[index].set(false);
// });
// }
// } else if (conn.runningCount() < 1) {
// return CompletableFuture.completedFuture(conn);
// } else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) {
// minRunningConn = conn;
// }
// }
// if (minRunningConn != null) { // && minRunningConn.runningCount() < maxPipelines
// return CompletableFuture.completedFuture(minRunningConn);
// }
// return waitClientConnection();
} }
protected CompletableFuture<ClientConnection> waitClientConnection() { protected CompletableFuture<ClientConnection> waitClientConnection() {
CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS);
connWaits[connSeqno.getAndIncrement() % this.connLimit].offer(rs); connAcquireWaitings[connSeqno.getAndIncrement() % this.connLimit].offer(rs);
return rs; return rs;
} }
protected ClientConnection createClientConnection(final int index, AsyncConnection channel) { protected long getRespWaitingCount() {
return new ClientConnection(this, index, channel); long s = 0;
for (LongAdder a : connRespWaitings) {
s += a.longValue();
}
return s;
} }
public int getReadTimeoutSeconds() { public int getReadTimeoutSeconds() {

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