Redkale 2.4.0 结束

This commit is contained in:
redkale
2021-10-18 13:19:30 +08:00
parent 2464c360c0
commit 7ffb65cc38
523 changed files with 90963 additions and 81040 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
/target/

View File

@@ -1,6 +1,6 @@
<h1>项目介绍</h1> <h1>项目介绍</h1>
<p> <p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 8全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 11全新的微服务框架, 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
</p> </p>
<strong>RedKale 有如下主要特点:</strong> <strong>RedKale 有如下主要特点:</strong>
<ol> <ol>

View File

@@ -1,7 +1,7 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 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..
java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -1,7 +1,7 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 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..
java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -1,9 +1,9 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 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.bat"
call "%APP_HOME%\bin\start.bat" call "%APP_HOME%\bin\start.bat"

View File

@@ -1,7 +1,7 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 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..
java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -1,8 +1,8 @@
@ECHO OFF @ECHO OFF
SET APP_HOME=%~dp0 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..
java -server -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application java -server -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

View File

@@ -1,14 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<application nodeid="10000" port="2121"> <application nodeid="10000" port="2020">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
<resources> <resources>
</resources> </resources>
<server protocol="HTTP" port="6060"> <server protocol="HTTP" port="5050">
<request> <request>
<remoteaddr value="request.headers.X-RemoteAddress"/> <remoteaddr value="request.headers.X-RemoteAddress"/>
@@ -24,7 +22,7 @@
<filters autoload="true"/> <filters autoload="true"/>
<rest path="/pipes" /> <!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 --> <rest path="/pipes" />
<servlets path="/pipes" autoload="true" /> <servlets path="/pipes" autoload="true" />

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <persistence version="2.0">
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="" transaction-type="RESOURCE_LOCAL"> <persistence-unit name="" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode> <shared-cache-mode>ALL</shared-cache-mode>

View File

@@ -4,16 +4,33 @@
<groupId>org.redkale</groupId> <groupId>org.redkale</groupId>
<artifactId>redkale</artifactId> <artifactId>redkale</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<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.2.0</version> <version>2.5.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<licenses> <licenses>
<license> <license>
<name>Apache 2</name> <name>Apache 2</name>
<url>http://www.apache.org/licenses/</url> <url>https://www.apache.org/licenses/</url>
<distribution>repo</distribution> <distribution>repo</distribution>
<comments>Apache License</comments> <comments>Apache License</comments>
</license> </license>
</licenses> </licenses>
<developers> <developers>
@@ -21,13 +38,13 @@
<id>Redkale</id> <id>Redkale</id>
<name>redkale</name> <name>redkale</name>
<email>redkale@qq.com</email> <email>redkale@qq.com</email>
<url>http://redkale.org</url> <url>https://redkale.org</url>
<roles> <roles>
<role>Project Manager</role> <role>Project Manager</role>
<role>Architect</role> <role>Architect</role>
</roles> </roles>
<organization>redkale</organization> <organization>redkale</organization>
<organizationUrl>http://redkale.org</organizationUrl> <organizationUrl>https://redkale.org</organizationUrl>
<properties> <properties>
<dept>No</dept> <dept>No</dept>
</properties> </properties>
@@ -35,12 +52,6 @@
</developer> </developer>
</developers> </developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<name>Redkale</name>
<distributionManagement> <distributionManagement>
<snapshotRepository> <snapshotRepository>
<id>ossrh</id> <id>ossrh</id>
@@ -51,11 +62,13 @@
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<scm> <scm>
<url>https://github.com/redkale/redkale</url> <url>https://github.com/redkale/redkale</url>
<connection>scm:git:git@github.com/redkale/redkale.git</connection> <connection>scm:git:git@github.com/redkale/redkale.git</connection>
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection> <developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
</scm> </scm>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@@ -99,6 +112,7 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
@@ -111,6 +125,7 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>

View File

@@ -1,97 +1,99 @@
<settings> <settings>
<servers> <servers>
<server> <server>
<id>ossrh</id> <id>ossrh</id>
<username>redkale</username> <username>redkale</username>
<password>xxxxxxxxxxxxxxxxxxxxxxxxx</password> <password>xxxxxxxxxxxxxxxxxxxxxxxxx</password>
</server> </server>
</servers> </servers>
<profiles> <profiles>
<profile> <profile>
<id>ossrh</id> <id>ossrh</id>
<activation> <activation>
<activeByDefault>true</activeByDefault> <activeByDefault>true</activeByDefault>
</activation> </activation>
<properties> <properties>
<gpg.executable>gpg2</gpg.executable> <gpg.executable>gpg2</gpg.executable>
<gpg.passphrase>xxxxxxxxxxxxxxxxxxxxxxxxx</gpg.passphrase> <gpg.passphrase>xxxxxxxxxxxxxxxxxxxxxxxxx</gpg.passphrase>
</properties> </properties>
</profile> </profile>
<profile> <profile>
<id>release</id> <id>release</id>
<build> <!--
<plugins> <build>
<plugin> <plugins>
<groupId>org.sonatype.plugins</groupId> <plugin>
<artifactId>nexus-staging-maven-plugin</artifactId> <groupId>org.sonatype.plugins</groupId>
<version>1.6.6</version> <artifactId>nexus-staging-maven-plugin</artifactId>
<extensions>true</extensions> <version>1.6.6</version>
<configuration> <extensions>true</extensions>
<serverId>ossrh</serverId> <configuration>
<nexusUrl>https://oss.sonatype.org/</nexusUrl> <serverId>ossrh</serverId>
<autoReleaseAfterClose>true</autoReleaseAfterClose> <nexusUrl>https://oss.sonatype.org/</nexusUrl>
</configuration> <autoReleaseAfterClose>true</autoReleaseAfterClose>
</plugin> </configuration>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-release-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>2.5.3</version> <artifactId>maven-release-plugin</artifactId>
<configuration> <version>2.5.3</version>
<autoVersionSubmodules>true</autoVersionSubmodules> <configuration>
<useReleaseProfile>false</useReleaseProfile> <autoVersionSubmodules>true</autoVersionSubmodules>
<releaseProfiles>release</releaseProfiles> <useReleaseProfile>false</useReleaseProfile>
<goals>deploy</goals> <releaseProfiles>release</releaseProfiles>
</configuration> <goals>deploy</goals>
</plugin> </configuration>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>3.5.1</version> <artifactId>maven-compiler-plugin</artifactId>
</plugin> <version>3.5.1</version>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-gpg-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>1.6</version> <artifactId>maven-gpg-plugin</artifactId>
<executions> <version>1.6</version>
<execution> <executions>
<id>sign-artifacts</id> <execution>
<phase>verify</phase> <id>sign-artifacts</id>
<goals> <phase>verify</phase>
<goal>sign</goal> <goals>
</goals> <goal>sign</goal>
</execution> </goals>
</executions> </execution>
</plugin> </executions>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-source-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>3.0.0</version> <artifactId>maven-source-plugin</artifactId>
<executions> <version>3.0.0</version>
<execution> <executions>
<id>attach-sources</id> <execution>
<goals> <id>attach-sources</id>
<goal>jar-no-fork</goal> <goals>
</goals> <goal>jar-no-fork</goal>
</execution> </goals>
</executions> </execution>
</plugin> </executions>
<plugin> </plugin>
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-javadoc-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>2.10.3</version> <artifactId>maven-javadoc-plugin</artifactId>
<executions> <version>2.10.3</version>
<execution> <executions>
<id>attach-javadocs</id> <execution>
<goals> <id>attach-javadocs</id>
<goal>jar</goal> <goals>
</goals> <goal>jar</goal>
</execution> </goals>
</executions> </execution>
</plugin> </executions>
</plugins> </plugin>
</build> </plugins>
</profile> </build>
</profiles> -->
</profile>
</profiles>
</settings> </settings>

138
pom.xml Normal file
View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.redkale</groupId>
<artifactId>redkale</artifactId>
<packaging>jar</packaging>
<name>RedkaleProject</name>
<url>https://redkale.org</url>
<description>redkale -- java framework</description>
<version>2.5.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<junit.version>5.7.0</junit.version>
<maven-jar-plugin.version>3.2.0</maven-jar-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>
<licenses>
<license>
<name>Apache 2</name>
<url>https://www.apache.org/licenses/</url>
<distribution>repo</distribution>
<comments>Apache License</comments>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<developers>
<developer>
<id>Redkale</id>
<name>redkale</name>
<email>redkale@qq.com</email>
<url>https://redkale.org</url>
<roles>
<role>Project Manager</role>
<role>Architect</role>
</roles>
<organization>redkale</organization>
<organizationUrl>https://redkale.org</organizationUrl>
<properties>
<dept>No</dept>
</properties>
<timezone>8</timezone>
</developer>
</developers>
<scm>
<url>https://github.com/redkale/redkale</url>
<connection>scm:git:git@github.com/redkale/redkale.git</connection>
<developerConnection>scm:git:git@github.com:redkale/redkale.git</developerConnection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 需要注释掉, 否则会生成native-image配置信息
<plugin>
<groupId>org.redkale.maven.plugins</groupId>
<artifactId>redkale-maven-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<id>redkale-compile</id>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<mainClass>org.redkale.boot.Application</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -136,12 +136,12 @@
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。 如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。 load: 加载文件,多个用;隔开。
默认置入的system.property.的有: 默认置入的system.property.的有:
System.setProperty("net.transport.poolmaxconns", "100"); System.setProperty("redkale.net.transport.poolmaxconns", "100");
System.setProperty("net.transport.pinginterval", "30"); System.setProperty("redkale.net.transport.pinginterval", "30");
System.setProperty("net.transport.checkinterval", "30"); System.setProperty("redkale.net.transport.checkinterval", "30");
System.setProperty("convert.tiny", "true"); System.setProperty("redkale.convert.tiny", "true");
System.setProperty("convert.pool.size", "128"); System.setProperty("redkale.convert.pool.size", "128");
System.setProperty("convert.writer.buffer.defsize", "4096"); System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点. <properties>节点下也可包含非<property>节点.
<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[] <property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
@@ -164,30 +164,38 @@
excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开 excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
charset: 文本编码, 默认: UTF-8 charset: 文本编码, 默认: UTF-8
backlog: 默认10K backlog: 默认10K
threads 线程数, 默认: CPU核数*2最小8个【已废弃 @since 2.3.0】 threads【已废弃】 线程数, 默认: CPU核数*2最小8个【已废弃 @since 2.3.0】
maxconns 最大连接数, 小于1表示无限制 默认: 0 maxconns 最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 1350B bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 1350B
bufferPoolSize ByteBuffer池的大小默认: 线程数*4 bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 线程数*2 responsePoolSize Response池的大小默认: 1024
aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 读操作超时秒数, 默认0 表示永久不超时 readTimeoutSeconds: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时 writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时
iogroup: 流线程组AsyncGroup对象如果值为client表示和Application.asyncGroup对象共用
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
--> -->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib=""> <server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
<!-- <!--
【节点在<server>中唯一】 【节点在<server>中唯一】
value: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLCreator的子类 builder: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLBuilder的子类
clientauth: true/false/want sslProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider
keystorepass: KEY密码 jsseProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider
keystorefile: KEY文件 protocol: TLS版本默认值: TLS
truststorepass: TRUST密码 protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3
truststorefile: TRUST文件 clientAuth: WANT/NEED/NONE, 默认值: NONE
ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256
keystorePass: KEY密码
keystoreFile: KEY文件 .jks
keystoreType: KEY类型 默认值为JKS
keystoreAlgorithm: KEY文件的algorithm 默认值为SunX509
truststorePass: TRUST密码
truststoreFile: TRUST文件
truststoreType: TRUST类型 默认值为JKS
truststoreAlgorithm: TRUST文件的algorithm 默认值为SunX509
--> -->
<ssl creator=""/> <ssl builder=""/>
<!-- <!--
加载所有的Service服务; 加载所有的Service服务;
@@ -296,7 +304,7 @@
period>0表示定时获取时间; 设置1000表示每秒刷新Date时间 period>0表示定时获取时间; 设置1000表示每秒刷新Date时间
--> -->
<response> <response>
<contenttype plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/> <content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<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" />
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/> <setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>

View File

@@ -12,29 +12,18 @@
是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL 是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL
--> -->
<property name="javax.persistence.cachemode" value="ALL"/> <property name="javax.persistence.cachemode" value="ALL"/>
<!--
是否自动建表当表不存在的时候, 目前只支持mysql、postgres 默认为false
-->
<property name="javax.persistence.table.autoddl" value="false"/>
<!-- 多个URL用;隔开如分布式SearchSource需要配多个URL --> <!-- 多个URL用;隔开如分布式SearchSource需要配多个URL -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
<!--
javax.persistence.jdbc.driver在JPA的值是JDBC驱动Redkale有所不同值应该是javax.sql.DataSource的子类。
为了兼容用户习惯Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系
org.mariadb.jdbc.Driver —————— org.mariadb.jdbc.MySQLDataSource
org.postgresql.Driver —————— org.postgresql.ds.PGConnectionPoolDataSource
com.mysql.jdbc.Driver —————— com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
com.mysql.cj.jdbc.Driver —————— com.mysql.cj.jdbc.MysqlConnectionPoolDataSource
oracle.jdbc.driver.OracleDriver —————— oracle.jdbc.pool.OracleConnectionPoolDataSource
com.microsoft.sqlserver.jdbc.SQLServerDriver —————— com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
org.h2.Driver —————— org.h2.jdbcx.JdbcDataSource
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本javax.persistence.jdbc.driver属性都可以省略Redkale会根据javax.persistence.jdbc.url的值来识别驱动
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.source" value="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"/>
-->
<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"/>
<!-- 最大连接数默认值CPU数*16 --> <!-- 最大连接数默认值CPU数 -->
<property name="javax.persistence.connections.limit" value="32"/> <property name="javax.persistence.connections.limit" value="12"/>
<!-- 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句 --> <!-- 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句 -->
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/> <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
@@ -42,7 +31,7 @@
<!-- 复制表结构的SQL模板Redkale内置了MySQL的语句 --> <!-- 复制表结构的SQL模板Redkale内置了MySQL的语句 -->
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/> <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/> <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"/>
</properties> </properties>
</persistence-unit> </persistence-unit>

View File

@@ -1,33 +1,39 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package javax.annotation; package javax.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* 值越大优先级越高 * 值越大优先级越高
* *
* @since Common Annotations 1.2 * @since Common Annotations 1.2
*/ */
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Priority { public @interface Priority {
int value();
} /**
* 优先级值
*
* @return int
*/
int value();
}

View File

@@ -1,32 +1,83 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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 javax.annotation; package javax.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* @since Common Annotations 1.0 * @since Common Annotations 1.0
*/ */
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Resource { public @interface Resource {
public enum AuthenticationType {
CONTAINER, /**
APPLICATION * AuthenticationType
} */
public String name() default ""; @Deprecated
public enum AuthenticationType {
public Class<?> type() default Object.class; /**
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; * @deprecated
public boolean shareable() default true; */
public String description() default ""; CONTAINER,
public String mappedName() default ""; /**
* @deprecated
public String lookup() default ""; */
} APPLICATION
}
/**
* 资源名称
*
* @return String
*/
public String name() default "";
/**
* 依赖注入的类型
*
* @return Class
*/
public Class<?> type() default Object.class;
/**
*
* @return AuthenticationType
*/
@Deprecated
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
/**
*
* @return boolean
*/
@Deprecated
public boolean shareable() default true;
/**
*
* @return String
*/
@Deprecated
public String description() default "";
/**
*
* @return String
*/
@Deprecated
public String mappedName() default "";
/**
*
* @return String
*/
@Deprecated
public String lookup() default "";
}

View File

@@ -1,62 +1,62 @@
/** ***************************************************************************** /** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
* *
* This program and the accompanying materials are made available under the * This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution. * which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at * and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php. * http://www.eclipse.org/org/documents/edl-v10.php.
* *
* Contributors: * Contributors:
* Linda DeMichiel - Java Persistence 2.1 * Linda DeMichiel - Java Persistence 2.1
* Linda DeMichiel - Java Persistence 2.0 * Linda DeMichiel - Java Persistence 2.0
* *
***************************************************************************** */ ***************************************************************************** */
package javax.persistence; package javax.persistence;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Specifies whether an entity should be cached if caching is enabled * Specifies whether an entity should be cached if caching is enabled
* when the value of the <code>persistence.xml</code> caching element * when the value of the <code>persistence.xml</code> caching element
* is <code>ENABLE_SELECTIVE</code> or <code>DISABLE_SELECTIVE</code>. * is <code>ENABLE_SELECTIVE</code> or <code>DISABLE_SELECTIVE</code>.
* The value of the <code>Cacheable</code> annotation is inherited by * The value of the <code>Cacheable</code> annotation is inherited by
* subclasses; it can be overridden by specifying * subclasses; it can be overridden by specifying
* <code>Cacheable</code> on a subclass. * <code>Cacheable</code> on a subclass.
* *
* <p> * <p>
* <code>Cacheable(false)</code> means that the entity and its state must * <code>Cacheable(false)</code> means that the entity and its state must
* not be cached by the provider. * not be cached by the provider.
* *
* @since Java Persistence 2.0 * @since Java Persistence 2.0
*/ */
@Target({TYPE}) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Cacheable { public @interface Cacheable {
/** /**
* (Optional) Whether or not the entity should be cached. * (Optional) Whether or not the entity should be cached.
* *
* @return boolean * @return boolean
*/ */
boolean value() default true; boolean value() default true;
/** /**
* (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache * (Optional) 定时自动更新缓存的周期秒数为0表示不做定时更新 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
* *
* @return int * @return int
*/ */
int interval() default 0; int interval() default 0;
/** /**
* DataSource是否直接返回对象的真实引用 而不是copy一份 * DataSource是否直接返回对象的真实引用 而不是copy一份
* *
* @return boolean * @return boolean
*/ */
boolean direct() default false; boolean direct() default false;
} }

View File

@@ -81,12 +81,19 @@ public @interface Column {
boolean unique() default false; boolean unique() default false;
/** /**
* (Optional) Whether the database column is nullable. * (Optional) Whether the database column is required.
* *
* @return boolean * @return boolean
*/ */
boolean nullable() default true; boolean nullable() default true;
/**
* for OpenAPI Specification 3
*
* @return String
*/
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.
@@ -109,11 +116,13 @@ public @interface Column {
* *
* @return String * @return String
*/ */
@Deprecated
String table() default ""; String table() default "";
/** /**
* (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
* *
* @return int * @return int
*/ */

View File

@@ -15,9 +15,7 @@
******************************************************************************/ ******************************************************************************/
package javax.persistence; package javax.persistence;
import java.lang.annotation.Target; import java.lang.annotation.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -27,6 +25,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* *
* @since Java Persistence 1.0 * @since Java Persistence 1.0
*/ */
@Inherited
@Documented @Documented
@Target(TYPE) @Target(TYPE)
@Retention(RUNTIME) @Retention(RUNTIME)

View File

@@ -82,6 +82,11 @@ public @interface Table {
*/ */
Index[] indexes() default {}; Index[] indexes() default {};
/**
* comment
*
* @return String
*/
String comment() default ""; String comment() default "";
} }

View File

@@ -4,20 +4,22 @@
* *
* @author zhangjx * @author zhangjx
* *
module org.redkale { */
module redkale {
requires java.base; requires java.base;
requires java.logging; requires java.logging;
requires java.xml; requires java.net.http;
requires java.sql; requires java.sql;
requires jdk.unsupported; //sun.misc.Unsafe requires jdk.unsupported; //sun.misc.Unsafe
exports javax.annotation; exports javax.annotation;
exports javax.persistence; exports javax.persistence;
exports org.redkale.asm;
exports org.redkale.boot; exports org.redkale.boot;
exports org.redkale.boot.watch; exports org.redkale.boot.watch;
exports org.redkale.cluster;
exports org.redkale.convert; exports org.redkale.convert;
exports org.redkale.convert.bson; exports org.redkale.convert.bson;
exports org.redkale.convert.ext; exports org.redkale.convert.ext;
@@ -32,10 +34,11 @@ module org.redkale {
exports org.redkale.util; exports org.redkale.util;
exports org.redkale.watch; exports org.redkale.watch;
uses org.redkale.cluster.ClusterAgent;
uses org.redkale.mq.MessageAgent; uses org.redkale.mq.MessageAgent;
uses org.redkale.source.CacheSource; uses org.redkale.cluster.ClusterAgent;
uses org.redkale.source.SourceLoader; uses org.redkale.convert.ConvertProvider;
uses org.redkale.source.CacheSourceProvider;
uses org.redkale.source.DataSourceProvider;
uses org.redkale.util.ResourceInjectLoader; uses org.redkale.util.ResourceInjectLoader;
} }
*/

View File

@@ -102,9 +102,6 @@ public abstract class AnnotationVisitor {
* method calls. May be null. * method calls. May be null.
*/ */
public AnnotationVisitor(final int api, final AnnotationVisitor av) { public AnnotationVisitor(final int api, final AnnotationVisitor av) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api; this.api = api;
this.av = av; this.av = av;
} }

View File

@@ -286,8 +286,13 @@ public class Attribute {
//The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed. //The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
//see also changes in ClassReader.accept. //see also changes in ClassReader.accept.
/**
*
*/
public static class NestMembers extends Attribute { public static class NestMembers extends Attribute {
/**
*
*/
public NestMembers() { public NestMembers() {
super("NestMembers"); super("NestMembers");
} }
@@ -321,11 +326,16 @@ public class Attribute {
} }
} }
/**
*
*/
public static class NestHost extends Attribute { public static class NestHost extends Attribute {
byte[] bytes; byte[] bytes;
String clazz; String clazz;
/**
*
*/
public NestHost() { public NestHost() {
super("NestHost"); super("NestHost");
} }

View File

@@ -104,9 +104,6 @@ public abstract class ClassVisitor {
* calls. May be null. * calls. May be null.
*/ */
public ClassVisitor(final int api, final ClassVisitor cv) { public ClassVisitor(final int api, final ClassVisitor cv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api; this.api = api;
this.cv = cv; this.cv = cv;
} }
@@ -244,9 +241,6 @@ public abstract class ClassVisitor {
*/ */
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) { TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (cv != null) { if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
} }

View File

@@ -1297,38 +1297,6 @@ public class ClassWriter extends ClassVisitor {
return result; return result;
} }
/**
* Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is
* intended for {@link Attribute} sub classes, and is normally not needed by
* class generators or adapters.</i>
*
* @param tag
* the kind of this handle. Must be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the field or method owner class.
* @param name
* the name of the field or method.
* @param desc
* the descriptor of the field or method.
* @return the index of a new or already existing method type reference
* item.
*
* @deprecated this method is superseded by
* {@link #newHandle(int, String, String, String, boolean)}.
*/
@Deprecated
public int newHandle(final int tag, final String owner, final String name,
final String desc) {
return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/** /**
* Adds a handle to the constant pool of the class being build. Does nothing * Adds a handle to the constant pool of the class being build. Does nothing
* if the constant pool already contains a similar item. <i>This method is * if the constant pool already contains a similar item. <i>This method is

View File

@@ -101,9 +101,6 @@ public abstract class FieldVisitor {
* calls. May be null. * calls. May be null.
*/ */
public FieldVisitor(final int api, final FieldVisitor fv) { public FieldVisitor(final int api, final FieldVisitor fv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api; this.api = api;
this.fv = fv; this.fv = fv;
} }
@@ -145,9 +142,6 @@ public abstract class FieldVisitor {
*/ */
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) { TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (fv != null) { if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
} }

View File

@@ -99,35 +99,6 @@ public final class Handle {
*/ */
final boolean itf; final boolean itf;
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* handle.
*
* @deprecated this constructor has been superseded
* by {@link #Handle(int, String, String, String, boolean)}.
*/
@Deprecated
public Handle(int tag, String owner, String name, String desc) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
}
/** /**
* Constructs a new field or method handle. * Constructs a new field or method handle.
* *

View File

@@ -1,192 +1,274 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.asm; package org.redkale.asm;
import java.util.*; import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/** import java.util.*;
* MethodVisitor 的调试类 import static org.redkale.asm.Opcodes.*;
* <p>
* 详情见: https://redkale.org /**
* * MethodVisitor 的调试类
* @author zhangjx * <p>
*/ * 详情见: https://redkale.org
public class MethodDebugVisitor { *
* @author zhangjx
private final MethodVisitor visitor; */
public class MethodDebugVisitor {
private boolean debug = false;
private final MethodVisitor visitor;
public MethodDebugVisitor setDebug(boolean d) {
debug = d; private boolean debug = false;
return this;
} public MethodDebugVisitor setDebug(boolean d) {
debug = d;
public void debugLine() { return this;
if (!debug) return; }
System.out.println();
System.out.println(); public void debugLine() {
System.out.println(); if (!debug) return;
} System.out.println();
System.out.println();
private final Map<Label, Integer> labels = new LinkedHashMap<>(); System.out.println();
}
private static final String[] opcodes = new String[200]; //0 -18
private final Map<Label, Integer> labels = new LinkedHashMap<>();
static {
try { private static final String[] opcodes = new String[200]; //0 -18
for (java.lang.reflect.Field field : Opcodes.class.getFields()) {
String name = field.getName(); static {
if (name.startsWith("ASM")) continue; try {
if (name.startsWith("V1_")) continue; for (java.lang.reflect.Field field : Opcodes.class.getFields()) {
if (name.startsWith("ACC_")) continue; String name = field.getName();
if (name.startsWith("T_")) continue; if (name.startsWith("ASM")) continue;
if (name.startsWith("H_")) continue; if (name.startsWith("V1_")) continue;
if (name.startsWith("F_")) continue; if (name.startsWith("ACC_")) continue;
if (field.getType() != int.class) continue; if (name.startsWith("T_")) continue;
opcodes[(int) (Integer) field.get(null)] = name; if (name.startsWith("H_")) continue;
} if (name.startsWith("F_")) continue;
} catch (Exception ex) { if (field.getType() != int.class) continue;
throw new RuntimeException(ex); //不可能会发生 opcodes[(int) (Integer) field.get(null)] = name;
} }
} } catch (Exception ex) {
throw new RuntimeException(ex); //不可能会发生
public MethodDebugVisitor(MethodVisitor visitor) { }
//super(Opcodes.ASM5, visitor); }
this.visitor = visitor;
} /**
*
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) { * @param visitor MethodVisitor
AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln); */
if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");"); public MethodDebugVisitor(MethodVisitor visitor) {
return av; //super(Opcodes.ASM5, visitor);
} this.visitor = visitor;
}
public AnnotationVisitor visitAnnotation(String desc, boolean flag) {
AnnotationVisitor av = visitor.visitAnnotation(desc, flag); public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
if (debug) System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");"); visitor.visitTryCatchBlock(start, end, handler, type);
return av; if (debug) System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");");
} }
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible); AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln);
if (debug) System.out.println("mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");"); if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");");
return av; return av;
} }
public void visitParameter(String name, int access) { public AnnotationVisitor visitAnnotation(String desc, boolean flag) {
visitor.visitParameter(name, access); AnnotationVisitor av = visitor.visitAnnotation(desc, flag);
if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");"); if (debug) System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");");
} return av;
}
public void visitVarInsn(int opcode, int var) {
visitor.visitVarInsn(opcode, var); public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible);
} if (debug) System.out.println("mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");");
return av;
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { }
visitor.visitFrame(type, nLocal, local, nStack, stack);
if (debug) { public void visitParameter(String name, int access) {
String typestr = "" + type; visitor.visitParameter(name, access);
if (type == -1) { if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");");
typestr = "Opcodes.F_NEW"; }
} else if (type == 1) {
typestr = "Opcodes.F_APPEND"; public void visitVarInsn(int opcode, int var) {
} else if (type == 2) { visitor.visitVarInsn(opcode, var);
typestr = "Opcodes.F_CHOP"; if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");");
} else if (type == 3) { }
typestr = "Opcodes.F_SAME";
} else if (type == 4) { public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
typestr = "Opcodes.F_SAME1"; visitor.visitFrame(type, nLocal, local, nStack, stack);
} if (debug) {
System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");"); String typestr = "" + type;
} if (type == -1) {
} typestr = "Opcodes.F_NEW";
} else if (type == 1) {
public void visitJumpInsn(int opcode, Label var) { //调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建 typestr = "Opcodes.F_APPEND";
visitor.visitJumpInsn(opcode, var); } else if (type == 2) {
if (debug) { typestr = "Opcodes.F_CHOP";
Integer index = labels.get(var); } else if (type == 3) {
if (index == null) { typestr = "Opcodes.F_SAME";
index = labels.size(); } else if (type == 4) {
labels.put(var, index); typestr = "Opcodes.F_SAME1";
System.out.println("Label l" + index + " = new Label();"); }
} System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");");
System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");"); }
} }
}
public void visitJumpInsn(int opcode, Label var) { //调用此方法的 ClassWriter 必须由 COMPUTE_FRAMES 构建
public void visitCode() { visitor.visitJumpInsn(opcode, var);
visitor.visitCode(); if (debug) {
if (debug) System.out.println("mv.visitCode();"); Integer index = labels.get(var);
} if (index == null) {
index = labels.size();
public void visitLabel(Label var) { labels.put(var, index);
visitor.visitLabel(var); System.out.println("Label l" + index + " = new Label();");
if (debug) { }
Integer index = labels.get(var); System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");");
if (index == null) { }
index = labels.size(); }
labels.put(var, index);
System.out.println("Label l" + index + " = new Label();"); public void visitCode() {
} visitor.visitCode();
System.out.println("mv.visitLabel(l" + index + ");"); if (debug) System.out.println("mv.visitCode();");
} }
}
public void visitLabel(Label var) {
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { visitor.visitLabel(var);
visitor.visitMethodInsn(opcode, owner, name, desc, itf); if (debug) {
if (debug) System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\", " + itf + ");"); Integer index = labels.get(var);
} if (index == null) {
index = labels.size();
public void visitFieldInsn(int opcode, String owner, String name, String desc) { labels.put(var, index);
visitor.visitFieldInsn(opcode, owner, name, desc); System.out.println("Label l" + index + " = new Label();");
if (debug) System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\");"); }
} System.out.println("mv.visitLabel(l" + index + ");");
}
public void visitTypeInsn(int opcode, String type) { }
visitor.visitTypeInsn(opcode, type);
if (debug) System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");"); public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
} visitor.visitMethodInsn(opcode, owner, name, desc, itf);
if (debug) System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\", " + itf + ");");
public void visitInsn(int opcode) { }
visitor.visitInsn(opcode);
if (debug) System.out.println("mv.visitInsn(" + opcodes[opcode] + ");"); public void visitFieldInsn(int opcode, String owner, String name, String desc) {
} visitor.visitFieldInsn(opcode, owner, name, desc);
if (debug) System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\");");
public void visitIntInsn(int opcode, int value) { }
visitor.visitIntInsn(opcode, value);
if (debug) System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");"); public void visitTypeInsn(int opcode, String type) {
} visitor.visitTypeInsn(opcode, type);
if (debug) System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");");
public void visitIincInsn(int opcode, int value) { }
visitor.visitIincInsn(opcode, value);
if (debug) System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");"); public void visitInsn(int opcode) {
} visitor.visitInsn(opcode);
if (debug) System.out.println("mv.visitInsn(" + opcodes[opcode] + ");");
public void visitLdcInsn(Object o) { }
visitor.visitLdcInsn(o);
if (debug) { public void visitIntInsn(int opcode, int value) {
if (o instanceof CharSequence) { visitor.visitIntInsn(opcode, value);
System.out.println("mv.visitLdcInsn(\"" + o + "\");"); if (debug) System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");");
} else if (o instanceof org.redkale.asm.Type) { }
System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
} else { public void visitIincInsn(int opcode, int value) {
System.out.println("mv.visitLdcInsn(" + o + ");"); visitor.visitIincInsn(opcode, value);
} if (debug) System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");");
} }
}
public void visitLdcInsn(Object o) {
public void visitMaxs(int maxStack, int maxLocals) { visitor.visitLdcInsn(o);
visitor.visitMaxs(maxStack, maxLocals); if (debug) {
if (debug) System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");"); if (o instanceof CharSequence) {
} System.out.println("mv.visitLdcInsn(\"" + o + "\");");
} else if (o instanceof org.redkale.asm.Type) {
public void visitEnd() { System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));");
visitor.visitEnd(); } else {
if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n"); System.out.println("mv.visitLdcInsn(" + o + ");");
} }
} }
}
public void visitMaxs(int maxStack, int maxLocals) {
visitor.visitMaxs(maxStack, maxLocals);
if (debug) System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");");
}
public void visitEnd() {
visitor.visitEnd();
if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n");
}
public static void pushInt(MethodDebugVisitor mv, int num) {
if (num < 6) {
mv.visitInsn(ICONST_0 + num);
} else if (num <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, num);
} else if (num <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, num);
} else {
mv.visitLdcInsn(num);
}
}
public static void pushInt(MethodVisitor mv, int num) {
if (num < 6) {
mv.visitInsn(ICONST_0 + num);
} else if (num <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, num);
} else if (num <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, num);
} else {
mv.visitLdcInsn(num);
}
}
public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) {
try {
for (Method anm : ann.annotationType().getMethods()) {
final String mname = anm.getName();
if ("equals".equals(mname) || "hashCode".equals(mname) || "toString".equals(mname) || "annotationType".equals(mname)) continue;
final Object r = anm.invoke(ann);
if (r instanceof String[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (String item : (String[]) r) {
av1.visit(null, item);
}
av1.visitEnd();
} else if (r instanceof Class[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Class item : (Class[]) r) {
av1.visit(null, Type.getType(item));
}
av1.visitEnd();
} else if (r instanceof Enum[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Enum item : (Enum[]) r) {
av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name());
}
av1.visitEnd();
} else if (r instanceof Annotation[]) {
AnnotationVisitor av1 = av.visitArray(mname);
for (Annotation item : (Annotation[]) r) {
visitAnnotation(av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), item);
}
av1.visitEnd();
} else if (r instanceof Class) {
av.visit(mname, Type.getType((Class) r));
} else if (r instanceof Enum) {
av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name());
} else if (r instanceof Annotation) {
visitAnnotation(av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), (Annotation) r);
} else {
av.visit(mname, r);
}
}
av.visitEnd();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -118,9 +118,6 @@ public abstract class MethodVisitor {
* calls. May be null. * calls. May be null.
*/ */
public MethodVisitor(final int api, final MethodVisitor mv) { public MethodVisitor(final int api, final MethodVisitor mv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException();
}
this.api = api; this.api = api;
this.mv = mv; this.mv = mv;
} }
@@ -140,9 +137,6 @@ public abstract class MethodVisitor {
* allowed (see {@link Opcodes}). * allowed (see {@link Opcodes}).
*/ */
public void visitParameter(String name, int access) { public void visitParameter(String name, int access) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) { if (mv != null) {
mv.visitParameter(name, access); mv.visitParameter(name, access);
} }
@@ -209,9 +203,6 @@ public abstract class MethodVisitor {
*/ */
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) { TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) { if (mv != null) {
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible); return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
} }
@@ -453,35 +444,6 @@ public abstract class MethodVisitor {
} }
} }
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
@Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/** /**
* Visits a method instruction. A method instruction is an instruction that * Visits a method instruction. A method instruction is an instruction that
* invokes a method. * invokes a method.
@@ -502,14 +464,6 @@ public abstract class MethodVisitor {
*/ */
public void visitMethodInsn(int opcode, String owner, String name, public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) { String desc, boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException(
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf); mv.visitMethodInsn(opcode, owner, name, desc, itf);
} }
@@ -723,9 +677,6 @@ public abstract class MethodVisitor {
*/ */
public AnnotationVisitor visitInsnAnnotation(int typeRef, public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) { TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) { if (mv != null) {
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible); return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
} }
@@ -783,9 +734,6 @@ public abstract class MethodVisitor {
*/ */
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) { TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) { if (mv != null) {
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible); return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
} }
@@ -854,9 +802,6 @@ public abstract class MethodVisitor {
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index, TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) { String desc, boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
if (mv != null) { if (mv != null) {
return mv.visitLocalVariableAnnotation(typeRef, typePath, start, return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
end, index, desc, visible); end, index, desc, visible);

View File

@@ -73,10 +73,9 @@ package org.redkale.asm;
public interface Opcodes { public interface Opcodes {
// ASM API versions // ASM API versions
int ASM4 = 4 << 16 | 0 << 8;
int ASM4 = 4 << 16 | 0 << 8 | 0; int ASM5 = 5 << 16 | 0 << 8;
int ASM5 = 5 << 16 | 0 << 8 | 0; int ASM6 = 6 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8 | 0;
// versions // versions

View File

@@ -161,7 +161,7 @@ public class TypePath {
* @return the corresponding TypePath object, or null if the path is empty. * @return the corresponding TypePath object, or null if the path is empty.
*/ */
public static TypePath fromString(final String typePath) { public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.length() == 0) { if (typePath == null || typePath.isEmpty()) {
return null; return null;
} }
int n = typePath.length(); int n = typePath.length();

View File

@@ -1,27 +1,27 @@
need copy classes: need copy classes:
AnnotationVisitor.java AnnotationVisitor.java
AnnotationWriter.java AnnotationWriter.java
Attribute.java Attribute.java
ByteVector.java ByteVector.java
ClassReader.java ClassReader.java
ClassVisitor.java ClassVisitor.java
ClassWriter.java ClassWriter.java
Context.java Context.java
CurrentFrame.java CurrentFrame.java
Edge.java Edge.java
FieldVisitor.java FieldVisitor.java
FieldWriter.java FieldWriter.java
Frame.java Frame.java
Handle.java Handle.java
Handler.java Handler.java
Item.java Item.java
Label.java Label.java
MethodVisitor.java MethodVisitor.java
MethodWriter.java MethodWriter.java
ModuleVisitor.java ModuleVisitor.java
ModuleWriter.java ModuleWriter.java
Opcodes.java Opcodes.java
Type.java Type.java
TypePath.java TypePath.java
TypeReference.java TypeReference.java

View File

@@ -1,4 +1,4 @@
/** /**
* 本包下所有代码均是从/java.base/jdk/internal/org/objectweb/asm 拷贝过来的 * 本包下所有代码均是从/java.base/jdk/internal/org/objectweb/asm 拷贝过来的
*/ */
package org.redkale.asm; package org.redkale.asm;

View File

@@ -0,0 +1,535 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import java.io.*;
import java.lang.reflect.*;
import java.math.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.persistence.*;
import org.redkale.convert.*;
import org.redkale.convert.json.*;
import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 HttpMapping 信息 <br>
* https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class ApiDocsService {
private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken<RetResult<String>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_INTEGER = new TypeToken<RetResult<Integer>>() {
}.getType();
private static final java.lang.reflect.Type TYPE_RETRESULT_LONG = new TypeToken<RetResult<Long>>() {
}.getType();
private final Application app; //Application全局对象
public ApiDocsService(Application app) {
this.app = app;
}
public void run(String[] args) throws Exception {
//是否跳过RPC接口
final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false");
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
__prefix.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> typesMap = new LinkedHashMap<>();
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
Map<String, Object> swaggerPathsMap = new LinkedHashMap<>();
List<Map> swaggerServers = new ArrayList<>();
List<Map> swaggerTags = new ArrayList<>();
Map<String, Map<String, Object>> swaggerComponentsMap = new LinkedHashMap<>();
for (NodeServer node : app.servers) {
if (!(node instanceof NodeHttpServer)) continue;
final Map<String, Object> map = new LinkedHashMap<>();
serverList.add(map);
HttpServer server = node.getServer();
map.put("address", server.getSocketAddress());
swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort()));
List<Map<String, Object>> servletsList = new ArrayList<>();
map.put("servlets", servletsList);
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json";
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
for (HttpServlet servlet : server.getPrepareServlet().getServlets()) {
if (!(servlet instanceof HttpServlet)) continue;
if (servlet instanceof WebSocketServlet) continue;
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer");
continue;
}
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws == null) {
node.logger.log(Level.WARNING, servlet + " not found @WebServlet");
continue;
}
if (ws.name().isEmpty()) {
node.logger.log(Level.INFO, servlet + " be skipped because @WebServlet.name is empty");
continue;
}
final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name();
final Map<String, Object> servletMap = new LinkedHashMap<>();
String prefix = (String) __prefix.get(servlet);
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < urlregs.length; i++) {
urlregs[i] = prefix + urlregs[i];
}
}
servletMap.put("urlregs", urlregs);
servletMap.put("moduleid", ws.moduleid());
servletMap.put("name", ws.name());
servletMap.put("comment", ws.comment());
List<Map> mappingsList = new ArrayList<>();
servletMap.put("mappings", mappingsList);
final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionUrls = new HashSet<>();
do {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
HttpMapping action = method.getAnnotation(HttpMapping.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
if (actionUrls.contains(action.url())) continue;
if (HttpScope.class.isAssignableFrom(action.result())) continue; //忽略模板引擎的方法
if (action.rpconly() && skipRPC) continue; //不生成RPC接口
final List<Map<String, Object>> swaggerParamsList = new ArrayList<>();
final Map<String, Object> mappingMap = new LinkedHashMap<>();
mappingMap.put("url", prefix + action.url());
actionUrls.add(action.url());
mappingMap.put("auth", action.auth());
mappingMap.put("actionid", action.actionid());
mappingMap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
mappingMap.put("params", paramsList);
List<String> results = new ArrayList<>();
Type resultType = action.result();
if (!action.resultref().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(action.resultref());
f.setAccessible(true);
resultType = (Type) f.get(servlet);
}
// for (final Class rtype : action.results()) {
// results.add(rtype.getName());
// if (typesMap.containsKey(rtype.getName())) continue;
// if (rtype.getName().startsWith("java.")) continue;
// if (rtype.getName().startsWith("javax.")) continue;
// final boolean filter = FilterBean.class.isAssignableFrom(rtype);
// final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
// Class loop = rtype;
// do {
// if (loop == null || loop.isInterface()) break;
// for (Field field : loop.getDeclaredFields()) {
// if (Modifier.isFinal(field.getModifiers())) continue;
// if (Modifier.isStatic(field.getModifiers())) continue;
//
// Map<String, Object> fieldmap = new LinkedHashMap<>();
// fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
//
// Comment comment = field.getAnnotation(Comment.class);
// Column col = field.getAnnotation(Column.class);
// FilterColumn fc = field.getAnnotation(FilterColumn.class);
// if (comment != null) {
// fieldmap.put("comment", comment.value());
// } else if (col != null) {
// fieldmap.put("comment", col.comment());
// } else if (fc != null) {
// fieldmap.put("comment", fc.comment());
// }
// fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
// fieldmap.put("updatable", (filter || col == null || col.updatable()));
// if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
// if (field.getAnnotation(RestAddress.class) != null) continue;
// }
//
// typeMap.put(field.getName(), fieldmap);
// }
// } while ((loop = loop.getSuperclass()) != Object.class);
// typesMap.put(rtype.getName(), typeMap);
// }
mappingMap.put("results", results);
boolean hasbodyparam = false;
Map<String, Object> swaggerRequestBody = new LinkedHashMap<>();
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> oldapisParamMap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
final Class ptype = isarray ? param.type().getComponentType() : param.type();
oldapisParamMap.put("name", param.name());
oldapisParamMap.put("radix", param.radix());
oldapisParamMap.put("type", ptype.getName() + (isarray ? "[]" : ""));
oldapisParamMap.put("style", param.style());
oldapisParamMap.put("comment", param.comment());
oldapisParamMap.put("required", param.required());
paramsList.add(oldapisParamMap);
{
final Map<String, Object> paramSchemaMap = new LinkedHashMap<>();
Type paramGenericType = param.type();
if (!param.typeref().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(param.typeref());
f.setAccessible(true);
paramGenericType = (Type) f.get(servlet);
}
simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
swaggerRequestBody.put("description", param.comment());
swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap)));
} else {
final Map<String, Object> swaggerParamMap = new LinkedHashMap<>();
swaggerParamMap.put("name", param.name());
swaggerParamMap.put("in", param.style().name().toLowerCase());
swaggerParamMap.put("description", param.comment());
swaggerParamMap.put("required", param.required());
if (param.deprecated()) {
swaggerParamMap.put("deprecated", param.deprecated());
}
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterStyle
swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form");
swaggerParamMap.put("explode", true);
swaggerParamMap.put("schema", paramSchemaMap);
Object example = formatExample(param.example(), param.type(), paramGenericType);
if (example != null) swaggerParamMap.put("example", example);
if (!param.example().isEmpty()) {
swaggerParamMap.put("example", param.example());
}
swaggerParamsList.add(swaggerParamMap);
}
}
if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true;
if (ptype.isPrimitive() || ptype == String.class) continue;
if (typesMap.containsKey(ptype.getName())) continue;
if (ptype.getName().startsWith("java.")) continue;
if (ptype.getName().startsWith("javax.")) continue;
final Map<String, Map<String, Object>> typeMap = new LinkedHashMap<>();
Class loop = ptype;
final boolean filter = FilterBean.class.isAssignableFrom(loop);
do {
if (loop == null || loop.isInterface()) break;
for (Field field : loop.getDeclaredFields()) {
if (Modifier.isFinal(field.getModifiers())) continue;
if (Modifier.isStatic(field.getModifiers())) continue;
Map<String, Object> fieldmap = new LinkedHashMap<>();
fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName());
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
if (field.getAnnotation(RestAddress.class) != null) continue;
}
typeMap.put(field.getName(), fieldmap);
}
} while ((loop = loop.getSuperclass()) != Object.class);
typesMap.put(ptype.getName(), typeMap);
}
mappingMap.put("result", action.result().getSimpleName().replace("void", "Object"));
mappingsList.add(mappingMap);
final Map<String, Object> swaggerOperatMap = new LinkedHashMap<>();
swaggerOperatMap.put("tags", new String[]{tag});
swaggerOperatMap.put("operationId", action.name());
if (method.getAnnotation(Deprecated.class) != null) {
swaggerOperatMap.put("deprecated", true);
}
Map<String, Object> respSchemaMap = new LinkedHashMap<>();
simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
Map<String, Object> respMap = new LinkedHashMap<>();
respMap.put("schema", respSchemaMap);
Object example = formatExample(action.example(), action.result(), resultType);
if (example != null) swaggerOperatMap.put("example", example);
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
swaggerOperatMap.put("parameters", swaggerParamsList);
String actiondesc = action.comment();
if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc;
swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap))));
String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase();
if (m == null) {
m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType)
|| TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert")
|| action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get";
}
swaggerPathsMap.put(prefix + action.url(), Utility.ofMap("description", action.comment(), m, swaggerOperatMap));
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletMap);
if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment()));
}
servletsList.sort((o1, o2) -> {
String[] urlregs1 = (String[]) o1.get("urlregs");
String[] urlregs2 = (String[]) o2.get("urlregs");
return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1;
});
}
{ // https://github.com/OAI/OpenAPI-Specification
Map<String, Object> swaggerResultMap = new LinkedHashMap<>();
swaggerResultMap.put("openapi", "3.0.0");
Map<String, Object> infomap = new LinkedHashMap<>();
infomap.put("title", "Redkale generate apidoc");
infomap.put("version", "1.0.0");
swaggerResultMap.put("info", infomap);
swaggerResultMap.put("servers", swaggerServers);
swaggerResultMap.put("paths", swaggerPathsMap);
swaggerResultMap.put("tags", swaggerTags);
if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap));
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json"));
out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8));
out.close();
}
{
Map<String, Object> oldapisResultMap = new LinkedHashMap<>();
oldapisResultMap.put("servers", serverList);
oldapisResultMap.put("types", typesMap);
final String json = JsonConvert.root().convertTo(oldapisResultMap);
final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"));
out.write(json.getBytes(StandardCharsets.UTF_8));
out.close();
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);
}
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("'${content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes(StandardCharsets.UTF_8));
outhtml.close();
}
}
private static void simpleSchemaType(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) {
schemaMap.put("type", "integer");
schemaMap.put("format", "int32");
} else if (type == long.class || type == Long.class
|| type == AtomicLong.class || type == LongAdder.class || type == BigInteger.class) {
schemaMap.put("type", "integer");
schemaMap.put("format", "int64");
} else if (type == float.class || type == Float.class) {
schemaMap.put("type", "number");
schemaMap.put("format", "float");
} else if (type == double.class || type == Double.class || type == BigDecimal.class) {
schemaMap.put("type", "number");
schemaMap.put("format", "double");
} else if (type == boolean.class || type == Boolean.class || type == AtomicBoolean.class) {
schemaMap.put("type", "boolean");
} else if (type.isPrimitive() || Number.class.isAssignableFrom(type)) {
schemaMap.put("type", "number");
} else if (type == String.class || CharSequence.class.isAssignableFrom(type)) {
schemaMap.put("type", "string");
} else if (recursive && (type.isArray() || Collection.class.isAssignableFrom(type))) {
schemaMap.put("type", "array");
Map<String, Object> sbumap = new LinkedHashMap<>();
if (type.isArray()) {
simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
} else if (genericType instanceof ParameterizedType) {
Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (subpt instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false);
} else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
} else {
sbumap.put("type", "object");
}
} else {
sbumap.put("type", "object");
}
schemaMap.put("items", sbumap);
} else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) {
String ct = simpleComponentType(logger, componentsMap, type, genericType);
if (ct == null) {
schemaMap.put("type", "object");
} else {
schemaMap.put("$ref", "#/components/schemas/" + ct);
}
} else {
schemaMap.put("type", "object");
}
}
private static String simpleComponentType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
try {
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
String ct = componentKey(logger, componentsMap, null, encodeable, true);
if (ct == null || ct.length() == 0) return null;
if (componentsMap.containsKey(ct)) return ct;
Map<String, Object> cmap = new LinkedHashMap<>();
componentsMap.put(ct, cmap); //必须在调用simpleSchemaType之前put不然嵌套情况下死循环
cmap.put("type", "object");
List<String> requireds = new ArrayList<>();
Map<String, Object> properties = new LinkedHashMap<>();
if (encodeable instanceof ObjectEncoder) {
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
Map<String, Object> schemaMap = new LinkedHashMap<>();
simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
String desc = "";
if (member.getField() != null) {
Column col = member.getField().getAnnotation(Column.class);
if (col == null) {
FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class);
if (fcol != null) {
desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field());
}
} else {
desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field());
}
if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) {
desc = member.getField().getAnnotation(Comment.class).value();
}
} else if (member.getMethod() != null) {
Column col = member.getMethod().getAnnotation(Column.class);
if (col == null) {
FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class);
if (fcol != null) {
desc = fcol.comment();
if (fcol.required()) requireds.add(member.getAttribute().field());
}
} else {
desc = col.comment();
if (!col.nullable()) requireds.add(member.getAttribute().field());
}
if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) {
desc = member.getMethod().getAnnotation(Comment.class).value();
}
}
if (!desc.isEmpty()) schemaMap.put("description", desc);
properties.put(member.getAttribute().field(), schemaMap);
}
}
if (!requireds.isEmpty()) cmap.put("required", requireds);
cmap.put("properties", properties);
return ct;
} catch (Exception e) {
logger.log(Level.WARNING, genericType + " generate component info error", e);
return null;
}
}
private static String componentKey(Logger logger, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
if (encodeable instanceof ObjectEncoder) {
StringBuilder sb = new StringBuilder();
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
if (member.getEncoder() instanceof ArrayEncoder
|| member.getEncoder() instanceof CollectionEncoder) {
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
if (member.getEncoder() instanceof SimpledCoder) {
simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
} else {
simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
}
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof MapEncoder) {
continue;
} else {
return null;
}
}
return sb.toString();
} else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) {
final boolean array = (encodeable instanceof ArrayEncoder);
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
if (subEncodeable instanceof SimpledCoder && field != null) return "";
final String sb = componentKey(logger, componentsMap, null, subEncodeable, false);
if (sb == null || sb.isEmpty()) return sb;
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
return sb;
}
return sb + (array ? "_Array" : "_Collection");
} else if (encodeable instanceof SimpledCoder) {
Class stype = ((SimpledCoder) encodeable).getType();
if (stype.isPrimitive() || stype == Boolean.class || Number.class.isAssignableFrom(stype) || CharSequence.class.isAssignableFrom(stype)) {
return stype.getSimpleName();
}
return "";
} else if (encodeable instanceof MapEncoder) {
return first ? null : "";
} else {
return null;
}
}
private static Object formatExample(String example, Class type, Type genericType) {
if (example == null || example.isEmpty()) return null;
if (type == Flipper.class) {
return new Flipper();
} else if (TYPE_RETRESULT_OBJECT.equals(genericType)) {
return RetResult.success();
} else if (TYPE_RETRESULT_STRING.equals(genericType)) {
return RetResult.success();
} else if (TYPE_RETRESULT_INTEGER.equals(genericType)) {
return RetResult.success(0);
} else if (TYPE_RETRESULT_LONG.equals(genericType)) {
return RetResult.success(0L);
}
return example;
}
}

View File

@@ -1,53 +1,69 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
/** /**
* Application启动和关闭时的监听事件 <br> * Application启动和关闭时的监听事件 <br>
* 只能通过application.xml配置 * 只能通过application.xml配置
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public interface ApplicationListener { public interface ApplicationListener {
/** /**
* 初始化方法 * 初始化方法
* *
* @param config 配置参数 * @param config 配置参数
*/ */
default void init(AnyValue config) { default void init(AnyValue config) {
} }
/** /**
* Application 在运行start前调用 * Application 在运行start前调用
* *
* @param application Application * @param application Application
*/ */
default void preStart(Application application) { default void preStart(Application application) {
} }
/** /**
* Application 在运行start后调用 * Application 在运行start后调用
* *
* @param application Application * @param application Application
*/ */
default void postStart(Application application) { default void postStart(Application application) {
} }
/** /**
* Application 在运行shutdown前调用 * Application 在运行Compile前调用
* *
* @param application Application * @param application Application
*/ */
default void preShutdown(Application application) { default void preCompile(Application application) {
} }
}
/**
* Application 在运行Compile后调用
*
* @param application Application
*/
default void postCompile(Application application) {
}
/**
* Application 在运行shutdown前调用
*
* @param application Application
*/
default void preShutdown(Application application) {
}
}

View File

@@ -1,366 +1,372 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import java.io.*; import org.redkale.util.RedkaleClassLoader;
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*; import java.io.*;
import java.time.*; import java.nio.file.*;
import java.util.*; import static java.nio.file.StandardCopyOption.*;
import java.util.concurrent.*; import java.time.*;
import java.util.concurrent.atomic.*; import java.util.*;
import java.util.logging.*; import java.util.concurrent.*;
import java.util.logging.Formatter; import java.util.concurrent.atomic.*;
import java.util.regex.Pattern; import java.util.logging.*;
import java.util.logging.Formatter;
/** import java.util.regex.Pattern;
* 自定义的日志输出类
* <p> /**
* 详情见: https://redkale.org * 自定义的日志输出类
* * <p>
* @author zhangjx * 详情见: https://redkale.org
*/ *
@SuppressWarnings("unchecked") * @author zhangjx
public class LogFileHandler extends Handler { */
@SuppressWarnings("unchecked")
/** public class LoggingFileHandler extends Handler {
* SNCP的日志输出Handler
*/ //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 class SncpLogFileHandler extends LogFileHandler { 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";
@Override /**
public String getPrefix() { * SNCP的日志输出Handler
return "sncp-"; */
} public static class LoggingSncpFileHandler extends LoggingFileHandler {
}
@Override
/** public String getPrefix() {
* 默认的日志时间格式化类 return "sncp-";
* }
*/ }
public static class LoggingFormater extends Formatter {
/**
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n"; * 默认的日志时间格式化类
* 与SimpleFormatter的区别在于level不使用本地化
@Override *
public String format(LogRecord log) { */
String source; public static class LoggingFormater extends Formatter {
if (log.getSourceClassName() != null) {
source = log.getSourceClassName(); @Override
if (log.getSourceMethodName() != null) { public String format(LogRecord log) {
source += " " + log.getSourceMethodName(); String source;
} if (log.getSourceClassName() != null) {
} else { source = log.getSourceClassName();
source = log.getLoggerName(); if (log.getSourceMethodName() != null) {
} source += " " + log.getSourceMethodName();
String message = formatMessage(log); }
String throwable = ""; } else {
if (log.getThrown() != null) { source = log.getLoggerName();
StringWriter sw = new StringWriter(); }
PrintWriter pw = new PrintWriter(sw) { String message = formatMessage(log);
@Override String throwable = "";
public void println() { if (log.getThrown() != null) {
super.print("\r\n"); StringWriter sw = new StringWriter();
} PrintWriter pw = new PrintWriter(sw) {
}; @Override
pw.println(); public void println() {
log.getThrown().printStackTrace(pw); super.print("\r\n");
pw.close(); }
throwable = sw.toString(); };
} pw.println();
return String.format(format, log.getThrown().printStackTrace(pw);
System.currentTimeMillis(), pw.close();
source, throwable = sw.toString();
log.getLoggerName(), }
log.getLevel().getName(), return String.format(FORMATTER_FORMAT,
message, System.currentTimeMillis(),
throwable); source,
} log.getLoggerName(),
} log.getLevel().getName(),
message,
public static void initDebugLogConfig() { throwable);
try { }
ByteArrayOutputStream out = new ByteArrayOutputStream(); }
final PrintStream ps = new PrintStream(out);
ps.println("handlers = java.util.logging.ConsoleHandler"); public static void initDebugLogConfig() {
ps.println(".level = FINEST"); try {
ps.println("jdk.level = INFO"); ByteArrayOutputStream out = new ByteArrayOutputStream();
ps.println("sun.level = INFO"); final PrintStream ps = new PrintStream(out);
ps.println("com.sun.level = INFO"); ps.println("handlers = java.util.logging.ConsoleHandler");
ps.println("javax.level = INFO"); ps.println(".level = FINEST");
ps.println("java.util.logging.ConsoleHandler.level = FINEST"); ps.println("jdk.level = INFO");
ps.println("java.util.logging.ConsoleHandler.formatter = " + LogFileHandler.LoggingFormater.class.getName()); ps.println("sun.level = INFO");
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray())); ps.println("com.sun.level = INFO");
} catch (Exception e) { ps.println("javax.level = INFO");
} ps.println("java.util.logging.ConsoleHandler.level = FINEST");
} ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName());
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue(); } catch (Exception e) {
}
private String pattern; }
private String unusual; //不为null表示将 WARNINGSEVERE 级别的日志写入单独的文件中 protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
private int limit; //文件大小限制 private String pattern;
private final AtomicInteger logindex = new AtomicInteger(); private String unusual; //不为null表示将 WARNINGSEVERE 级别的日志写入单独的文件中
private final AtomicInteger logunusualindex = new AtomicInteger(); private int limit; //文件大小限制
private int count = 1; //文件限制 private final AtomicInteger logindex = new AtomicInteger();
private long tomorrow; private final AtomicInteger logunusualindex = new AtomicInteger();
private boolean append; private int count = 1; //文件限制
private Pattern denyreg; private long tomorrow;
private final AtomicLong loglength = new AtomicLong(); private boolean append;
private final AtomicLong logunusuallength = new AtomicLong(); private Pattern denyreg;
private File logfile; private final AtomicLong loglength = new AtomicLong();
private File logunusualfile; private final AtomicLong logunusuallength = new AtomicLong();
private OutputStream logstream; private File logfile;
private OutputStream logunusualstream; private File logunusualfile;
public LogFileHandler() { private OutputStream logstream;
updateTomorrow();
configure(); private OutputStream logunusualstream;
open();
} public LoggingFileHandler() {
updateTomorrow();
private void updateTomorrow() { configure();
Calendar cal = Calendar.getInstance(); open();
cal.set(Calendar.HOUR_OF_DAY, 0); }
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0); private void updateTomorrow() {
cal.set(Calendar.MILLISECOND, 0); Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 1); cal.set(Calendar.HOUR_OF_DAY, 0);
long t = cal.getTimeInMillis(); cal.set(Calendar.MINUTE, 0);
if (this.tomorrow != t) logindex.set(0); cal.set(Calendar.SECOND, 0);
this.tomorrow = t; cal.set(Calendar.MILLISECOND, 0);
} cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis();
private void open() { if (this.tomorrow != t) logindex.set(0);
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread"; this.tomorrow = t;
new Thread() { }
{
setName(name); private void open() {
setDaemon(true); final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
} new Thread() {
{
@Override setName(name);
public void run() { setDaemon(true);
while (true) { }
try {
LogRecord log = logqueue.take(); @Override
final boolean bigger = (limit > 0 && limit <= loglength.get()); public void run() {
final boolean changeday = tomorrow <= log.getMillis(); while (true) {
if (bigger || changeday) { try {
updateTomorrow(); LogRecord log = logqueue.take();
if (logstream != null) { final boolean bigger = (limit > 0 && limit <= loglength.get());
logstream.close(); final boolean changeday = tomorrow <= log.getMillis();
if (bigger) { if (bigger || changeday) {
for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) { updateTomorrow();
File greater = new File(logfile.getPath() + "." + i); if (logstream != null) {
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); logstream.close();
} if (bigger) {
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) {
} else { File greater = new File(logfile.getPath() + "." + i);
if (logfile.exists() && logfile.length() < 1) logfile.delete(); if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
logstream = null; Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} } else {
} if (logfile.exists() && logfile.length() < 1) logfile.delete();
if (unusual != null && changeday && logunusualstream != null) { }
logunusualstream.close(); logstream = null;
if (limit > 0 && limit <= logunusuallength.get()) { }
for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) { }
File greater = new File(logunusualfile.getPath() + "." + i); if (unusual != null && changeday && logunusualstream != null) {
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); logunusualstream.close();
} if (limit > 0 && limit <= logunusuallength.get()) {
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) {
} else { File greater = new File(logunusualfile.getPath() + "." + i);
if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete(); if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} }
logunusualstream = null; Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} } else {
if (logstream == null) { if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete();
logindex.incrementAndGet(); }
java.time.LocalDate date = LocalDate.now(); logunusualstream = null;
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(); if (logstream == null) {
loglength.set(logfile.length()); logindex.incrementAndGet();
logstream = new FileOutputStream(logfile, append); java.time.LocalDate date = LocalDate.now();
} logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
if (unusual != null && logunusualstream == null) { logfile.getParentFile().mkdirs();
logunusualindex.incrementAndGet(); loglength.set(logfile.length());
java.time.LocalDate date = LocalDate.now(); logstream = new FileOutputStream(logfile, append);
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(); if (unusual != null && logunusualstream == null) {
logunusuallength.set(logunusualfile.length()); logunusualindex.incrementAndGet();
logunusualstream = new FileOutputStream(logunusualfile, append); java.time.LocalDate date = LocalDate.now();
} 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();
String message = getFormatter().format(log); logunusuallength.set(logunusualfile.length());
String encoding = getEncoding(); logunusualstream = new FileOutputStream(logunusualfile, append);
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); }
logstream.write(bytes); //----------------------写日志-------------------------
loglength.addAndGet(bytes.length); String message = getFormatter().format(log);
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) { String encoding = getEncoding();
logunusualstream.write(bytes); byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
logunusuallength.addAndGet(bytes.length); logstream.write(bytes);
} loglength.addAndGet(bytes.length);
} catch (Exception e) { if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
ErrorManager err = getErrorManager(); logunusualstream.write(bytes);
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); logunusuallength.addAndGet(bytes.length);
} }
} } catch (Exception e) {
ErrorManager err = getErrorManager();
} if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
}.start(); }
} }
public String getPrefix() { }
return ""; }.start();
} }
private void configure() { public String getPrefix() {
LogManager manager = LogManager.getLogManager(); return "";
String cname = LogFileHandler.class.getName(); }
this.pattern = manager.getProperty(cname + ".pattern");
if (this.pattern == null) { private void configure() {
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log"; LogManager manager = LogManager.getLogManager();
} else { String cname = LoggingFileHandler.class.getName();
int pos = this.pattern.lastIndexOf('/'); this.pattern = manager.getProperty(cname + ".pattern");
if (pos > 0) { if (this.pattern == null) {
this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1); this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
} else { } else {
this.pattern = getPrefix() + this.pattern; int pos = this.pattern.lastIndexOf('/');
} if (pos > 0) {
} this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1);
String unusualstr = manager.getProperty(cname + ".unusual"); } else {
if (unusualstr != null) { this.pattern = getPrefix() + this.pattern;
int pos = unusualstr.lastIndexOf('/'); }
if (pos > 0) { }
this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1); String unusualstr = manager.getProperty(cname + ".unusual");
} else { if (unusualstr != null) {
this.unusual = getPrefix() + unusualstr; int pos = unusualstr.lastIndexOf('/');
} if (pos > 0) {
} this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1);
String limitstr = manager.getProperty(cname + ".limit"); } else {
try { this.unusual = getPrefix() + unusualstr;
if (limitstr != null) { }
limitstr = limitstr.toUpperCase(); }
boolean g = limitstr.indexOf('G') > 0; String limitstr = manager.getProperty(cname + ".limit");
boolean m = limitstr.indexOf('M') > 0; try {
boolean k = limitstr.indexOf('K') > 0; if (limitstr != null) {
int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", ""))); limitstr = limitstr.toUpperCase();
if (g) { boolean g = limitstr.indexOf('G') > 0;
ls *= 1024 * 1024 * 1024; boolean m = limitstr.indexOf('M') > 0;
} else if (m) { boolean k = limitstr.indexOf('K') > 0;
ls *= 1024 * 1024; int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", "")));
} else if (k) { if (g) {
ls *= 1024; ls *= 1024 * 1024 * 1024;
} } else if (m) {
this.limit = ls; ls *= 1024 * 1024;
} } else if (k) {
} catch (Exception e) { ls *= 1024;
} }
String countstr = manager.getProperty(cname + ".count"); this.limit = ls;
try { }
if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr))); } catch (Exception e) {
} catch (Exception e) { }
} String countstr = manager.getProperty(cname + ".count");
String appendstr = manager.getProperty(cname + ".append"); try {
try { if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); } catch (Exception e) {
} catch (Exception e) { }
} String appendstr = manager.getProperty(cname + ".append");
String levelstr = manager.getProperty(cname + ".level"); try {
try { if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
if (levelstr != null) { } catch (Exception e) {
Level l = Level.parse(levelstr); }
setLevel(l != null ? l : Level.ALL); String levelstr = manager.getProperty(cname + ".level");
} try {
} catch (Exception e) { if (levelstr != null) {
} Level l = Level.parse(levelstr);
String filterstr = manager.getProperty(cname + ".filter"); setLevel(l != null ? l : Level.ALL);
try { }
if (filterstr != null) { } catch (Exception e) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr); }
setFilter((Filter) clz.getDeclaredConstructor().newInstance()); String filterstr = manager.getProperty(cname + ".filter");
} try {
} catch (Exception e) { if (filterstr != null) {
} Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
String formatterstr = manager.getProperty(cname + ".formatter"); RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
try { setFilter((Filter) clz.getDeclaredConstructor().newInstance());
if (formatterstr != null) { }
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr); } catch (Exception e) {
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance()); }
} String formatterstr = manager.getProperty(cname + ".formatter");
} catch (Exception e) { try {
} if (formatterstr != null) {
if (getFormatter() == null) setFormatter(new SimpleFormatter()); Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
String encodingstr = manager.getProperty(cname + ".encoding"); setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
try { }
if (encodingstr != null) setEncoding(encodingstr); } catch (Exception e) {
} catch (Exception e) { }
} if (getFormatter() == null) setFormatter(new SimpleFormatter());
String denyregstr = manager.getProperty(cname + ".denyreg"); String encodingstr = manager.getProperty(cname + ".encoding");
try { try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) { if (encodingstr != null) setEncoding(encodingstr);
denyreg = Pattern.compile(denyregstr); } catch (Exception e) {
} }
} catch (Exception e) {
} String denyregstr = manager.getProperty(cname + ".denyreg");
} try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
@Override denyreg = Pattern.compile(denyregstr);
public void publish(LogRecord log) { }
final String sourceClassName = log.getSourceClassName(); } catch (Exception e) {
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; @Override
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName()); public void publish(LogRecord log) {
log.setSourceMethodName(ses[i].getMethodName()); final String sourceClassName = log.getSourceClassName();
break; if (sourceClassName == null || true) {
} StackTraceElement[] ses = new Throwable().getStackTrace();
} else { for (int i = 2; i < ses.length; i++) {
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName); if (ses[i].getClassName().startsWith("java.util.logging")) continue;
} log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; log.setSourceMethodName(ses[i].getMethodName());
logqueue.offer(log); break;
} }
} else {
@Override log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
public void flush() { }
try { if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
if (logstream != null) logstream.flush(); logqueue.offer(log);
} catch (Exception e) { }
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE); @Override
} public void flush() {
} try {
if (logstream != null) logstream.flush();
@Override } catch (Exception e) {
public void close() throws SecurityException { ErrorManager err = getErrorManager();
try { if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE);
if (logstream != null) logstream.close(); }
} catch (Exception e) { }
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE); @Override
} public void close() throws SecurityException {
} try {
if (logstream != null) logstream.close();
} } catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE);
}
}
}

View File

@@ -1,399 +1,446 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.logging.Level; import java.util.logging.Level;
import javax.annotation.*; import java.util.stream.Stream;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR; import javax.annotation.*;
import org.redkale.boot.ClassFilter.FilterEntry; import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
import org.redkale.cluster.ClusterAgent; import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.mq.MessageAgent; import org.redkale.cluster.ClusterAgent;
import org.redkale.net.*; import org.redkale.mq.MessageAgent;
import org.redkale.net.http.*; import org.redkale.net.*;
import org.redkale.net.sncp.Sncp; import org.redkale.net.http.*;
import org.redkale.service.*; import org.redkale.net.sncp.Sncp;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.service.*;
import org.redkale.util.*; import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.watch.*; import org.redkale.util.*;
import org.redkale.watch.*;
/**
* HTTP Server节点的配置Server /**
* * HTTP Server节点的配置Server
* <p> *
* 详情见: https://redkale.org * <p>
* * 详情见: https://redkale.org
* @author zhangjx *
*/ * @author zhangjx
@NodeProtocol("HTTP") */
public class NodeHttpServer extends NodeServer { @NodeProtocol("HTTP")
public class NodeHttpServer extends NodeServer {
protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
protected final boolean rest; //是否加载REST服务 为true加载rest节点信息并将所有可REST化的Service生成RestServlet
protected final HttpServer httpServer;
protected final HttpServer httpServer;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf)); public NodeHttpServer(Application application, AnyValue serconf) {
this.httpServer = (HttpServer) server; super(application, createServer(application, serconf));
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null; this.httpServer = (HttpServer) server;
} this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
}
private static Server createServer(Application application, AnyValue serconf) {
return new HttpServer(application, application.getStartTime(), application.getResourceFactory().createChild()); private static Server createServer(Application application, AnyValue serconf) {
} return new HttpServer(application, application.getStartTime(), application.getResourceFactory().createChild());
}
public HttpServer getHttpServer() {
return httpServer; public HttpServer getHttpServer() {
} return httpServer;
}
@Override
public InetSocketAddress getSocketAddress() { @Override
return httpServer == null ? null : httpServer.getSocketAddress(); public InetSocketAddress getSocketAddress() {
} return httpServer == null ? null : httpServer.getSocketAddress();
}
@Override
@SuppressWarnings("unchecked") @Override
protected ClassFilter<Service> createServiceClassFilter() { @SuppressWarnings("unchecked")
return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service"); protected ClassFilter<Service> createServiceClassFilter() {
} return createClassFilter(this.sncpGroup, null, Service.class, new Class[]{org.redkale.watch.WatchService.class}, Annotation.class, "services", "service");
}
@Override
@SuppressWarnings("unchecked") @Override
protected ClassFilter<Filter> createFilterClassFilter() { @SuppressWarnings("unchecked")
return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter"); protected ClassFilter<Filter> createFilterClassFilter() {
} return createClassFilter(null, null, HttpFilter.class, new Class[]{WatchFilter.class}, null, "filters", "filter");
}
@Override
@SuppressWarnings("unchecked") @Override
protected ClassFilter<Servlet> createServletClassFilter() { @SuppressWarnings("unchecked")
return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet"); protected ClassFilter<Servlet> createServletClassFilter() {
} return createClassFilter(null, WebServlet.class, HttpServlet.class, new Class[]{WatchServlet.class}, null, "servlets", "servlet");
}
@Override
protected ClassFilter createOtherClassFilter() { @Override
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket"); protected ClassFilter createOtherClassFilter() {
} return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
}
@Override
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception { @Override
super.loadService(serviceFilter, otherFilter); protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
initWebSocketService(); super.loadService(serviceFilter, otherFilter);
} initWebSocketService();
}
@Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception { @Override
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter); protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
} if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
}
@Override
@SuppressWarnings("unchecked") @Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception { @SuppressWarnings("unchecked")
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter); protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
} if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
}
private void initWebSocketService() {
final NodeServer self = this; private void initWebSocketService() {
final ResourceFactory regFactory = application.getResourceFactory(); final NodeServer self = this;
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务 final ResourceFactory regFactory = application.getResourceFactory();
try { resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
if (field.getAnnotation(Resource.class) == null) return; try {
if (!(src instanceof WebSocketServlet)) return; if (field.getAnnotation(Resource.class) == null) return;
ResourceFactory.ResourceLoader loader = null; if (!(src instanceof WebSocketServlet)) return;
ResourceFactory sncpResFactory = null; ResourceFactory.ResourceLoader loader = null;
for (NodeServer ns : application.servers) { ResourceFactory sncpResFactory = null;
if (!ns.isSNCP()) continue; for (NodeServer ns : application.servers) {
sncpResFactory = ns.resourceFactory; if (!ns.isSNCP()) continue;
loader = sncpResFactory.findLoader(WebSocketNode.class, field); sncpResFactory = ns.resourceFactory;
if (loader != null) break; loader = sncpResFactory.findLoader(WebSocketNode.class, field);
} if (loader != null) break;
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment); }
synchronized (regFactory) { if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); synchronized (regFactory) {
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) { Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class)); if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class)); resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class)); resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
} resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
if (nodeService == null) { }
MessageAgent messageAgent = null; if (nodeService == null) {
try { MessageAgent messageAgent = null;
Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); try {
c.setAccessible(true); Field c = WebSocketServlet.class.getDeclaredField("messageAgent");
messageAgent = (MessageAgent) c.get(src); c.setAccessible(true);
} catch (Exception ex) { messageAgent = (MessageAgent) c.get(src);
logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); } catch (Exception ex) {
} logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null); }
regFactory.register(resourceName, WebSocketNode.class, nodeService); nodeService = Sncp.createLocalService(serverClassLoader, resourceName, WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
} regFactory.register(resourceName, WebSocketNode.class, nodeService);
resourceFactory.inject(nodeService, self); }
field.set(src, nodeService); resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService); field.set(src, nodeService);
} logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
} catch (Exception e) { }
logger.log(Level.SEVERE, "WebSocketNode inject error", e); } catch (Exception e) {
} logger.log(Level.SEVERE, "WebSocketNode inject error", e);
}, WebSocketNode.class); }
} }, WebSocketNode.class);
}
@SuppressWarnings("unchecked")
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception { @SuppressWarnings("unchecked")
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final String localThreadName = "[" + Thread.currentThread().getName() + "] "; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys()); final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
for (FilterEntry<? extends Filter> en : list) { List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType(); for (FilterEntry<? extends Filter> en : list) {
if (Modifier.isAbstract(clazz.getModifiers())) continue; Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
final HttpFilter filter = clazz.getDeclaredConstructor().newInstance(); if (Modifier.isAbstract(clazz.getModifiers())) continue;
resourceFactory.inject(filter, this); RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty(); final HttpFilter filter = clazz.getDeclaredConstructor().newInstance();
this.httpServer.addHttpFilter(filter, filterConf); resourceFactory.inject(filter, this);
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR); DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
} this.httpServer.addHttpFilter(filter, filterConf);
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
} }
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
@SuppressWarnings("unchecked") }
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets"); @SuppressWarnings("unchecked")
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", ""); RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName());
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1); RedkaleClassLoader.putReflectionPublicClasses(HttpPrepareServlet.class.getName());
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0; RedkaleClassLoader.putReflectionDeclaredConstructors(HttpResourceServlet.class, HttpResourceServlet.class.getName());
final String prefix = prefix0; final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
final String localThreadName = "[" + Thread.currentThread().getName() + "] "; final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys()); String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", "");
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType()); if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType()); final String prefix = prefix0;
if (ws1 == ws2) { final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
Priority p1 = o1.getType().getAnnotation(Priority.class); List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
Priority p2 = o2.getType().getAnnotation(Priority.class); list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0; boolean ws2 = WebSocketServlet.class.isAssignableFrom(o2.getType());
} if (ws1 == ws2) {
return ws1 ? -1 : 1; Priority p1 = o1.getType().getAnnotation(Priority.class);
}); Priority p2 = o2.getType().getAnnotation(Priority.class);
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>(); int v = (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
for (FilterEntry<? extends Servlet> en : list) { return v == 0 ? o1.getType().getName().compareTo(o2.getType().getName()) : 0;
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType(); }
if (Modifier.isAbstract(clazz.getModifiers())) continue; return ws1 ? -1 : 1;
WebServlet ws = clazz.getAnnotation(WebServlet.class); });
if (ws == null) continue; final long starts = System.currentTimeMillis();
if (ws.value().length == 0) { final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName()); for (FilterEntry<? extends Servlet> en : list) {
continue; Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
} if (Modifier.isAbstract(clazz.getModifiers())) continue;
final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance(); if (clazz.getAnnotation(Rest.RestDyn.class) != null) continue; //动态生成的跳过
resourceFactory.inject(servlet, this); WebServlet ws = clazz.getAnnotation(WebServlet.class);
final String[] mappings = ws.value(); if (ws == null) continue;
String pref = ws.repair() ? prefix : ""; if (ws.value().length == 0) {
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty(); logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName());
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings); continue;
if (ss != null) { }
for (int i = 0; i < mappings.length; i++) { RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
mappings[i] = pref + mappings[i]; final HttpServlet servlet = clazz.getDeclaredConstructor().newInstance();
} resourceFactory.inject(servlet, this);
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings)); final String[] mappings = ws.value();
} String pref = ws.repair() ? prefix : "";
} DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
int max = 0; this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null && sb != null) { if (ss != null) {
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey())); for (int i = 0; i < mappings.length; i++) {
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { mappings[i] = pref + mappings[i];
if (as.getKey().length() > max) max = as.getKey().length(); }
} ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { }
sb.append(localThreadName).append(" Load ").append(as.getKey()); }
for (int i = 0; i < max - as.getKey().length(); i++) { final List<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new ArrayList<>();
sb.append(' '); final List<AbstractMap.SimpleEntry<String, String[]>> webss = sb == null ? null : new ArrayList<>();
} if (rest && serverConf != null) {
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); final List<Object> restedObjects = new ArrayList<>();
} for (AnyValue restConf : serverConf.getAnyValues("rest")) {
} loadRestServlet(webSocketFilter, restConf, restedObjects, sb, rests, webss);
if (rest && serverConf != null) { }
final List<Object> restedObjects = new ArrayList<>(); }
for (AnyValue restConf : serverConf.getAnyValues("rest")) { int max = 0;
loadRestServlet(webSocketFilter, restConf, restedObjects, sb); if (ss != null && sb != null) {
} int maxTypeLength = 0;
} int maxNameLength = 0;
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim()); if (rests != null) {
} for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
int pos = en.getKey().indexOf('#');
@SuppressWarnings("unchecked") if (pos > maxTypeLength) maxTypeLength = pos;
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb) throws Exception { int len = en.getKey().length() - pos - 1;
if (!rest) return; if (len > maxNameLength) maxNameLength = len;
if (restConf == null) return; //不存在REST服务 }
}
final long starts = System.currentTimeMillis(); if (webss != null) {
String prefix0 = restConf.getValue("path", ""); for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1); int pos = en.getKey().indexOf('#');
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0; if (pos > maxTypeLength) maxTypeLength = pos;
int len = en.getKey().length() - pos - 1;
final String localThreadName = "[" + Thread.currentThread().getName() + "] "; if (len > maxNameLength) maxNameLength = len;
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>(); }
String mqname = restConf.getValue("mq"); }
MessageAgent agent0 = null; if (rests != null) {
if (mqname != null) { for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
agent0 = application.getMessageAgent(mqname); StringBuilder sub = new StringBuilder();
if (agent0 == null) throw new RuntimeException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")"); int pos = en.getKey().indexOf('#');
} sub.append("RestDynServlet (type=").append(en.getKey().substring(0, pos));
final MessageAgent messageAgent = agent0; for (int i = 0; i < maxTypeLength - pos; i++) {
if (messageAgent != null) prefix0 = ""; //开启MQ时,prefix字段失效 sub.append(' ');
final String prefix = prefix0; }
final boolean autoload = restConf.getBoolValue("autoload", true); sub.append(", name='").append(en.getKey().substring(pos + 1));
{ //加载RestService for (int i = 0; i < maxNameLength - pos; i++) {
String userTypeStr = restConf.getValue("usertype"); sub.append(' ');
final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr); }
sub.append("')");
final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName())); ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
final Set<String> includeValues = new HashSet<>(); }
final Set<String> excludeValues = new HashSet<>(); }
for (AnyValue item : restConf.getAnyValues("service")) { if (webss != null) {
if (item.getBoolValue("ignore", false)) { for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
excludeValues.add(item.getValue("value", "")); StringBuilder sub = new StringBuilder();
} else { int pos = en.getKey().indexOf('#');
includeValues.add(item.getValue("value", "")); sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos));
} for (int i = 0; i < maxTypeLength - pos; i++) {
} sub.append(' ');
}
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues); sub.append(", name='").append(en.getKey().substring(pos + 1));
final boolean finest = logger.isLoggable(Level.FINEST); for (int i = 0; i < maxNameLength - pos; i++) {
final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size()); sub.append(' ');
super.interceptorServices.stream().parallel().forEach((service) -> { }
try { sub.append("')");
final Class stype = Sncp.getServiceType(service); ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
final String name = Sncp.getResourceName(service); }
RestService rs = (RestService) stype.getAnnotation(RestService.class); }
if (rs == null || rs.ignore()) return; ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
final String stypename = stype.getName(); if (as.getKey().length() > max) max = as.getKey().length();
if (!autoload && !includeValues.contains(stypename)) return; }
if (!restFilter.accept(stypename)) return; for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
synchronized (restedObjects) { sb.append(localThreadName).append("Load ").append(as.getKey());
if (restedObjects.contains(service)) { for (int i = 0; i < max - as.getKey().length(); i++) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore"); sb.append(' ');
return; }
} sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
restedObjects.add(service); //避免重复创建Rest对象 }
} sb.append(localThreadName).append("All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix); }
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
String prefix2 = prefix; }
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = ""; @SuppressWarnings("unchecked")
resourceFactory.inject(servlet, NodeHttpServer.this); protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb,
dynServletMap.put(service, servlet); final List<AbstractMap.SimpleEntry<String, String[]>> rests, final List<AbstractMap.SimpleEntry<String, String[]>> webss) throws Exception {
if (messageAgent != null) messageAgent.putService(this, service, servlet); if (!rest) return;
//if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet); if (restConf == null) return; //不存在REST服务
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value(); String prefix0 = restConf.getValue("path", "");
for (int i = 0; i < mappings.length; i++) { if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
mappings[i] = prefix2 + mappings[i]; if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
}
synchronized (ss) { final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName() + "(rest.name='" + name + "')", mappings)); String mqname = restConf.getValue("mq");
} MessageAgent agent0 = null;
} if (mqname != null) {
} finally { agent0 = application.getMessageAgent(mqname);
scdl.countDown(); if (agent0 == null) throw new RuntimeException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")");
} }
}); final MessageAgent messageAgent = agent0;
scdl.await(); if (messageAgent != null) prefix0 = ""; //开启MQ时,prefix字段失效
} final String prefix = prefix0;
if (webSocketFilter != null) { //加载RestWebSocket final boolean autoload = restConf.getBoolValue("autoload", true);
final Set<String> includeValues = new HashSet<>(); { //加载RestService
final Set<String> excludeValues = new HashSet<>(); String userTypeStr = restConf.getValue("usertype");
for (AnyValue item : restConf.getAnyValues("websocket")) { final Class userType = userTypeStr == null ? null : this.serverClassLoader.loadClass(userTypeStr);
if (item.getBoolValue("ignore", false)) {
excludeValues.add(item.getValue("value", "")); final Class baseServletType = this.serverClassLoader.loadClass(restConf.getValue("base", HttpServlet.class.getName()));
} else { final Set<String> includeValues = new HashSet<>();
includeValues.add(item.getValue("value", "")); final Set<String> excludeValues = new HashSet<>();
} for (AnyValue item : restConf.getAnyValues("service")) {
} if (item.getBoolValue("ignore", false)) {
excludeValues.add(item.getValue("value", ""));
final ClassFilter restFilter = ClassFilter.create(null, restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues); } else {
final boolean finest = logger.isLoggable(Level.FINEST); includeValues.add(item.getValue("value", ""));
}
List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys()); }
for (FilterEntry<? extends WebSocket> en : list) {
Class<WebSocket> clazz = (Class<WebSocket>) en.getType(); final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
if (Modifier.isAbstract(clazz.getModifiers())) { final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore"); Stream<Service> stream = super.interceptorServices.stream();
continue; if (!application.isCompileMode()) stream = stream.parallel(); //不能并行否则在maven plugin运行环境下ClassLoader不对
} stream.forEach((service) -> {
if (Modifier.isFinal(clazz.getModifiers())) { try {
logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore"); final Class stype = Sncp.getServiceType(service);
continue; final String name = Sncp.getResourceName(service);
} RestService rs = (RestService) stype.getAnnotation(RestService.class);
final Class<? extends WebSocket> stype = en.getType(); if (rs == null || rs.ignore()) return;
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
if (rs == null || rs.ignore()) return; final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
final String stypename = stype.getName(); if (!restFilter.accept(stypename)) return;
if (!autoload && !includeValues.contains(stypename)) return; synchronized (restedObjects) {
if (!restFilter.accept(stypename)) return; if (restedObjects.contains(service)) {
if (restedObjects.contains(stype)) { logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore"); return;
return; }
} restedObjects.add(service); //避免重复创建Rest对象
restedObjects.add(stype); //避免重复创建Rest对象 }
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty()); HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
String prefix2 = prefix; String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = ""; if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this); resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet"); dynServletMap.put(service, servlet);
if (ss != null) { if (messageAgent != null) messageAgent.putService(this, service, servlet);
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value(); //if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
for (int i = 0; i < mappings.length; i++) { if (rests != null) {
mappings[i] = prefix2 + mappings[i]; String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
} for (int i = 0; i < mappings.length; i++) {
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings)); mappings[i] = prefix2 + mappings[i];
} }
} synchronized (rests) {
} rests.add(new AbstractMap.SimpleEntry<>(Sncp.getServiceType(service).getName() + "#" + name, mappings));
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent); }
//输出信息 }
if (ss != null && !ss.isEmpty() && sb != null) { } finally {
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey())); scdl.countDown();
int max = 0; }
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { });
if (as.getKey().length() > max) max = as.getKey().length(); scdl.await();
} }
for (AbstractMap.SimpleEntry<String, String[]> as : ss) { if (webSocketFilter != null) { //加载RestWebSocket
sb.append(localThreadName).append(" Load ").append(as.getKey()); final Set<String> includeValues = new HashSet<>();
for (int i = 0; i < max - as.getKey().length(); i++) { final Set<String> excludeValues = new HashSet<>();
sb.append(' '); for (AnyValue item : restConf.getAnyValues("websocket")) {
} if (item.getBoolValue("ignore", false)) {
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR); excludeValues.add(item.getValue("value", ""));
} } else {
sb.append(localThreadName).append(" All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR); includeValues.add(item.getValue("value", ""));
} }
} }
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
@Override //loadServlet执行之后调用 final boolean finest = logger.isLoggable(Level.FINEST);
protected void postLoadServlets() {
final ClusterAgent cluster = application.clusterAgent; List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys());
if (cluster != null) { for (FilterEntry<? extends WebSocket> en : list) {
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class); Class<WebSocket> clazz = (Class<WebSocket>) en.getType();
String protocol = pros.value().toUpperCase(); if (Modifier.isAbstract(clazz.getModifiers())) {
if (!cluster.containsProtocol(protocol)) return; logger.log(Level.FINE, clazz.getName() + " cannot abstract on rest websocket, so ignore");
if (!cluster.containsPort(server.getSocketAddress().getPort())) return; continue;
cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>()); }
} if (Modifier.isFinal(clazz.getModifiers())) {
} logger.log(Level.FINE, clazz.getName() + " cannot final on rest websocket, so ignore");
continue;
@Override }
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) { final Class<? extends WebSocket> stype = en.getType();
cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>()); if (stype.getAnnotation(Rest.RestDyn.class) != null) continue;
} RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
} if (rs == null || rs.ignore()) continue;
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) continue;
if (!restFilter.accept(stypename)) continue;
if (restedObjects.contains(stype)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
continue;
}
restedObjects.add(stype); //避免重复创建Rest对象
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty());
if (servlet == null) continue; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet");
if (webss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (webss) {
webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + "#" + rs.name(), mappings));
}
}
}
}
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent);
}
@Override //loadServlet执行之后调用
protected void postLoadServlets() {
final ClusterAgent cluster = application.clusterAgent;
if (!application.isCompileMode() && cluster != null) {
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
String protocol = pros.value().toUpperCase();
if (!cluster.containsProtocol(protocol)) return;
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>());
}
}
@Override
protected void afterClusterDeregisterOnPreDestroyServices(ClusterAgent cluster, String protocol) {
cluster.deregister(this, protocol, dynServletMap.keySet(), new HashSet<>());
}
}

View File

@@ -1,38 +1,38 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
/** /**
* NodeServer的拦截类 * NodeServer的拦截类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class NodeInterceptor { public class NodeInterceptor {
/** * /** *
* Server.start之前调用 <br> * Server.start之前调用 <br>
* NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法 * NodeServer.start的部署是先执行NodeInterceptor.preStart再执行 Server.start 方法
* *
* @param server NodeServer * @param server NodeServer
*/ */
public void preStart(NodeServer server) { public void preStart(NodeServer server) {
} }
/** /**
* Server.shutdown之前调用 <br> * Server.shutdown之前调用 <br>
* NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.sshutdown 方法 * NodeServer.shutdown的部署是先执行NodeInterceptor.preShutdown再执行 Server.sshutdown 方法
* *
* @param server NodeServer * @param server NodeServer
*/ */
public void preShutdown(NodeServer server) { public void preShutdown(NodeServer server) {
} }
} }

View File

@@ -1,24 +1,24 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上 * 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface NodeProtocol { public @interface NodeProtocol {
String value(); String value();
} }

View File

@@ -1,122 +1,125 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.logging.Level; import java.util.logging.Level;
import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.mq.MessageAgent; import org.redkale.mq.MessageAgent;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* SNCP Server节点的配置Server * SNCP Server节点的配置Server
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@NodeProtocol("SNCP") @NodeProtocol("SNCP")
public class NodeSncpServer extends NodeServer { public class NodeSncpServer extends NodeServer {
protected final SncpServer sncpServer; protected final SncpServer sncpServer;
private NodeSncpServer(Application application, AnyValue serconf) { private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf)); super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server; this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null || application.singletonrun ? null : (agent, x) -> {//singleton模式下不生成SncpServlet this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton模式下不生成SncpServlet
if (x.getClass().getAnnotation(Local.class) != null) return; if (x.getClass().getAnnotation(Local.class) != null) return; //本地模式的Service不生成SncpServlet
SncpDynServlet servlet = sncpServer.addSncpServlet(x); SncpDynServlet servlet = sncpServer.addSncpServlet(x);
dynServletMap.put(x, servlet); dynServletMap.put(x, servlet);
if (agent != null) agent.putService(this, x, servlet); if (agent != null) agent.putService(this, x, servlet);
}; };
} }
public static NodeServer createNodeServer(Application application, AnyValue serconf) { public static NodeServer createNodeServer(Application application, AnyValue serconf) {
return new NodeSncpServer(application, serconf); return new NodeSncpServer(application, serconf);
} }
private static Server createServer(Application application, AnyValue serconf) { private static Server createServer(Application application, AnyValue serconf) {
return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild()); return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild());
} }
@Override @Override
public InetSocketAddress getSocketAddress() { public InetSocketAddress getSocketAddress() {
return sncpServer == null ? null : sncpServer.getSocketAddress(); return sncpServer == null ? null : sncpServer.getSocketAddress();
} }
public void consumerAccept(MessageAgent messageAgent, Service service) { public void consumerAccept(MessageAgent messageAgent, Service service) {
if (this.consumer != null) this.consumer.accept(messageAgent, service); if (this.consumer != null) this.consumer.accept(messageAgent, service);
} }
@Override @Override
public void init(AnyValue config) throws Exception { public void init(AnyValue config) throws Exception {
super.init(config); super.init(config);
//------------------------------------------------------------------- //-------------------------------------------------------------------
if (sncpServer == null) return; //调试时server才可能为null if (sncpServer == null) return; //调试时server才可能为null
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String localThreadName = "[" + Thread.currentThread().getName() + "] "; final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<SncpServlet> servlets = sncpServer.getSncpServlets(); List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets); Collections.sort(servlets);
for (SncpServlet en : servlets) { for (SncpServlet en : servlets) {
if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR); if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR);
} }
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
} }
@Override @Override
public boolean isSNCP() { public boolean isSNCP() {
return true; return true;
} }
public SncpServer getSncpServer() { public SncpServer getSncpServer() {
return sncpServer; return sncpServer;
} }
@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 (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter); if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception { protected void loadSncpFilter(final AnyValue servletsConf, 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());
for (FilterEntry<? extends Filter> en : list) { for (FilterEntry<? extends Filter> en : list) {
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType(); Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue; if (Modifier.isAbstract(clazz.getModifiers())) continue;
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance(); RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
resourceFactory.inject(filter, this); final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty(); resourceFactory.inject(filter, this);
this.sncpServer.addSncpFilter(filter, filterConf); DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR); this.sncpServer.addSncpFilter(filter, filterConf);
} if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); }
} if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception { @Override
} protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
@Override RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
@SuppressWarnings("unchecked") }
protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter"); @Override
} @SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() {
@Override return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter");
protected ClassFilter<Servlet> createServletClassFilter() { }
return null;
} @Override
protected ClassFilter<Servlet> createServletClassFilter() {
} return null;
}
}

View File

@@ -1,53 +1,53 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot; package org.redkale.boot;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.service.Service; import org.redkale.service.Service;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
import org.redkale.watch.*; import org.redkale.watch.*;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
@NodeProtocol("WATCH") @NodeProtocol("WATCH")
public class NodeWatchServer extends NodeHttpServer { public class NodeWatchServer extends NodeHttpServer {
public NodeWatchServer(Application application, AnyValue serconf) { public NodeWatchServer(Application application, AnyValue serconf) {
super(application, serconf); super(application, serconf);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Service> createServiceClassFilter() { protected ClassFilter<Service> createServiceClassFilter() {
return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service"); return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service");
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Filter> createFilterClassFilter() { protected ClassFilter<Filter> createFilterClassFilter() {
return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter"); return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter");
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected ClassFilter<Servlet> createServletClassFilter() { protected ClassFilter<Servlet> createServletClassFilter() {
return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet"); return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet");
} }
@Override @Override
protected ClassFilter createOtherClassFilter() { protected ClassFilter createOtherClassFilter() {
return null; return null;
} }
@Override @Override
public boolean isWATCH() { public boolean isWATCH() {
return true; return true;
} }
} }

View File

@@ -0,0 +1,86 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot;
import java.lang.reflect.Modifier;
import javax.persistence.Entity;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.Decodeable;
import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* 执行一次Application.run提前获取所有动态类
*
* @author zhangjx
* @since 2.5.0
*/
public class PrepareCompiler {
// public static void main(String[] args) throws Exception {
// new PrepareCompiler().run();
// }
public Application run() throws Exception {
final Application application = new Application(false, true, Application.loadAppConfig());
application.init();
for (ApplicationListener listener : application.listeners) {
listener.preStart(application);
}
for (ApplicationListener listener : application.listeners) {
listener.preCompile(application);
}
application.start();
final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent();
final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";");
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null);
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null);
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null);
ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter);
for (FilterEntry en : entityFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : beanFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : filterFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
try {
FilterNodeBean.load(clz);
} catch (Exception e) {
}
}
for (ApplicationListener listener : application.listeners) {
listener.postCompile(application);
}
application.shutdown();
return application;
}
}

View File

@@ -1,110 +1,110 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="UTF-8"><title>接口文档(apidoc生成)</title> <meta charset="UTF-8"><title>接口文档(apidoc生成)</title>
<style type="text/css"> <style type="text/css">
body {text-align: center;margin:auto;} body {text-align: center;margin:auto;}
a{text-decoration: none;} a{text-decoration: none;}
.table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;} .table {margin: auto;border-collapse: collapse;border-spacing: 0;display: block;width: 100%;overflow: auto;word-break: normal;word-break: keep-all;}
.table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;} .table td,.table th{padding: 0.2rem 0.8rem 0.2rem 0.8rem;border: 1px solid #aaa;}
.table td {text-align: left;} .table td {text-align: left;}
.s {font-size: 0.8rem; vertical-align: middle;} .s {font-size: 0.8rem; vertical-align: middle;}
.subtable {border-spacing: 0;border: 0;margin:0;} .subtable {border-spacing: 0;border: 0;margin:0;}
.subtable td{border: 0;padding: 0 0 0 10px;} .subtable td{border: 0;padding: 0 0 0 10px;}
.typetable {border-spacing: 0;border: 0;margin:0;} .typetable {border-spacing: 0;border: 0;margin:0;}
.typetable td{border: 0;padding: 2px 20px 2px 10px;} .typetable td{border: 0;padding: 2px 20px 2px 10px;}
.typetable .l{border-bottom: 1px solid red;} .typetable .l{border-bottom: 1px solid red;}
</style> </style>
</head> </head>
<body> <body>
<script> <script>
var createhtml = function (jsoncontent) { var createhtml = function (jsoncontent) {
var classmap = jsoncontent.types; var classmap = jsoncontent.types;
var html = []; var html = [];
html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">'); html.push('<div style="width:' + Math.floor(window.screen.width * 0.9) + 'px;margin:0 auto;text-align: center;">');
html.push('<br/><br/><table class="table" align="center">'); html.push('<br/><br/><table class="table" align="center">');
for (var i = 0; i < jsoncontent.servers.length; i++) { for (var i = 0; i < jsoncontent.servers.length; i++) {
var servlets = jsoncontent.servers[i].servlets; var servlets = jsoncontent.servers[i].servlets;
if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) { if (servlets.length && (servlets[0].comment || "").indexOf("【") === 0) {
servlets.sort(function (a, b) { servlets.sort(function (a, b) {
return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1); return a.comment > b.comment ? -1 : (a.comment == b.comment ? 0 : 1);
}); });
} }
for (var j = 0; j < servlets.length; j++) { for (var j = 0; j < servlets.length; j++) {
var servlet = servlets[j]; var servlet = servlets[j];
if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>'); if (html.length > 2) html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>');
html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>'); html.push(' <tr><th colspan="5" style="border-top:' + ((html.length > 2) ? 0 : 1) + ';">' + (servlet.comment || '未知模块') + '</th></tr>');
html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>'); html.push(' <tr><th>请求URL</th><th>描 述</th><th>鉴 权</th><th>参 数 <span style="font-size:12px;">(粗体: 必填项; 红色: Header; 蓝色: Cookie)</span></th><th>输 出</th></tr>');
for (var k = 0; k < servlet.mappings.length; k++) { for (var k = 0; k < servlet.mappings.length; k++) {
var action = servlet.mappings[k]; var action = servlet.mappings[k];
html.push(' <tr>'); html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>'); html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>'); html.push('<td>' + action.comment + '</td>');
html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>'); html.push('<td class="s" style="width:80px;">模块ID: ' + servlet.moduleid + '<br/>操作ID: ' + action.actionid + '<br/>需鉴权: ' + (action.auth ? '<font style="font-weight:bold;color:green;">true</font>' : '<font color=red>false</font>') + '</td>');
var paramshtml = []; var paramshtml = [];
paramshtml.push('<table class="subtable">'); paramshtml.push('<table class="subtable">');
for (var p = 0; p < action.params.length; p++) { for (var p = 0; p < action.params.length; p++) {
var param = action.params[p]; var param = action.params[p];
var t = param.type.substring(param.type.lastIndexOf('.') + 1); var t = param.type.substring(param.type.lastIndexOf('.') + 1);
if (classmap[param.type.replace('[]', '')]) { if (classmap[param.type.replace('[]', '')]) {
t = '<a href="#' + param.type.replace('[]', '') + '">' + t + '</a>'; t = '<a href="#' + param.type.replace('[]', '') + '">' + t + '</a>';
} }
if (param.name == '&') { if (param.name == '&') {
paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>'); paramshtml.push('<tr><td style="font-size:12px;">内置 </td><td> ' + t + '</td><td> 当前用户</td></tr>');
} else { } else {
var w = param.required ? "font-weight:bold;" : ""; var w = param.required ? "font-weight:bold;" : "";
var c = ' style="' + w + '"'; var c = ' style="' + w + '"';
if (param.src == "HEADER") c = ' style="color:red;' + w + '"'; if (param.style == "HEADER") c = ' style="color:red;' + w + '"';
if (param.src == "COOKIE") c = ' style="color:blue;' + w + '"'; if (param.style == "COOKIE") c = ' style="color:blue;' + w + '"';
paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>'); paramshtml.push('<tr><td ' + c + '> ' + param.name + ' </td><td> ' + t + '</td><td> ' + param.comment + '</td></tr>');
} }
} }
paramshtml.push('</table>'); paramshtml.push('</table>');
html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>'); html.push('<td class="s" style="padding:0 5px;">' + paramshtml.join('') + '</td>');
var rs = []; var rs = [];
rs.push(action.result.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, "")); rs.push(action.result.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""));
var results = action.results || []; var results = action.results || [];
for (var r = 0; r < results.length; r++) { for (var r = 0; r < results.length; r++) {
rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>'); rs.push('<a href="#' + results[r].replace('[]', '') + '">' + results[r].replace(/([a-zA-Z0-9_\$]+\.)+/g, "") + '</a>');
} }
html.push('<td>' + rs.join("<br/>") + '</td>'); html.push('<td>' + rs.join("<br/>") + '</td>');
html.push('</tr>'); html.push('</tr>');
} }
} }
} }
for (var type in classmap) { for (var type in classmap) {
html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>'); html.push(' <tr><th colspan="5" style="border-bottom:0;">&nbsp;</th></tr>');
html.push(' <tr id="' + type + '"><th colspan="5" style="border-top:0;">' + type + '</th></tr>'); html.push(' <tr id="' + type + '"><th colspan="5" style="border-top:0;">' + type + '</th></tr>');
html.push(' <tr><td colspan="5"><table class="typetable">'); html.push(' <tr><td colspan="5"><table class="typetable">');
for (var fieldname in classmap[type]) { for (var fieldname in classmap[type]) {
var field = classmap[type][fieldname]; var field = classmap[type][fieldname];
var t = field.type.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, ""); var t = field.type.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\$/g, ".").replace(/([a-zA-Z0-9_\$]+\.)+/g, "");
if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double' if (t == 'boolean' || t == 'short' || t == 'int' || t == 'long' || t == 'float' || t == 'double'
|| t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') { || t == 'boolean[]' || t == 'short[]' || t == 'int[]' || t == 'long[]' || t == 'float[]' || t == 'double[]') {
t = '<font color=blue>' + t + '</font>'; t = '<font color=blue>' + t + '</font>';
} else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map&lt;') === 0) { } else if (t == 'String' || t == 'String[]' || t == 'LongRange' || t.indexOf('Map&lt;') === 0) {
t = '<font color=red>' + t + '</font>'; t = '<font color=red>' + t + '</font>';
} }
var c = (field.comment || ''); var c = (field.comment || '');
if (field.primary) { if (field.primary) {
c = '【主键】 ' + c; c = '【主键】 ' + c;
} else if (!field.updatable) { } else if (!field.updatable) {
c = '【只读】 ' + c; c = '【只读】 ' + c;
} }
html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>'); html.push(' <tr class="l"><td>' + fieldname + '</td><td>' + t + '</td><td colspan="2">' + c + '</td></tr>');
} }
html.push(' </table></td></tr>'); html.push(' </table></td></tr>');
} }
html.push('</table><br/><br/><br/>'); html.push('</table><br/><br/><br/>');
html.push('</div>'); html.push('</div>');
return html.join(''); return html.join('');
}; };
</script> </script>
<script> <script>
var jsoncontent = '${content}'; //这里必须要用单引号引起来 var jsoncontent = '${content}'; //这里必须要用单引号引起来
document.write(createhtml(jsoncontent)); document.write(createhtml(jsoncontent));
</script> </script>
</body> </body>
</html> </html>

View File

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

View File

@@ -1,23 +1,23 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot.watch; package org.redkale.boot.watch;
import org.redkale.service.AbstractService; import org.redkale.service.AbstractService;
import org.redkale.util.Comment; import org.redkale.util.Comment;
import org.redkale.watch.WatchService; import org.redkale.watch.WatchService;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
public abstract class AbstractWatchService extends AbstractService implements WatchService { public abstract class AbstractWatchService extends AbstractService implements WatchService {
@Comment("缺少参数") @Comment("缺少参数")
public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001; public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001;
@Comment("执行异常") @Comment("执行异常")
public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002; public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002;
} }

View File

@@ -1,80 +1,80 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot.watch; package org.redkale.boot.watch;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.*; import org.redkale.boot.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.service.RetResult; import org.redkale.service.RetResult;
import org.redkale.util.Comment; import org.redkale.util.Comment;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
@RestService(name = "filter", catalog = "watch", repair = false) @RestService(name = "filter", catalog = "watch", repair = false)
public class FilterWatchService extends AbstractWatchService { public class FilterWatchService extends AbstractWatchService {
@Comment("Filter类名不存在") @Comment("Filter类名不存在")
public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002; public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002;
@Comment("Filter类名不合法") @Comment("Filter类名不合法")
public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003; public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003;
@Comment("Filter类名已存在") @Comment("Filter类名已存在")
public static final int RET_FILTER_EXISTS = 1601_0004; public static final int RET_FILTER_EXISTS = 1601_0004;
@Comment("Filter的JAR包不存在") @Comment("Filter的JAR包不存在")
public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005; public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005;
@Resource @Resource
protected Application application; protected Application application;
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter") @RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar, public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
@RestParam(name = "server", comment = "Server节点名") final String serverName, @RestParam(name = "server", comment = "Server节点名") final String serverName,
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException { @RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")"); if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file"); if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
List<NodeServer> nodes = application.getNodeServers(); List<NodeServer> nodes = application.getNodeServers();
for (NodeServer node : nodes) { for (NodeServer node : nodes) {
if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists"); if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
} }
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test1", auth = false, comment = "预留") @RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() { public RetResult test1() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test2", auth = false, comment = "预留") @RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() { public RetResult test2() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test3", auth = false, comment = "预留") @RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() { public RetResult test3() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test4", auth = false, comment = "预留") @RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() { public RetResult test4() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test5", auth = false, comment = "预留") @RestMapping(name = "test5", auth = false, comment = "预留")
public RetResult test5() { public RetResult test5() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test6", auth = false, comment = "预留") @RestMapping(name = "test6", auth = false, comment = "预留")
public RetResult test6() { public RetResult test6() {
return RetResult.success(); return RetResult.success();
} }
} }

View File

@@ -1,104 +1,104 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot.watch; package org.redkale.boot.watch;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.*; import org.redkale.boot.*;
import org.redkale.net.Server; import org.redkale.net.Server;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.service.RetResult; import org.redkale.service.RetResult;
import org.redkale.util.Comment; import org.redkale.util.Comment;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
@RestService(name = "server", catalog = "watch", repair = false) @RestService(name = "server", catalog = "watch", repair = false)
public class ServerWatchService extends AbstractWatchService { public class ServerWatchService extends AbstractWatchService {
@Comment("不存在的Server节点") @Comment("不存在的Server节点")
public static final int RET_SERVER_NOT_EXISTS = 1602_0001; public static final int RET_SERVER_NOT_EXISTS = 1602_0001;
@Comment("更改Server监听地址端口失败") @Comment("更改Server监听地址端口失败")
public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002; public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002;
@Resource @Resource
protected Application application; protected Application application;
@RestMapping(name = "info", comment = "单个Server信息查询") @RestMapping(name = "info", comment = "单个Server信息查询")
public RetResult info(@RestParam(name = "#port:") final int port) { public RetResult info(@RestParam(name = "#port:") final int port) {
Stream<NodeServer> stream = application.getNodeServers().stream(); Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null); NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found"); if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
return new RetResult(formatToMap(node)); return new RetResult(formatToMap(node));
} }
@RestMapping(name = "infos", comment = "Server信息查询") @RestMapping(name = "infos", comment = "Server信息查询")
public RetResult infos() { public RetResult infos() {
Map<String, Object> rs = new LinkedHashMap<>(); Map<String, Object> rs = new LinkedHashMap<>();
for (NodeServer ns : application.getNodeServers()) { for (NodeServer ns : application.getNodeServers()) {
Server server = ns.getServer(); Server server = ns.getServer();
rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns)); rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns));
} }
return new RetResult(rs); return new RetResult(rs);
} }
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口") @RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport, public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) { @RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`"); if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`"); if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
Stream<NodeServer> stream = application.getNodeServers().stream(); Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null); NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found"); if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
final Server server = node.getServer(); final Server server = node.getServer();
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport); InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
try { try {
server.changeAddress(application, newAddr); server.changeAddress(application, newAddr);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error"); return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
} }
return RetResult.success(); return RetResult.success();
} }
private Map<String, Object> formatToMap(NodeServer node) { private Map<String, Object> formatToMap(NodeServer node) {
Server server = node.getServer(); Server server = node.getServer();
Map<String, Object> rs = new LinkedHashMap<>(); Map<String, Object> rs = new LinkedHashMap<>();
String protocol = server.getNetprotocol(); String protocol = server.getNetprotocol();
if (node instanceof NodeSncpServer) { if (node instanceof NodeSncpServer) {
protocol += "/SNCP"; protocol += "/SNCP";
} else if (node instanceof NodeWatchServer) { } else if (node instanceof NodeWatchServer) {
protocol += "/WATCH"; protocol += "/WATCH";
} else if (node instanceof NodeHttpServer) { } else if (node instanceof NodeHttpServer) {
protocol += "/HTTP"; protocol += "/HTTP";
} else { } else {
NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class); NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class);
protocol += "/" + np.value(); protocol += "/" + np.value();
} }
rs.put("name", server.getName()); rs.put("name", server.getName());
rs.put("protocol", protocol); rs.put("protocol", protocol);
rs.put("address", server.getSocketAddress()); rs.put("address", server.getSocketAddress());
rs.put("backlog", server.getBacklog()); rs.put("backlog", server.getBacklog());
rs.put("bufferCapacity", server.getBufferCapacity()); rs.put("bufferCapacity", server.getBufferCapacity());
rs.put("bufferPoolSize", server.getBufferPoolSize()); rs.put("bufferPoolSize", server.getBufferPoolSize());
rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name()); rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name());
rs.put("maxbody", server.getMaxbody()); rs.put("maxbody", server.getMaxbody());
rs.put("maxconns", server.getMaxconns()); rs.put("maxconns", server.getMaxconns());
rs.put("serverStartTime", server.getServerStartTime()); rs.put("serverStartTime", server.getServerStartTime());
rs.put("responsePoolSize", server.getResponsePoolSize()); rs.put("responsePoolSize", server.getResponsePoolSize());
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds()); rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());
rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds()); rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds());
rs.put("createConnectionCount", server.getCreateConnectionCount()); rs.put("createConnectionCount", server.getCreateConnectionCount());
rs.put("livingConnectionCount", server.getLivingConnectionCount()); rs.put("livingConnectionCount", server.getLivingConnectionCount());
rs.put("closedConnectionCount", server.getClosedConnectionCount()); rs.put("closedConnectionCount", server.getClosedConnectionCount());
return rs; return rs;
} }
} }

View File

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

View File

@@ -1,39 +1,39 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot.watch; package org.redkale.boot.watch;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.Application; import org.redkale.boot.Application;
import org.redkale.net.TransportFactory; import org.redkale.net.TransportFactory;
import org.redkale.net.http.*; import org.redkale.net.http.*;
/** /**
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@RestService(name = "servlet", catalog = "watch", repair = false) @RestService(name = "servlet", catalog = "watch", repair = false)
public class ServletWatchService extends AbstractWatchService { public class ServletWatchService extends AbstractWatchService {
@Resource @Resource
protected Application application; protected Application application;
@Resource @Resource
protected TransportFactory transportFactory; protected TransportFactory transportFactory;
// //
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet") // @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) { // public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发 // //待开发
// return RetResult.success(); // return RetResult.success();
// } // }
// //
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet") // @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
// public RetResult stopServlet(String type) { // public RetResult stopServlet(String type) {
// //待开发 // //待开发
// return RetResult.success(); // return RetResult.success();
// } // }
} }

View File

@@ -1,140 +1,140 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.boot.watch; package org.redkale.boot.watch;
import java.io.IOException; import java.io.IOException;
import java.net.*; import java.net.*;
import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.AsynchronousSocketChannel;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.Application; import org.redkale.boot.Application;
import org.redkale.net.*; import org.redkale.net.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.AnyValue.DefaultAnyValue;
/** /**
* *
* @author zhangjx * @author zhangjx
*/ */
@RestService(name = "transport", catalog = "watch", repair = false) @RestService(name = "transport", catalog = "watch", repair = false)
public class TransportWatchService extends AbstractWatchService { public class TransportWatchService extends AbstractWatchService {
@Comment("不存在的Group节点") @Comment("不存在的Group节点")
public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001; public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001;
@Comment("非法的Node节点IP地址") @Comment("非法的Node节点IP地址")
public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002; public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002;
@Comment("Node节点IP地址已存在") @Comment("Node节点IP地址已存在")
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003; public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource @Resource
protected Application application; protected Application application;
@Resource @Resource
protected TransportFactory transportFactory; protected TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点") @RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() { public List<TransportGroupInfo> listNodes() {
return transportFactory.getGroupInfos(); return transportFactory.getGroupInfos();
} }
@RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点") @RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点")
public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group, public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr, @RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException { @RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
InetSocketAddress address; InetSocketAddress address;
try { try {
address = new InetSocketAddress(addr, port); address = new InetSocketAddress(addr, port);
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(); AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒 channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒
channel.close(); channel.close();
} catch (Exception e) { } catch (Exception e) {
return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect"); return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect");
} }
if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists"); if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists");
synchronized (this) { synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) { if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
} }
transportFactory.addGroupInfo(group, address); transportFactory.addGroupInfo(group, address);
for (Service service : transportFactory.getServices()) { for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue; if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service); SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) { if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().addRemoteAddresses(address); client.getRemoteGroupTransport().addRemoteAddresses(address);
} }
} }
} }
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port); DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) { if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).addValue("node", node); ((DefaultAnyValue) groupconf).addValue("node", node);
break; break;
} }
} }
//application.restoreConfig(); //application.restoreConfig();
} }
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点") @RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点")
public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group, public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr, @RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException { @RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
final InetSocketAddress address = new InetSocketAddress(addr, port); final InetSocketAddress address = new InetSocketAddress(addr, port);
if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")"); if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")");
synchronized (this) { synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) { if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
} }
transportFactory.removeGroupInfo(group, address); transportFactory.removeGroupInfo(group, address);
for (Service service : transportFactory.getServices()) { for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue; if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service); SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) { if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().removeRemoteAddresses(address); client.getRemoteGroupTransport().removeRemoteAddresses(address);
} }
} }
} }
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) { if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port)); ((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port));
break; break;
} }
} }
//application.restoreConfig(); //application.restoreConfig();
} }
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test1", auth = false, comment = "预留") @RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() { public RetResult test1() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test2", auth = false, comment = "预留") @RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() { public RetResult test2() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test3", auth = false, comment = "预留") @RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() { public RetResult test3() {
return RetResult.success(); return RetResult.success();
} }
@RestMapping(name = "test4", auth = false, comment = "预留") @RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() { public RetResult test4() {
return RetResult.success(); return RetResult.success();
} }
} }

View File

@@ -1,327 +1,327 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.cluster; package org.redkale.cluster;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.logging.Level; import java.util.logging.Level;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.redkale.boot.*; import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.service.Service; import org.redkale.service.Service;
import org.redkale.source.CacheSource; import org.redkale.source.CacheSource;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 使用CacheSource实现的第三方服务发现管理接口cluster * 使用CacheSource实现的第三方服务发现管理接口cluster
* *
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* *
* @since 2.3.0 * @since 2.3.0
*/ */
public class CacheClusterAgent extends ClusterAgent implements Resourcable { public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Resource(name = "$") @Resource(name = "$")
private CacheSource source; private CacheSource source;
private String sourceName; private String sourceName;
protected int ttls = 10; //定时检查的秒数 protected int ttls = 10; //定时检查的秒数
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(AnyValue config) {
super.init(config); super.init(config);
this.sourceName = getSourceName(); this.sourceName = getSourceName();
AnyValue[] properties = config.getAnyValues("property"); AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) { for (AnyValue property : properties) {
if ("ttls".equalsIgnoreCase(property.getValue("name"))) { if ("ttls".equalsIgnoreCase(property.getValue("name"))) {
this.ttls = Integer.parseInt(property.getValue("value", "").trim()); this.ttls = Integer.parseInt(property.getValue("value", "").trim());
if (this.ttls < 5) this.ttls = 10; if (this.ttls < 5) this.ttls = 10;
} }
} }
} }
@Override @Override
public void destroy(AnyValue config) { public void destroy(AnyValue config) {
if (scheduler != null) scheduler.shutdownNow(); if (scheduler != null) scheduler.shutdownNow();
} }
public String getSourceName() { public String getSourceName() {
AnyValue[] properties = config.getAnyValues("property"); AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) { for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name")) if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) { && property.getValue("value") != null) {
this.sourceName = property.getValue("value"); this.sourceName = property.getValue("value");
return this.sourceName; return this.sourceName;
} }
} }
return null; return null;
} }
@Override @Override
public String resourceName() { public String resourceName() {
return sourceName; return sourceName;
} }
@Override //ServiceLoader时判断配置是否符合当前实现类 @Override //ServiceLoader时判断配置是否符合当前实现类
public boolean match(AnyValue config) { public boolean acceptsConf(AnyValue config) {
if (config == null) return false; if (config == null) return false;
AnyValue[] properties = config.getAnyValues("property"); AnyValue[] properties = config.getAnyValues("property");
if (properties == null || properties.length == 0) return false; if (properties == null || properties.length == 0) return false;
for (AnyValue property : properties) { for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name")) if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) return true; && property.getValue("value") != null) return true;
} }
return false; return false;
} }
@Override @Override
public void start() { public void start() {
if (this.scheduler == null) { if (this.scheduler == null) {
this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> { this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> {
final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread"); final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread");
t.setDaemon(true); t.setDaemon(true);
return t; return t;
}); });
this.scheduler.scheduleAtFixedRate(() -> { this.scheduler.scheduleAtFixedRate(() -> {
try { try {
checkApplicationHealth(); checkApplicationHealth();
checkHttpAddressHealth(); checkHttpAddressHealth();
loadMqtpAddressHealth(); loadMqtpAddressHealth();
localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> { localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> {
checkLocalHealth(entry); checkLocalHealth(entry);
}); });
remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> { remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> {
updateSncpTransport(entry); updateSncpTransport(entry);
}); });
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e); logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e);
} }
}, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS); }, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS);
} }
} }
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) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex); logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex);
} }
} }
protected void checkLocalHealth(final ClusterEntry entry) { protected void checkLocalHealth(final ClusterEntry entry) {
AddressEntry newaddr = new AddressEntry(); AddressEntry newaddr = new AddressEntry();
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) + ":";
mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix)) mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix))
.forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn))); .forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn)));
return CompletableFuture.completedFuture(rsmap); return CompletableFuture.completedFuture(rsmap);
} }
@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) -> {
if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr); if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr);
}); });
return set; return set;
}); });
} }
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;
} }
protected void checkApplicationHealth() { protected void checkApplicationHealth() {
String checkname = generateApplicationServiceName(); String checkname = generateApplicationServiceName();
String checkid = generateApplicationCheckId(); String checkid = generateApplicationCheckId();
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(checkname, checkid, AddressEntry.class, entry); source.hset(checkname, checkid, AddressEntry.class, entry);
} }
@Override @Override
public void register(Application application) { public void register(Application application) {
if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster"); if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster");
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
protected ClusterEntry register(NodeServer ns, String protocol, Service service) { protected ClusterEntry register(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, false); deregister(ns, protocol, service, false);
// //
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service); ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
AddressEntry entry = new AddressEntry(); AddressEntry entry = new AddressEntry();
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;
} }
@Override @Override
protected void deregister(NodeServer ns, String protocol, Service service) { protected void deregister(NodeServer ns, String protocol, Service service) {
deregister(ns, protocol, service, true); deregister(ns, protocol, service, true);
} }
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);
} }
} }
@Override @Override
protected String generateApplicationServiceName() { protected String generateApplicationServiceName() {
return "cluster." + super.generateApplicationServiceName(); return "cluster." + super.generateApplicationServiceName();
} }
@Override @Override
protected String generateServiceName(NodeServer ns, String protocol, Service service) { protected String generateServiceName(NodeServer ns, String protocol, Service service) {
return "cluster." + super.generateServiceName(ns, protocol, service); return "cluster." + super.generateServiceName(ns, protocol, service);
} }
@Override @Override
public String generateHttpServiceName(String protocol, String module, String resname) { public String generateHttpServiceName(String protocol, String module, String resname) {
return "cluster." + super.generateHttpServiceName(protocol, module, resname); return "cluster." + super.generateHttpServiceName(protocol, module, resname);
} }
@Override @Override
protected String generateApplicationCheckName() { protected String generateApplicationCheckName() {
return generateApplicationServiceName(); return generateApplicationServiceName();
} }
@Override @Override
protected String generateApplicationCheckId() { protected String generateApplicationCheckId() {
return generateApplicationServiceId(); return generateApplicationServiceId();
} }
@Override @Override
protected String generateCheckName(NodeServer ns, String protocol, Service service) { protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service); return generateServiceName(ns, protocol, service);
} }
@Override @Override
protected String generateCheckId(NodeServer ns, String protocol, Service service) { protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return generateServiceId(ns, protocol, service); return generateServiceId(ns, protocol, service);
} }
public static class AddressEntry { public static class AddressEntry {
public InetSocketAddress addr; public InetSocketAddress addr;
public int nodeid; public int nodeid;
public long time; public long time;
public AddressEntry() { public AddressEntry() {
} }
public AddressEntry refresh() { public AddressEntry refresh() {
this.time = System.currentTimeMillis(); this.time = System.currentTimeMillis();
return this; return this;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }
} }

View File

@@ -1,342 +1,342 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.cluster; package org.redkale.cluster;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
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.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.*;
import org.redkale.net.http.*; import org.redkale.net.http.*;
import org.redkale.net.sncp.*; import org.redkale.net.sncp.*;
import org.redkale.service.*; import org.redkale.service.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 第三方服务发现管理接口cluster * 第三方服务发现管理接口cluster
* *
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* *
* @since 2.1.0 * @since 2.1.0
*/ */
public abstract class ClusterAgent { public abstract class ClusterAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@Resource(name = RESNAME_APP_NODEID) @Resource(name = RESNAME_APP_NODEID)
protected int nodeid; protected int nodeid;
@Resource(name = RESNAME_APP_NAME) @Resource(name = RESNAME_APP_NAME)
protected String appName = ""; protected String appName = "";
@Resource(name = RESNAME_APP_ADDR) @Resource(name = RESNAME_APP_ADDR)
protected InetSocketAddress appAddress; protected InetSocketAddress appAddress;
protected String name; protected String name;
protected boolean waits; protected boolean waits;
protected String[] protocols; //必须全大写 protected String[] protocols; //必须全大写
protected int[] ports; protected int[] ports;
protected AnyValue config; protected AnyValue config;
protected TransportFactory transportFactory; protected TransportFactory transportFactory;
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>(); protected final ConcurrentHashMap<String, ClusterEntry> remoteEntrys = new ConcurrentHashMap<>();
public void init(AnyValue config) { public void init(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);
{ {
String ps = config.getValue("protocols", "").toUpperCase(); String ps = config.getValue("protocols", "").toUpperCase();
if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP"; if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP";
this.protocols = ps.split(";"); this.protocols = ps.split(";");
} }
String ts = config.getValue("ports", ""); String ts = config.getValue("ports", "");
if (ts != null && !ts.isEmpty()) { if (ts != null && !ts.isEmpty()) {
String[] its = ts.split(";"); String[] its = ts.split(";");
List<Integer> list = new ArrayList<>(); List<Integer> list = new ArrayList<>();
for (String str : its) { for (String str : its) {
if (str.trim().isEmpty()) continue; if (str.trim().isEmpty()) continue;
list.add(Integer.parseInt(str.trim())); list.add(Integer.parseInt(str.trim()));
} }
if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray(); if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray();
} }
} }
public void destroy(AnyValue config) { public void destroy(AnyValue config) {
} }
//ServiceLoader时判断配置是否符合当前实现类 //ServiceLoader时判断配置是否符合当前实现类
public abstract boolean match(AnyValue config); public abstract boolean acceptsConf(AnyValue config);
public boolean containsProtocol(String protocol) { public boolean containsProtocol(String protocol) {
if (protocol == null || protocol.isEmpty()) return false; if (protocol == null || protocol.isEmpty()) return false;
return protocols == null || Utility.contains(protocols, protocol.toUpperCase()); return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
} }
public boolean containsPort(int port) { public boolean containsPort(int port) {
if (ports == null || ports.length == 0) return true; if (ports == null || ports.length == 0) return true;
return Utility.contains(ports, port); return Utility.contains(ports, port);
} }
public abstract void register(Application application); public abstract void register(Application application);
public abstract void deregister(Application application); public abstract void deregister(Application application);
//注册服务, 在NodeService调用Service.init方法之前调用 //注册服务, 在NodeService调用Service.init方法之前调用
public void register(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) { public void register(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
if (localServices.isEmpty()) return; if (localServices.isEmpty()) return;
//注册本地模式 //注册本地模式
for (Service service : localServices) { for (Service service : localServices) {
if (!canRegister(protocol, service)) continue; if (!canRegister(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")) {
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
if (mmc != null) { if (mmc != null) {
ClusterEntry mqentry = register(ns, "mqtp", service); ClusterEntry mqentry = register(ns, "mqtp", service);
localEntrys.put(mqentry.serviceid, mqentry); localEntrys.put(mqentry.serviceid, mqentry);
htentry.submqtp = true; htentry.submqtp = true;
} }
} }
} }
//远程模式加载IP列表, 只支持SNCP协议 //远程模式加载IP列表, 只支持SNCP协议
if (ns.isSNCP()) { if (ns.isSNCP()) {
for (Service service : remoteServices) { for (Service service : remoteServices) {
ClusterEntry entry = new ClusterEntry(ns, protocol, service); ClusterEntry entry = new ClusterEntry(ns, protocol, service);
updateSncpTransport(entry); updateSncpTransport(entry);
remoteEntrys.put(entry.serviceid, entry); remoteEntrys.put(entry.serviceid, entry);
} }
} }
} }
//注销服务, 在NodeService调用Service.destroy 方法之前调用 //注销服务, 在NodeService调用Service.destroy 方法之前调用
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(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(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;
} }
return true; return true;
} }
public void start() { public void start() {
} }
protected void afterDeregister(NodeServer ns, String protocol) { protected void afterDeregister(NodeServer ns, String protocol) {
if (!this.waits) return; if (!this.waits) return;
int s = intervalCheckSeconds(); int s = intervalCheckSeconds();
if (s > 0) { //暂停弥补其他依赖本进程服务的周期偏差 if (s > 0) { //暂停弥补其他依赖本进程服务的周期偏差
try { try {
Thread.sleep(s * 1000); Thread.sleep(s * 1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
} }
logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister"); logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister");
} }
} }
public int intervalCheckSeconds() { public int intervalCheckSeconds() {
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列表
public abstract CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname); public abstract CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname);
//获取远程服务的可用ip列表 //获取远程服务的可用ip列表
protected abstract CompletableFuture<Collection<InetSocketAddress>> queryAddress(ClusterEntry entry); protected abstract CompletableFuture<Collection<InetSocketAddress>> queryAddress(ClusterEntry entry);
//注册服务 //注册服务
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service); protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
//注销服务 //注销服务
protected abstract void deregister(NodeServer ns, String protocol, Service service); protected abstract void deregister(NodeServer ns, String protocol, Service service);
//格式: 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 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 generateApplicationServiceId() { //与servicename相同
return generateApplicationServiceName(); return generateApplicationServiceName();
} }
protected String generateApplicationCheckName() { protected String generateApplicationCheckName() {
return "check-" + generateApplicationServiceName(); return "check-" + generateApplicationServiceName();
} }
protected String generateApplicationCheckId() { protected String generateApplicationCheckId() {
return "check-" + generateApplicationServiceId(); return "check-" + generateApplicationServiceId();
} }
//也会提供给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() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
} }
//格式: protocol:classtype-resourcename //格式: protocol:classtype-resourcename
protected String generateServiceName(NodeServer ns, String protocol, Service service) { protected String generateServiceName(NodeServer ns, String protocol, Service service) {
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() + ":" + 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() + ":" + mmc.module() + ":" + selfmodule;
} }
if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName(); if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + 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() + ":" + 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) + ":" + this.nodeid;
} }
protected String generateCheckName(NodeServer ns, String protocol, Service service) { protected String generateCheckName(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceName(ns, protocol, service); return "check-" + generateServiceName(ns, protocol, service);
} }
protected String generateCheckId(NodeServer ns, String protocol, Service service) { protected String generateCheckId(NodeServer ns, String protocol, Service service) {
return "check-" + generateServiceId(ns, protocol, service); return "check-" + generateServiceId(ns, protocol, service);
} }
protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() { protected ConcurrentHashMap<String, ClusterEntry> getLocalEntrys() {
return localEntrys; return localEntrys;
} }
protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() { protected ConcurrentHashMap<String, ClusterEntry> getRemoteEntrys() {
return remoteEntrys; return remoteEntrys;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
public TransportFactory getTransportFactory() { public TransportFactory getTransportFactory() {
return transportFactory; return transportFactory;
} }
public void setTransportFactory(TransportFactory transportFactory) { public void setTransportFactory(TransportFactory transportFactory) {
this.transportFactory = transportFactory; this.transportFactory = transportFactory;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public String[] getProtocols() { public String[] getProtocols() {
return protocols; return protocols;
} }
public void setProtocols(String[] protocols) { public void setProtocols(String[] protocols) {
this.protocols = protocols; this.protocols = protocols;
} }
public int[] getPorts() { public int[] getPorts() {
return ports; return ports;
} }
public void setPorts(int[] ports) { public void setPorts(int[] ports) {
this.ports = ports; this.ports = ports;
} }
public AnyValue getConfig() { public AnyValue getConfig() {
return config; return config;
} }
public void setConfig(AnyValue config) { public void setConfig(AnyValue config) {
this.config = config; this.config = config;
} }
public class ClusterEntry { public class ClusterEntry {
public String serviceid; public String serviceid;
public String servicename; public String servicename;
public String checkid; public String checkid;
public String checkname; public String checkname;
public String protocol; public String protocol;
public String netprotocol; public String netprotocol;
public WeakReference<Service> serviceref; public WeakReference<Service> serviceref;
public InetSocketAddress address; public InetSocketAddress address;
public boolean canceled; public boolean canceled;
public boolean submqtp; public boolean submqtp;
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.protocol = protocol; this.protocol = protocol;
InetSocketAddress addr = ns.getSocketAddress(); InetSocketAddress addr = ns.getSocketAddress();
String host = addr.getHostString(); String host = addr.getHostString();
if ("0.0.0.0".equals(host)) { if ("0.0.0.0".equals(host)) {
host = appAddress.getHostString(); host = appAddress.getHostString();
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
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }
} }

View File

@@ -1,25 +1,25 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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.cluster; package org.redkale.cluster;
import org.redkale.util.AnyValue; import org.redkale.util.AnyValue;
/** /**
* 自定义的ClusterAgent加载器 * 自定义的ClusterAgent加载器
* *
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @since 2.4.0 * @since 2.5.0
*/ */
public interface ClusterAgentLoader { public interface ClusterAgentProvider {
public boolean match(AnyValue config); public boolean acceptsConf(AnyValue config);
public Class<? extends ClusterAgent> agentClass(); public Class<? extends ClusterAgent> agentClass();
} }

View File

@@ -1,64 +1,64 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.*; import java.util.*;
import org.redkale.util.*; import org.redkale.util.*;
import org.redkale.convert.Reader.ValueType; import org.redkale.convert.Reader.ValueType;
import static org.redkale.convert.Reader.ValueType.MAP; import static org.redkale.convert.Reader.ValueType.MAP;
/** /**
* 对不明类型的对象进行反序列化 <br> * 对不明类型的对象进行反序列化 <br>
* <b>注意: 目前只支持文本格式</b> <br> * <b>注意: 目前只支持文本格式</b> <br>
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class AnyDecoder implements Decodeable<Reader, Object> { public class AnyDecoder implements Decodeable<Reader, Object> {
private static final Type collectionObjectType = new TypeToken<Collection<Object>>() { private static final Type collectionObjectType = new TypeToken<Collection<Object>>() {
}.getType(); }.getType();
private static final Type mapObjectType = new TypeToken<Map<String, Object>>() { private static final Type mapObjectType = new TypeToken<Map<String, Object>>() {
}.getType(); }.getType();
private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class); private static final Creator<ArrayList> collectionCreator = Creator.create(ArrayList.class);
private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class); private static final Creator<HashMap> mapCreator = Creator.create(HashMap.class);
protected final Decodeable<Reader, String> stringDecoder; protected final Decodeable<Reader, String> stringDecoder;
protected final CollectionDecoder collectionDecoder; protected final CollectionDecoder collectionDecoder;
protected final MapDecoder mapDecoder; protected final MapDecoder mapDecoder;
public AnyDecoder(final ConvertFactory factory) { public AnyDecoder(final ConvertFactory factory) {
this.stringDecoder = factory.loadDecoder(String.class); this.stringDecoder = factory.loadDecoder(String.class);
this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this); this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this);
this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this); this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this);
} }
@Override @Override
public Object convertFrom(Reader in) { public Object convertFrom(Reader in) {
ValueType vt = in.readType(); ValueType vt = in.readType();
if (vt == null) return null; if (vt == null) return null;
switch (vt) { switch (vt) {
case ARRAY: case ARRAY:
return this.collectionDecoder.convertFrom(in); return this.collectionDecoder.convertFrom(in);
case MAP: case MAP:
return this.mapDecoder.convertFrom(in); return this.mapDecoder.convertFrom(in);
} }
return this.stringDecoder.convertFrom(in); return this.stringDecoder.convertFrom(in);
} }
@Override @Override
public Type getType() { public Type getType() {
return void.class; return void.class;
} }
} }

View File

@@ -1,73 +1,73 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
/** /**
* 对不明类型的对象进行序列化 BSON序列化时将对象的类名写入WriterJSON则不写入 * 对不明类型的对象进行序列化 BSON序列化时将对象的类名写入WriterJSON则不写入
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <T> 序列化的泛型类型 * @param <T> 序列化的泛型类型
*/ */
public final class AnyEncoder<T> implements Encodeable<Writer, T> { public final class AnyEncoder<T> implements Encodeable<Writer, T> {
final ConvertFactory factory; final ConvertFactory factory;
AnyEncoder(ConvertFactory factory) { AnyEncoder(ConvertFactory factory) {
this.factory = factory; this.factory = factory;
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void convertTo(final Writer out, final T value) { public void convertTo(final Writer out, final T value) {
if (value == null) { if (value == null) {
out.writeClassName(null); out.writeClassName(null);
out.writeNull(); out.writeNull();
} else { } else {
Class clazz = value.getClass(); Class clazz = value.getClass();
if (clazz == Object.class) { if (clazz == Object.class) {
out.writeObjectB(value); out.writeObjectB(value);
out.writeObjectE(value); out.writeObjectE(value);
return; return;
} }
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz)); if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz));
factory.loadEncoder(clazz).convertTo(out, value); factory.loadEncoder(clazz).convertTo(out, value);
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void convertMapTo(final Writer out, final Object... values) { public void convertMapTo(final Writer out, final Object... values) {
if (values == null) { if (values == null) {
out.writeNull(); out.writeNull();
} else { } else {
int count = values.length - values.length % 2; int count = values.length - values.length % 2;
if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) { if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) {
for (int i = 0; i < count; i += 2) { for (int i = 0; i < count; i += 2) {
if (i > 0) out.writeArrayMark(); if (i > 0) out.writeArrayMark();
this.convertTo(out, (T) values[i]); this.convertTo(out, (T) values[i]);
out.writeMapMark(); out.writeMapMark();
Object val = values[i + 1]; Object val = values[i + 1];
if (val instanceof CompletableFuture) { if (val instanceof CompletableFuture) {
this.convertTo(out, (T) ((CompletableFuture) val).join()); this.convertTo(out, (T) ((CompletableFuture) val).join());
} else { } else {
this.convertTo(out, (T) val); this.convertTo(out, (T) val);
} }
} }
} }
out.writeMapE(); out.writeMapE();
} }
} }
@Override @Override
public Type getType() { public Type getType() {
return Object.class; return Object.class;
} }
} }

View File

@@ -0,0 +1,40 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import org.redkale.util.AnyValue;
/**
* AnyValue的Decoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <R> Reader输入的子类型
*
* @since 2.5.0
*/
public class AnyValueDecoder<R extends Reader> implements Decodeable<R, AnyValue> {
protected final ConvertFactory factory;
public AnyValueDecoder(final ConvertFactory factory) {
this.factory = factory;
}
@Override
public AnyValue convertFrom(R in) {
return null;
}
@Override
public Type getType() {
return AnyValue.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.reflect.Type;
import org.redkale.util.AnyValue;
/**
* AnyValue的Encoder实现
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <W> Writer输出的子类
*
* @since 2.5.0
*/
public class AnyValueEncoder<W extends Writer> implements Encodeable<W, AnyValue> {
@Override
public void convertTo(W out, AnyValue value) {
}
@Override
public Type getType() {
return AnyValue.class;
}
}

View File

@@ -1,144 +1,144 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
/** /**
* 数组的反序列化操作类 <br> * 数组的反序列化操作类 <br>
* 对象数组的反序列化不包含int[]long[]这样的primitive class数组 <br> * 对象数组的反序列化不包含int[]long[]这样的primitive class数组 <br>
* 支持一定程度的泛型 <br> * 支持一定程度的泛型 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <T> 反解析的数组元素类型 * @param <T> 反解析的数组元素类型
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ArrayDecoder<T> implements Decodeable<Reader, T[]> { public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
protected final Type type; protected final Type type;
protected final Type componentType; protected final Type componentType;
protected final Class componentClass; protected final Class componentClass;
protected final Decodeable<Reader, T> componentDecoder; protected final Decodeable<Reader, T> componentDecoder;
protected volatile boolean inited = false; protected volatile boolean inited = false;
protected final Object lock = new Object(); protected final Object lock = new Object();
public ArrayDecoder(final ConvertFactory factory, final Type type) { public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try { try {
if (type instanceof GenericArrayType) { if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType(); Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t; this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) { } else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType(); this.componentType = ((Class) type).getComponentType();
} else { } else {
throw new ConvertException("(" + type + ") is not a array type"); throw new ConvertException("(" + type + ") is not a array type");
} }
if (this.componentType instanceof ParameterizedType) { if (this.componentType instanceof ParameterizedType) {
this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType(); this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType();
} else { } else {
this.componentClass = (Class) this.componentType; this.componentClass = (Class) this.componentType;
} }
factory.register(type, this); factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType); this.componentDecoder = factory.loadDecoder(this.componentType);
} finally { } finally {
inited = true; inited = true;
synchronized (lock) { synchronized (lock) {
lock.notifyAll(); lock.notifyAll();
} }
} }
} }
@Override @Override
public T[] convertFrom(Reader in) { public T[] convertFrom(Reader in) {
return convertFrom(in, null); return convertFrom(in, null);
} }
public T[] convertFrom(Reader in, DeMember member) { public T[] convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1]; byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder); int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1; int contentLength = -1;
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) { if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder); contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH; len = Reader.SIGN_NOLENGTH;
} }
if (this.componentDecoder == null) { if (this.componentDecoder == null) {
if (!this.inited) { if (!this.inited) {
synchronized (lock) { synchronized (lock) {
try { try {
lock.wait(); lock.wait();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals); final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final List<T> result = new ArrayList(); final List<T> result = new ArrayList();
boolean first = true; boolean first = true;
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {
int startPosition = in.position(); int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) { while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first); Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break; if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first)); result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false; first = false;
} }
} else { } else {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in)); result.add(localdecoder.convertFrom(in));
} }
} }
in.readArrayE(); in.readArrayE();
T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size());
return result.toArray(rs); return result.toArray(rs);
} }
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength); return in.hasNext(startPosition, contentLength);
} }
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) { protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder; return decoder;
} }
protected Reader getItemReader(Reader in, DeMember member, boolean first) { protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in; return in;
} }
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) { protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null; if (in == null) return null;
return decoder.convertFrom(in); return decoder.convertFrom(in);
} }
@Override @Override
public String toString() { public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}"; return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}";
} }
@Override @Override
public Type getType() { public Type getType() {
return type; return type;
} }
public Type getComponentType() { public Type getComponentType() {
return componentType; return componentType;
} }
public Decodeable<Reader, T> getComponentDecoder() { public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder; return componentDecoder;
} }
} }

View File

@@ -1,133 +1,133 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
/** /**
* 数组的序列化操作类 <br> * 数组的序列化操作类 <br>
* 对象数组的序列化不包含int[]long[]这样的primitive class数组 <br> * 对象数组的序列化不包含int[]long[]这样的primitive class数组 <br>
* 支持一定程度的泛型 <br> * 支持一定程度的泛型 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <T> 序列化的数组元素类型 * @param <T> 序列化的数组元素类型
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ArrayEncoder<T> implements Encodeable<Writer, T[]> { public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
protected final Type type; protected final Type type;
protected final Type componentType; protected final Type componentType;
protected final Encodeable anyEncoder; protected final Encodeable anyEncoder;
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;
protected final Object lock = new Object(); protected final Object lock = new Object();
public ArrayEncoder(final ConvertFactory factory, final Type type) { public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try { try {
if (type instanceof GenericArrayType) { if (type instanceof GenericArrayType) {
Type t = ((GenericArrayType) type).getGenericComponentType(); Type t = ((GenericArrayType) type).getGenericComponentType();
this.componentType = t instanceof TypeVariable ? Object.class : t; this.componentType = t instanceof TypeVariable ? Object.class : t;
} else if ((type instanceof Class) && ((Class) type).isArray()) { } else if ((type instanceof Class) && ((Class) type).isArray()) {
this.componentType = ((Class) type).getComponentType(); this.componentType = ((Class) type).getComponentType();
} else { } else {
throw new ConvertException("(" + type + ") is not a array type"); throw new ConvertException("(" + type + ") is not a array type");
} }
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) {
lock.notifyAll(); lock.notifyAll();
} }
} }
} }
@Override @Override
public void convertTo(Writer out, T[] value) { public void convertTo(Writer out, T[] value) {
convertTo(out, null, value); convertTo(out, null, value);
} }
public void convertTo(Writer out, EnMember member, T[] value) { public void convertTo(Writer out, EnMember member, T[] value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
return; return;
} }
int iMax = value.length - 1; int iMax = value.length - 1;
if (iMax == -1) { if (iMax == -1) {
out.writeArrayB(0, this, componentEncoder, value); out.writeArrayB(0, this, componentEncoder, value);
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.componentEncoder == null) { if (this.componentEncoder == null) {
if (!this.inited) { if (!this.inited) {
synchronized (lock) { synchronized (lock) {
try { try {
lock.wait(); lock.wait();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
Encodeable<Writer, Object> itemEncoder = this.componentEncoder; 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);
if (i == iMax) break; if (i == iMax) break;
out.writeArrayMark(); out.writeArrayMark();
} }
} }
} else { } else {
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
final Type comp = this.componentType; final Type comp = this.componentType;
for (int i = 0;; i++) { for (int i = 0;; i++) {
Object v = value[i]; Object v = value[i];
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i); writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i);
if (i == iMax) break; if (i == iMax) break;
out.writeArrayMark(); out.writeArrayMark();
} }
} }
} }
out.writeArrayE(); out.writeArrayE();
} }
protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, int index) { protected void writeMemberValue(Writer out, EnMember member, Encodeable<Writer, Object> encoder, Object value, int index) {
encoder.convertTo(out, value); encoder.convertTo(out, value);
} }
@Override @Override
public String toString() { public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}"; return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}";
} }
@Override @Override
public Type getType() { public Type getType() {
return type; return type;
} }
public Type getComponentType() { public Type getComponentType() {
return componentType; return componentType;
} }
public Encodeable<Writer, Object> getComponentEncoder() { public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder; return componentEncoder;
} }
} }

View File

@@ -1,35 +1,35 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* 二进制序列化/反序列化操作类 * 二进制序列化/反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <R> Reader输入的子类 * @param <R> Reader输入的子类
* @param <W> Writer输出的子类 * @param <W> Writer输出的子类
*/ */
public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> { public abstract class BinaryConvert<R extends Reader, W extends Writer> extends Convert<R, W> {
protected BinaryConvert(ConvertFactory<R, W> factory) { protected BinaryConvert(ConvertFactory<R, W> factory) {
super(factory); super(factory);
} }
@Override @Override
public final boolean isBinary() { public final boolean isBinary() {
return true; return true;
} }
public abstract byte[] convertTo(final Object value); public abstract byte[] convertTo(final Object value);
public abstract byte[] convertTo(final Type type, final Object value); public abstract byte[] convertTo(final Type type, final Object value);
} }

View File

@@ -1,149 +1,149 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import org.redkale.util.Creator; import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.*; import java.util.*;
/** /**
* Collection的反序列化操作类 <br> * Collection的反序列化操作类 <br>
* 支持一定程度的泛型 <br> * 支持一定程度的泛型 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <T> 反解析的集合元素类型 * @param <T> 反解析的集合元素类型
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> { public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
protected final Type type; protected final Type type;
protected final Type componentType; protected final Type componentType;
protected Creator<Collection<T>> creator; protected Creator<Collection<T>> creator;
protected final Decodeable<Reader, T> componentDecoder; protected final Decodeable<Reader, T> componentDecoder;
protected volatile boolean inited = false; protected volatile boolean inited = false;
protected final Object lock = new Object(); protected final Object lock = new Object();
public CollectionDecoder(final ConvertFactory factory, final Type type) { public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try { try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type; final ParameterizedType pt = (ParameterizedType) type;
this.componentType = pt.getActualTypeArguments()[0]; this.componentType = pt.getActualTypeArguments()[0];
this.creator = factory.loadCreator((Class) pt.getRawType()); this.creator = factory.loadCreator((Class) pt.getRawType());
factory.register(type, this); factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType); this.componentDecoder = factory.loadDecoder(this.componentType);
} else if (factory.isReversible()) { } else if (factory.isReversible()) {
this.componentType = Object.class; this.componentType = Object.class;
this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class); this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class);
factory.register(type, this); factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType); this.componentDecoder = factory.loadDecoder(this.componentType);
} else { } else {
throw new ConvertException("CollectionDecoder not support the type (" + type + ")"); throw new ConvertException("CollectionDecoder not support the type (" + type + ")");
} }
} finally { } finally {
inited = true; inited = true;
synchronized (lock) { synchronized (lock) {
lock.notifyAll(); lock.notifyAll();
} }
} }
} }
//仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register //仅供类似JsonAnyDecoder这种动态创建使用 不得调用 factory.register
public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType, public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType,
Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) { Creator<Collection<T>> creator, final Decodeable<Reader, T> componentDecoder) {
Objects.requireNonNull(componentDecoder); Objects.requireNonNull(componentDecoder);
this.type = type; this.type = type;
this.componentType = componentType; this.componentType = componentType;
this.creator = creator; this.creator = creator;
this.componentDecoder = componentDecoder; this.componentDecoder = componentDecoder;
this.inited = true; this.inited = true;
} }
@Override @Override
public Collection<T> convertFrom(Reader in) { public Collection<T> convertFrom(Reader in) {
return convertFrom(in, null); return convertFrom(in, null);
} }
public Collection<T> convertFrom(Reader in, DeMember member) { public Collection<T> convertFrom(Reader in, DeMember member) {
byte[] typevals = new byte[1]; byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder); int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1; int contentLength = -1;
if (len == Reader.SIGN_NULL) return null; if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NOLENBUTBYTES) { if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder); contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH; len = Reader.SIGN_NOLENGTH;
} }
if (this.componentDecoder == null) { if (this.componentDecoder == null) {
if (!this.inited) { if (!this.inited) {
synchronized (lock) { synchronized (lock) {
try { try {
lock.wait(); lock.wait();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals); final Decodeable<Reader, T> localdecoder = getComponentDecoder(this.componentDecoder, typevals);
final Collection<T> result = this.creator.create(); final Collection<T> result = this.creator.create();
boolean first = true; boolean first = true;
if (len == Reader.SIGN_NOLENGTH) { if (len == Reader.SIGN_NOLENGTH) {
int startPosition = in.position(); int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) { while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first); Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break; if (itemReader == null) break;
result.add(readMemberValue(itemReader, member, localdecoder, first)); result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false; first = false;
} }
} else { } else {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
result.add(localdecoder.convertFrom(in)); result.add(localdecoder.convertFrom(in));
} }
} }
in.readArrayE(); in.readArrayE();
return result; return result;
} }
protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) {
return in.hasNext(startPosition, contentLength); return in.hasNext(startPosition, contentLength);
} }
protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) { protected Decodeable<Reader, T> getComponentDecoder(Decodeable<Reader, T> decoder, byte[] typevals) {
return decoder; return decoder;
} }
protected Reader getItemReader(Reader in, DeMember member, boolean first) { protected Reader getItemReader(Reader in, DeMember member, boolean first) {
return in; return in;
} }
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) { protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null; if (in == null) return null;
return decoder.convertFrom(in); return decoder.convertFrom(in);
} }
@Override @Override
public Type getType() { public Type getType() {
return type; return type;
} }
public Type getComponentType() { public Type getComponentType() {
return componentType; return componentType;
} }
public Decodeable<Reader, T> getComponentDecoder() { public Decodeable<Reader, T> getComponentDecoder() {
return componentDecoder; return componentDecoder;
} }
} }

View File

@@ -1,111 +1,111 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.Collection; import java.util.Collection;
/** /**
* Collection的序列化操作类 <br> * Collection的序列化操作类 <br>
* 支持一定程度的泛型 <br> * 支持一定程度的泛型 <br>
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <T> 序列化的集合元素类型 * @param <T> 序列化的集合元素类型
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> { public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
protected final Type type; protected final Type type;
protected final Encodeable<Writer, Object> componentEncoder; protected final Encodeable<Writer, Object> componentEncoder;
protected volatile boolean inited = false; protected volatile boolean inited = false;
protected final Object lock = new Object(); protected final Object lock = new Object();
public CollectionEncoder(final ConvertFactory factory, final Type type) { public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type; this.type = type;
try { try {
if (type instanceof ParameterizedType) { if (type instanceof ParameterizedType) {
Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; Type t = ((ParameterizedType) type).getActualTypeArguments()[0];
if (t instanceof TypeVariable) { if (t instanceof TypeVariable) {
this.componentEncoder = factory.getAnyEncoder(); this.componentEncoder = factory.getAnyEncoder();
} else { } else {
this.componentEncoder = factory.loadEncoder(t); this.componentEncoder = factory.loadEncoder(t);
} }
} else { } else {
this.componentEncoder = factory.getAnyEncoder(); this.componentEncoder = factory.getAnyEncoder();
} }
} finally { } finally {
inited = true; inited = true;
synchronized (lock) { synchronized (lock) {
lock.notifyAll(); lock.notifyAll();
} }
} }
} }
@Override @Override
public void convertTo(Writer out, Collection<T> value) { public void convertTo(Writer out, Collection<T> value) {
convertTo(out, null, value); convertTo(out, null, value);
} }
public void convertTo(Writer out, EnMember member, Collection<T> value) { public void convertTo(Writer out, EnMember member, Collection<T> value) {
if (value == null) { if (value == null) {
out.writeNull(); out.writeNull();
return; return;
} }
if (value.isEmpty()) { if (value.isEmpty()) {
out.writeArrayB(0, this, componentEncoder, value); out.writeArrayB(0, this, componentEncoder, value);
out.writeArrayE(); out.writeArrayE();
return; return;
} }
if (this.componentEncoder == null) { if (this.componentEncoder == null) {
if (!this.inited) { if (!this.inited) {
synchronized (lock) { synchronized (lock) {
try { try {
lock.wait(); lock.wait();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) { if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) {
boolean first = true; boolean first = true;
for (Object v : value) { for (Object v : value) {
if (!first) out.writeArrayMark(); if (!first) out.writeArrayMark();
writeMemberValue(out, member, v, first); writeMemberValue(out, member, v, first);
if (first) first = false; if (first) first = false;
} }
} }
out.writeArrayE(); out.writeArrayE();
} }
protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) { protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) {
componentEncoder.convertTo(out, value); componentEncoder.convertTo(out, value);
} }
@Override @Override
public Type getType() { public Type getType() {
return type; return type;
} }
@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 + "}";
} }
public Encodeable<Writer, Object> getComponentEncoder() { public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder; return componentEncoder;
} }
public Type getComponentType() { public Type getComponentType() {
return componentEncoder == null ? null : componentEncoder.getType(); return componentEncoder == null ? null : componentEncoder.getType();
} }
} }

View File

@@ -1,76 +1,80 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.*; import java.util.function.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
* 序列化/反序列化操作类 * 序列化/反序列化操作类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* @param <R> Reader输入的子类 * @param <R> Reader输入的子类
* @param <W> Writer输出的子类 * @param <W> Writer输出的子类
*/ */
public abstract class Convert<R extends Reader, W extends Writer> { public abstract class Convert<R extends Reader, W extends Writer> {
protected final ConvertFactory<R, W> factory; protected final ConvertFactory<R, W> factory;
protected Convert(ConvertFactory<R, W> factory) { protected Convert(ConvertFactory<R, W> factory) {
this.factory = factory; this.factory = factory;
} }
public ConvertFactory<R, W> getFactory() { public ConvertFactory<R, W> getFactory() {
return this.factory; return this.factory;
} }
protected <S extends W> S configWrite(S writer) { protected <S extends W> S configWrite(S writer) {
return writer; return writer;
} }
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) { protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
writer.objFieldFunc = objFieldFunc; writer.objFieldFunc = objFieldFunc;
writer.objExtFunc = objExtFunc; writer.objExtFunc = objExtFunc;
return writer; return writer;
} }
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc); public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc); public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
public abstract boolean isBinary(); public abstract boolean isBinary();
public abstract <T> T convertFrom(final Type type, final byte[] bytes); public abstract <T> T convertFrom(final Type type, final byte[] bytes);
//@since 2.2.0 //@since 2.2.0
public abstract <T> T convertFrom(final Type type, final byte[] bytes, final int offset, final int length); public abstract <T> T convertFrom(final Type type, final byte[] bytes, final int offset, final int length);
public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers); public abstract <T> T convertFrom(final Type type, final ByteBuffer... buffers);
public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers); public abstract <T> T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers);
public abstract byte[] convertToBytes(final Object value); public abstract void convertTo(final W writer, final Object value);
public abstract byte[] convertToBytes(final Type type, final Object value); public abstract void convertTo(final W writer, final Type type, final Object value);
public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler); public abstract byte[] convertToBytes(final Object value);
public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler); public abstract byte[] convertToBytes(final Type type, final Object value);
public abstract void convertToBytes(final ByteArray array, final Object value); public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler);
public abstract void convertToBytes(final ByteArray array, final Type type, final Object value); public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value); public abstract void convertToBytes(final ByteArray array, final Object value);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value); public abstract void convertToBytes(final ByteArray array, final Type type, final Object value);
} public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Object value);
public abstract ByteBuffer[] convertTo(final Supplier<ByteBuffer> supplier, final Type type, final Object value);
}

View File

@@ -1,23 +1,23 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* *
* convertToBytes系列的方法的回调 * convertToBytes系列的方法的回调
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* *
* @since 2.3.0 * @since 2.3.0
*/ */
public interface ConvertBytesHandler { public interface ConvertBytesHandler {
<A> void completed(byte[] bs, int offset, int length, Consumer<A> callback, A attachment); <A> void completed(byte[] bs, int offset, int length, Consumer<A> callback, A attachment);
} }

View File

@@ -1,71 +1,71 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.annotation.*; import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*; import static java.lang.annotation.RetentionPolicy.*;
/** /**
* 依附在settergetter方法字段进行简单的配置 * 依附在settergetter方法字段进行简单的配置
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@Documented @Documented
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
@Repeatable(ConvertColumn.ConvertColumns.class) @Repeatable(ConvertColumn.ConvertColumns.class)
public @interface ConvertColumn { public @interface ConvertColumn {
/** /**
* 给字段取个别名 * 给字段取个别名
* *
* @return 字段别名 * @return 字段别名
*/ */
String name() default ""; String name() default "";
/** /**
* 给字段取个序号ID值小靠前 * 给字段取个序号ID值小靠前
* *
* @return 字段排序ID * @return 字段排序ID
*/ */
int index() default 0; int index() default 0;
/** /**
* 解析/序列化时是否屏蔽该字段 * 解析/序列化时是否屏蔽该字段
* *
* @return 是否屏蔽该字段 * @return 是否屏蔽该字段
*/ */
boolean ignore() default false; boolean ignore() default false;
/** /**
* 解析/序列化定制化的TYPE * 解析/序列化定制化的TYPE
* *
* @return JSON or BSON or ALL * @return JSON or BSON or ALL
*/ */
ConvertType type() default ConvertType.ALL; ConvertType type() default ConvertType.ALL;
/** /**
* ConvertColumn 的多用类 * ConvertColumn 的多用类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@Documented @Documented
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public static @interface ConvertColumns { public static @interface ConvertColumns {
ConvertColumn[] value(); ConvertColumn[] value();
} }
} }

View File

@@ -1,97 +1,97 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
/** /**
* ConvertColumn 对应的实体类 * ConvertColumn 对应的实体类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public final class ConvertColumnEntry { public final class ConvertColumnEntry {
private int index; private int index;
private String name = ""; private String name = "";
private boolean ignore; private boolean ignore;
private ConvertType convertType; private ConvertType convertType;
public ConvertColumnEntry() { public ConvertColumnEntry() {
} }
public ConvertColumnEntry(ConvertColumn column) { public ConvertColumnEntry(ConvertColumn column) {
if (column == null) return; if (column == null) return;
this.name = column.name(); this.name = column.name();
this.index = column.index(); this.index = column.index();
this.ignore = column.ignore(); this.ignore = column.ignore();
this.convertType = column.type(); this.convertType = column.type();
} }
public ConvertColumnEntry(String name) { public ConvertColumnEntry(String name) {
this(name, false); this(name, false);
} }
public ConvertColumnEntry(String name, boolean ignore) { public ConvertColumnEntry(String name, boolean ignore) {
this.name = name; this.name = name;
this.ignore = ignore; this.ignore = ignore;
this.convertType = ConvertType.ALL; this.convertType = ConvertType.ALL;
} }
public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) { public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) {
this.name = name; this.name = name;
this.ignore = ignore; this.ignore = ignore;
this.convertType = convertType; this.convertType = convertType;
} }
public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) { public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) {
this.name = name; this.name = name;
this.index = index; this.index = index;
this.ignore = ignore; this.ignore = ignore;
this.convertType = convertType; this.convertType = convertType;
} }
public String name() { public String name() {
return name == null ? "" : name; return name == null ? "" : name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public boolean ignore() { public boolean ignore() {
return ignore; return ignore;
} }
public void setIgnore(boolean ignore) { public void setIgnore(boolean ignore) {
this.ignore = ignore; this.ignore = ignore;
} }
public ConvertType type() { public ConvertType type() {
return convertType == null ? ConvertType.ALL : convertType; return convertType == null ? ConvertType.ALL : convertType;
} }
public void setConvertType(ConvertType convertType) { public void setConvertType(ConvertType convertType) {
this.convertType = convertType; this.convertType = convertType;
} }
public int getIndex() { public int getIndex() {
return index; return index;
} }
public void setIndex(int index) { public void setIndex(int index) {
this.index = index; this.index = index;
} }
@Override @Override
public String toString() { public String toString() {
return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}'; return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}';
} }
} }

View File

@@ -1,47 +1,47 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.annotation.*; import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 序列化时永久禁用该字段, 与ConvertColumn.ignore()的区别在于: ConvertDisabled不能通过ConvertEntity来解禁 * 序列化时永久禁用该字段, 与ConvertColumn.ignore()的区别在于: ConvertDisabled不能通过ConvertEntity来解禁
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ConvertDisabled { public @interface ConvertDisabled {
/** /**
* 解析/序列化定制化的TYPE * 解析/序列化定制化的TYPE
* *
* @return JSON or BSON or ALL * @return JSON or BSON or ALL
*/ */
ConvertType type() default ConvertType.ALL; ConvertType type() default ConvertType.ALL;
/** /**
* ConvertDisabled 的多用类 * ConvertDisabled 的多用类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@Documented @Documented
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public static @interface ConvertDisableds { public static @interface ConvertDisableds {
ConvertDisabled[] value(); ConvertDisabled[] value();
} }
} }

View File

@@ -1,33 +1,33 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* 用于类名的别名, 该值必须是全局唯一 <br> * 用于类名的别名, 该值必须是全局唯一 <br>
* 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名关联方法: Reader.readClassName() Writer.writeClassName(String value) * 使用场景: 当BSON序列化为了不指定class可以使用@ConvertEntity来取个别名关联方法: Reader.readClassName() Writer.writeClassName(String value)
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
@Inherited @Inherited
@Documented @Documented
@Target({TYPE}) @Target({TYPE})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ConvertEntity { public @interface ConvertEntity {
/** /**
* 别名值 * 别名值
* *
* @return String * @return String
*/ */
String value(); String value();
} }

View File

@@ -1,32 +1,32 @@
/* /*
* To change this template, choose Tools | Templates * To change this template, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package org.redkale.convert; package org.redkale.convert;
/** /**
* 序列化自定义异常类 * 序列化自定义异常类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class ConvertException extends RuntimeException { public class ConvertException extends RuntimeException {
public ConvertException() { public ConvertException() {
super(); super();
} }
public ConvertException(String s) { public ConvertException(String s) {
super(s); super(s);
} }
public ConvertException(String message, Throwable cause) { public ConvertException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public ConvertException(Throwable cause) { public ConvertException(Throwable cause) {
super(cause); super(cause);
} }
} }

View File

@@ -1,102 +1,102 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
/** /**
* newConvert参数中的Function返回结果的数据类 * newConvert参数中的Function返回结果的数据类
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public class ConvertField implements Serializable { public class ConvertField implements Serializable {
protected String name; protected String name;
protected Type type; protected Type type;
protected int position; protected int position;
protected Object value; protected Object value;
public ConvertField() { public ConvertField() {
} }
public ConvertField(String name, Object value) { public ConvertField(String name, Object value) {
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
public ConvertField(String name, int position, Object value) { public ConvertField(String name, int position, Object value) {
this.name = name; this.name = name;
this.position = position; this.position = position;
this.value = value; this.value = value;
} }
public ConvertField(String name, Type type, Object value) { public ConvertField(String name, Type type, Object value) {
this.name = name; this.name = name;
this.type = type; this.type = type;
this.value = value; this.value = value;
} }
public ConvertField(String name, Type type, int position, Object value) { public ConvertField(String name, Type type, int position, Object value) {
this.name = name; this.name = name;
this.type = type; this.type = type;
this.position = position; this.position = position;
this.value = value; this.value = value;
} }
public static ConvertField[] ofArray(Object... items) { public static ConvertField[] ofArray(Object... items) {
int len = items.length / 2; int len = items.length / 2;
ConvertField[] rs = new ConvertField[len]; ConvertField[] rs = new ConvertField[len];
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]); rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]);
} }
return rs; return rs;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Type getType() { public Type getType() {
return type; return type;
} }
public void setType(Type type) { public void setType(Type type) {
this.type = type; this.type = type;
} }
public int getPosition() { public int getPosition() {
return position; return position;
} }
public void setPosition(int position) { public void setPosition(int position) {
this.position = position; this.position = position;
} }
public Object getValue() { public Object getValue() {
return value; return value;
} }
public void setValue(Object value) { public void setValue(Object value) {
this.value = value; this.value = value;
} }
@Override @Override
public String toString() { public String toString() {
return JsonConvert.root().convertTo(this); return JsonConvert.root().convertTo(this);
} }
} }

View File

@@ -0,0 +1,53 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 用于序列化时接口或抽象类的默认实现类, 被标记的类必须是接口或抽象类 <br>
* 使用场景: <br>
*
* <blockquote><pre>
* &#64;ConvertImpl(OneImpl.class)
* public interface OneEntity {
* public String getName();
* }
*
*
* public class OneImpl implements OneEntity {
* private String name;
* public String getName(){return name;}
* public void setName(String name){this.name=name;}
* }
*
*
* String json = "{'name':'hello'}";
* OneEntity one = JsonConvert.root.convertFrom(OneEntity.class, json);
* //one instanceof OneImpl
*
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.5.0
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ConvertImpl {
/**
* 默认的实现类
*
* @return String
*/
Class value();
}

View File

@@ -1,25 +1,25 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
/** /**
* Mask接口 * Mask接口
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public interface ConvertMask { public interface ConvertMask {
default byte mask(byte value) { default byte mask(byte value) {
return value; return value;
} }
default byte unmask(byte value) { default byte unmask(byte value) {
return value; return value;
} }
} }

View File

@@ -1,23 +1,23 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
/** /**
* Convert的扩展实现类加载器 * Convert的扩展实现类加载器
* *
* *
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* *
* @since 2.2.0 * @since 2.5.0
*/ */
public interface ConvertLoader { public interface ConvertProvider {
public ConvertType type(); public ConvertType type();
public Convert convert(); public Convert convert();
} }

View File

@@ -1,27 +1,27 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
import java.lang.annotation.*; import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串 * 序列化时标记String字段的值是否为无转义字符且长度不超过255的字符串
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
* *
* @since 2.3.0 * @since 2.3.0
* *
*/ */
@Target({METHOD, FIELD}) @Target({METHOD, FIELD})
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface ConvertSmallString { public @interface ConvertSmallString {
} }

View File

@@ -1,46 +1,46 @@
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* 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; package org.redkale.convert;
/** /**
* 序列化类型枚举结合&#64;ConvertColumn使用 * 序列化类型枚举结合&#64;ConvertColumn使用
* *
* <p> * <p>
* 详情见: https://redkale.org * 详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public enum ConvertType { public enum ConvertType {
JSON(1), JSON(1),
BSON(2), BSON(2),
PROTOBUF(64), PROTOBUF(64),
PROTOBUF_JSON(64 + 1), PROTOBUF_JSON(64 + 1),
DIY(256), DIY(256),
ALL(1023); ALL(1023);
private final int value; private final int value;
private ConvertType(int v) { private ConvertType(int v) {
this.value = v; this.value = v;
} }
public int getValue() { public int getValue() {
return value; return value;
} }
public boolean contains(ConvertType type) { public boolean contains(ConvertType type) {
if (type == null) return false; if (type == null) return false;
return this.value >= type.value && (this.value & type.value) > 0; return this.value >= type.value && (this.value & type.value) > 0;
} }
public static ConvertType find(int value) { public static ConvertType find(int value) {
for (ConvertType t : ConvertType.values()) { for (ConvertType t : ConvertType.values()) {
if (value == t.value) return t; if (value == t.value) return t;
} }
return null; return null;
} }
} }

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