112 Commits
1.5.1 ... 1.7.0

Author SHA1 Message Date
Redkale
f9f2e080da 2017-04-30 19:25:33 +08:00
Redkale
027fa3a18b 2017-04-30 19:25:13 +08:00
Redkale
d9f50d63f0 2017-04-30 18:48:10 +08:00
Redkale
181486c348 2017-04-30 18:30:53 +08:00
Redkale
74adfdfc99 2017-04-30 17:33:15 +08:00
Redkale
c3783eb041 2017-04-30 17:08:59 +08:00
Redkale
77451561e6 2017-04-23 21:22:38 +08:00
Redkale
59d30b05f2 2017-04-23 21:08:18 +08:00
Redkale
2fcf0bb644 2017-04-23 21:03:08 +08:00
Redkale
71ab9c9728 去掉ServiceWrapper 2017-04-23 20:19:07 +08:00
Redkale
09165127e3 2017-04-23 16:47:24 +08:00
Redkale
c28310e0df 2017-04-23 16:03:24 +08:00
Redkale
51435a1c33 2017-04-23 14:19:34 +08:00
Redkale
83c70b9767 2017-04-20 22:03:07 +08:00
Redkale
5534dcd476 2017-04-20 15:03:32 +08:00
Redkale
d18a55deaf 2017-04-20 14:32:15 +08:00
Redkale
ae2d64991c 2017-04-20 14:28:59 +08:00
Redkale
ecb6b80e5e 2017-04-20 14:10:48 +08:00
Redkale
cf332fa67a 2017-04-20 14:08:13 +08:00
Redkale
ffa80c9212 2017-04-20 12:21:47 +08:00
Redkale
7463a8f6b5 2017-04-19 22:58:03 +08:00
Redkale
a168897784 2017-04-19 22:42:04 +08:00
Redkale
d39b3856ca 2017-04-19 18:52:20 +08:00
Redkale
ca9f74185b 2017-04-19 09:50:17 +08:00
Redkale
c35e421ba3 2017-04-19 07:55:45 +08:00
Redkale
65755e0787 2017-04-19 07:54:05 +08:00
Redkale
366c3becc4 2017-04-19 07:44:59 +08:00
Redkale
a1ac6ec543 2017-04-18 17:10:41 +08:00
Redkale
b27bbb7836 2017-03-31 08:11:46 +08:00
Redkale
a57574dd10 2017-03-30 23:19:54 +08:00
Redkale
a7dd22569c 2017-03-30 16:53:20 +08:00
Redkale
0bc0755fb3 2017-03-29 13:55:16 +08:00
Redkale
c2edb60218 2017-03-28 10:42:11 +08:00
Redkale
60c1a82a62 2017-03-27 10:03:55 +08:00
Redkale
e3205128b4 2017-03-27 08:23:22 +08:00
Redkale
a9dff0360f 2017-03-26 15:42:56 +08:00
Redkale
1e871cbee5 2017-03-26 15:02:54 +08:00
Redkale
41aadf33f3 2017-03-26 14:28:06 +08:00
Redkale
679567c85a 2017-03-26 14:15:36 +08:00
Redkale
b77050250c 2017-03-25 22:03:19 +08:00
Redkale
e178d1120b 2017-03-25 14:36:10 +08:00
Redkale
eca138b671 2017-03-24 11:28:01 +08:00
Redkale
0366aef672 2017-03-24 11:11:11 +08:00
Redkale
30103e5c8f 2017-03-23 14:20:35 +08:00
Redkale
cbba7701d8 2017-03-23 14:17:06 +08:00
Redkale
da53bd7db9 2017-03-23 11:20:43 +08:00
Redkale
9e7999da0f 2017-03-22 16:42:54 +08:00
Redkale
2c96f991d5 2017-03-22 16:36:09 +08:00
Redkale
67f8127452 2017-03-22 16:34:51 +08:00
Redkale
bce498885e 异步接口支持AsyncHandler子类 2017-03-22 16:05:10 +08:00
Redkale
eb57a25698 PrepareServlet.addServlet方法改为线程安全 2017-03-22 11:56:21 +08:00
Redkale
4e83e5bf71 2017-03-22 11:28:21 +08:00
Redkale
19a44ce8cf 2017-03-22 10:31:14 +08:00
Redkale
0bd0df3245 2017-03-21 17:16:28 +08:00
Redkale
4f0163736f 2017-03-21 13:09:11 +08:00
Redkale
8d03f52f09 2017-03-21 13:06:15 +08:00
Redkale
815267a590 2017-03-21 12:53:00 +08:00
Redkale
77f8d442b2 2017-03-21 12:45:41 +08:00
Redkale
aacda5d35e 2017-03-21 12:35:12 +08:00
Redkale
58d02f6471 2017-03-21 12:32:42 +08:00
Redkale
c735874cff 2017-03-21 12:02:54 +08:00
Redkale
045029b4a9 2017-03-21 11:55:57 +08:00
Redkale
f6b5882cd4 2017-03-21 11:45:40 +08:00
Redkale
63a9005e6b 2017-03-21 09:47:18 +08:00
Redkale
c4923f317b 2017-03-21 09:34:35 +08:00
Redkale
15e03c0459 2017-03-21 09:14:32 +08:00
Redkale
74f4ddf50b 2017-03-20 22:37:13 +08:00
Redkale
fdc868641d 2017-03-20 21:05:28 +08:00
Redkale
910eb88c55 2017-03-20 17:54:58 +08:00
Redkale
b597131de4 2017-03-20 17:33:32 +08:00
Redkale
56d5f97556 2017-03-20 17:08:54 +08:00
Redkale
b364dd5811 Service异步接口的返回类型强制约束为void,且必须存在对应的同步方法 2017-03-20 16:15:07 +08:00
Redkale
4fec27498c 2017-03-20 13:53:13 +08:00
Redkale
7a195ecf23 2017-03-20 13:37:40 +08:00
Redkale
95b7e819cd 2017-03-20 13:25:42 +08:00
Redkale
73d243aaf1 2017-03-20 10:59:08 +08:00
Redkale
998fecdd51 2017-03-19 21:36:16 +08:00
Redkale
b1ddc0e3a5 2017-03-18 19:21:05 +08:00
Redkale
641ff4709d 2017-03-18 19:16:06 +08:00
Redkale
13f2fbf7d6 2017-03-17 20:18:18 +08:00
Redkale
62f9882314 2017-03-17 20:08:24 +08:00
Redkale
7f270eb9d7 2017-03-17 20:04:09 +08:00
Redkale
974a6bfeaa 2017-03-17 18:18:58 +08:00
Redkale
4958b454af 2017-03-17 18:04:17 +08:00
Redkale
3531d0963d 2017-03-17 17:57:24 +08:00
Redkale
41e6497a2e 2017-03-17 16:49:55 +08:00
Redkale
3439fab690 2017-03-17 16:07:41 +08:00
Redkale
14274c8d04 2017-03-17 15:57:49 +08:00
Redkale
b3cbd9be71 2017-03-17 15:21:35 +08:00
Redkale
b1d810188c 2017-03-17 14:54:00 +08:00
Redkale
4b48f85162 2017-03-17 13:20:26 +08:00
Redkale
738b02e1b9 优化DataSource的异步接口 2017-03-17 13:09:28 +08:00
Redkale
dc487f9226 2017-03-17 12:03:42 +08:00
Redkale
bb2f43c317 2017-03-17 09:26:44 +08:00
Redkale
be61aef123 Service、DataSource、CacheSource增加异步接口 2017-03-16 20:04:20 +08:00
Redkale
6ad7888e85 2017-03-16 20:02:34 +08:00
Redkale
242adb3c9e 2017-03-16 17:46:38 +08:00
Redkale
8654c69d0c 2017-03-16 17:38:18 +08:00
Redkale
a7999ff160 2017-03-14 17:03:29 +08:00
Redkale
9c04b8aab0 2017-03-10 18:59:36 +08:00
Redkale
3643fefc9c 2017-03-09 17:22:02 +08:00
Redkale
47189901e5 2017-03-09 15:44:43 +08:00
Redkale
2577684897 2017-03-09 15:08:36 +08:00
Redkale
77396df8fd 2017-03-09 14:04:36 +08:00
Redkale
c517a1d469 增加javadoc注释 2017-03-09 11:44:12 +08:00
Redkale
b7d7e6567b 2017-03-09 11:19:13 +08:00
Redkale
67807e913e 2017-03-09 09:49:14 +08:00
Redkale
19a950dab5 2017-03-08 20:04:09 +08:00
Redkale
79b91f8386 @WebAction替换成@WebMapping 2017-03-08 18:56:07 +08:00
Redkale
0359a4b7e9 2017-03-08 17:28:33 +08:00
Redkale
d89f410749 2017-03-08 17:22:56 +08:00
Redkale
850f6dd060 2017-03-08 17:05:21 +08:00
108 changed files with 7059 additions and 1657 deletions

32
assembly.xml Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>redkale</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/bin</directory>
<outputDirectory>bin</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/conf</directory>
<outputDirectory>conf</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/logs</directory>
<outputDirectory>logs</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<useTransitiveDependencies>false</useTransitiveDependencies>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<application port="5050">
<!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml -->
<resources>
<!--
<properties>
@@ -9,6 +12,7 @@
-->
</resources>
<server protocol="HTTP" host="0.0.0.0" port="6060" root="root">
<!--
<request>

36
pom.xml
View File

@@ -6,7 +6,7 @@
<packaging>jar</packaging>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>1.4.0-SNAPSHOT</version>
<version>1.6.2</version>
<licenses>
<license>
<name>Apache 2</name>
@@ -122,19 +122,29 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>redkale</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>3.0.22</version>
</dependency>
</dependencies>
</project>

View File

@@ -59,7 +59,7 @@
</group>
<!--
【节点全局唯一】
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入, 被注解的字段类型只能是String、primitive class
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
load: 加载文件,多个用;隔开。
@@ -70,6 +70,8 @@
System.setProperty("convert.bson.pool.size", "128");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
<properties>节点下也可包含非<property>节点,其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
-->
<properties load="config.properties">
<property name="system.property.yyyy" value="YYYYYY"/>
@@ -77,6 +79,7 @@
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</properties>
</resources>
<!--
protocol: required server所启动的协议Redkale内置的有HTTP、SNCPSNCP使用TCP实现;

View File

@@ -6,6 +6,11 @@
<!-- 为NONE表示不启动缓存@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<!--
DataSource的实现类没有设置默认为org.redkale.source.DataJdbcSource的实现使用常规基于JDBC的数据库驱动一般无需设置
-->
<property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
<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的子类。

View File

@@ -16,7 +16,7 @@ import org.redkale.util.*;
/**
* API接口文档生成类作用生成Application实例中所有HttpServer的可用HttpServlet的API接口方法 <br>
* 继承 HttpBaseServlet 是为了获取 WebAction 信息
* 继承 HttpBaseServlet 是为了获取 WebMapping 信息
*
* <p>
* 详情见: https://redkale.org
@@ -52,19 +52,19 @@ public class ApiDocs extends HttpBaseServlet {
}
final Map<String, Object> servletmap = new LinkedHashMap<>();
String prefix = _prefix(servlet);
String[] mappings = ws.value();
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix + mappings[i];
for (int i = 0; i < urlregs.length; i++) {
urlregs[i] = prefix + urlregs[i];
}
}
servletmap.put("mappings", mappings);
servletmap.put("urlregs", urlregs);
servletmap.put("moduleid", ws.moduleid());
servletmap.put("name", ws.name());
servletmap.put("comment", ws.comment());
List<Map> actionsList = new ArrayList<>();
servletmap.put("actions", actionsList);
List<Map> mappingsList = new ArrayList<>();
servletmap.put("mappings", mappingsList);
final Class selfClz = servlet.getClass();
Class clz = servlet.getClass();
HashSet<String> actionurls = new HashSet<>();
@@ -72,18 +72,18 @@ public class ApiDocs extends HttpBaseServlet {
if (Modifier.isAbstract(clz.getModifiers())) break;
for (Method method : clz.getMethods()) {
if (method.getParameterCount() != 2) continue;
WebAction action = method.getAnnotation(WebAction.class);
WebMapping action = method.getAnnotation(WebMapping.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final Map<String, Object> actionmap = new LinkedHashMap<>();
final Map<String, Object> mappingmap = new LinkedHashMap<>();
if (actionurls.contains(action.url())) continue;
actionmap.put("url", prefix + action.url());
mappingmap.put("url", prefix + action.url());
actionurls.add(action.url());
actionmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
actionmap.put("actionid", action.actionid());
actionmap.put("comment", action.comment());
mappingmap.put("auth", method.getAnnotation(AuthIgnore.class) == null);
mappingmap.put("actionid", action.actionid());
mappingmap.put("comment", action.comment());
List<Map> paramsList = new ArrayList<>();
actionmap.put("params", paramsList);
mappingmap.put("params", paramsList);
List<String> results = new ArrayList<>();
for (final Class rtype : action.results()) {
results.add(rtype.getName());
@@ -121,7 +121,7 @@ public class ApiDocs extends HttpBaseServlet {
} while ((loop = loop.getSuperclass()) != Object.class);
typesmap.put(rtype.getName(), typemap);
}
actionmap.put("results", results);
mappingmap.put("results", results);
for (WebParam param : method.getAnnotationsByType(WebParam.class)) {
final Map<String, Object> parammap = new LinkedHashMap<>();
final boolean isarray = param.type().isArray();
@@ -171,17 +171,17 @@ public class ApiDocs extends HttpBaseServlet {
typesmap.put(ptype.getName(), typemap);
}
actionmap.put("result", action.result());
actionsList.add(actionmap);
mappingmap.put("result", action.result());
mappingsList.add(mappingmap);
}
} while ((clz = clz.getSuperclass()) != HttpServlet.class);
actionsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url")));
servletsList.add(servletmap);
}
servletsList.sort((o1, o2) -> {
String[] mappings1 = (String[]) o1.get("mappings");
String[] mappings2 = (String[]) o2.get("mappings");
return mappings1.length > 0 ? (mappings2.length > 0 ? mappings1[0].compareTo(mappings2[0]) : 1) : -1;
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;
});
}
Map<String, Object> resultmap = new LinkedHashMap<>();
@@ -205,7 +205,7 @@ public class ApiDocs extends HttpBaseServlet {
}
@Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
next.execute(request, response);
}
}

View File

@@ -118,6 +118,9 @@ public final class Application {
//全局根ResourceFactory
final ResourceFactory resourceFactory = ResourceFactory.root();
//服务配置项
final AnyValue config;
//临时计数器
CountDownLatch servicecdl; //会出现两次赋值
@@ -134,9 +137,6 @@ public final class Application {
//日志
private final Logger logger;
//服务配置项
private final AnyValue config;
//服务启动时间
private final long startTime = System.currentTimeMillis();
@@ -307,7 +307,7 @@ public final class Application {
File persist = new File(this.home, "conf/persistence.xml");
final String homepath = this.home.getCanonicalPath();
if (persist.isFile()) System.setProperty(DataDefaultSource.DATASOURCE_CONFPATH, persist.getCanonicalPath());
if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
logger.log(Level.INFO, RESNAME_APP_HOME + "= " + homepath + "\r\n" + RESNAME_APP_ADDR + "= " + this.localAddress.getHostAddress());
String lib = config.getValue("lib", "").trim().replace("${APP_HOME}", homepath);
lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
@@ -338,6 +338,7 @@ public final class Application {
String name = prop.getValue("name");
String value = prop.getValue("value");
if (name == null || value == null) continue;
value = value.replace("${APP_HOME}", home.getCanonicalPath()).replace('\\', '/');
if (name.startsWith("system.property.")) {
System.setProperty(name.substring("system.property.".length()), value);
} else if (name.startsWith("mimetype.property.")) {
@@ -350,11 +351,6 @@ public final class Application {
}
}
}
if (this.localAddress != null && this.resourceFactory.find("property.datasource.nodeid", String.class) == null) {
byte[] bs = this.localAddress.getAddress();
int v = (0xff & bs[bs.length - 2]) % 10 * 100 + (0xff & bs[bs.length - 1]);
this.resourceFactory.register("property.datasource.nodeid", "" + v);
}
this.resourceFactory.register(BsonFactory.root());
this.resourceFactory.register(JsonFactory.root());
this.resourceFactory.register(BsonFactory.root().getConvert());

View File

@@ -7,6 +7,7 @@ package org.redkale.boot;
import java.net.InetSocketAddress;
import java.util.*;
import org.redkale.convert.json.JsonConvert;
/**
* 协议地址组合对象, 对应application.xml 中 resources-&#62;group 节点信息
@@ -72,4 +73,8 @@ public class GroupInfo {
this.addrs = addrs;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
}

View File

@@ -74,7 +74,7 @@ public class NodeHttpServer extends NodeServer {
synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) {
nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (Transport) null, (Collection<Transport>) null);
nodeService = Sncp.createLocalService(resourceName, getExecutor(), application.getResourceFactory(), WebSocketNodeService.class, (InetSocketAddress) null, (String) null, (Set<String>) null, (AnyValue) null, (Transport) null, (Collection<Transport>) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
resourceFactory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
@@ -109,13 +109,6 @@ public class NodeHttpServer extends NodeServer {
final String[] mappings = ws.value();
String pref = ws.repair() ? prefix : "";
DefaultAnyValue servletConf = (DefaultAnyValue) en.getProperty();
WebInitParam[] webparams = ws.initParams();
if (webparams.length > 0) {
if (servletConf == null) servletConf = new DefaultAnyValue();
for (WebInitParam webparam : webparams) {
servletConf.addValue(webparam.name(), webparam.value());
}
}
this.httpServer.addHttpServlet(servlet, pref, servletConf, mappings);
if (ss != null) {
for (int i = 0; i < mappings.length; i++) {
@@ -124,9 +117,9 @@ public class NodeHttpServer extends NodeServer {
ss.add(new AbstractMap.SimpleEntry<>(clazz.getName(), mappings));
}
}
int max = 0;
if (ss != null && sb != null) {
Collections.sort(ss, (AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
int max = 0;
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
@@ -138,18 +131,17 @@ public class NodeHttpServer extends NodeServer {
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
if (rest && serverConf != null) {
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(prefix, restConf);
loadRestServlet(prefix, restConf, sb);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
protected void loadRestServlet(final String prefix, final AnyValue restConf) throws Exception {
protected void loadRestServlet(final String prefix, final AnyValue restConf, final StringBuilder sb) throws Exception {
if (!rest) return;
if (restConf == null) return; //不存在REST服务
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
@@ -170,8 +162,9 @@ public class NodeHttpServer extends NodeServer {
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
super.interceptorServiceWrappers.forEach((wrapper) -> {
final Class stype = wrapper.getType();
super.interceptorServices.forEach((service) -> {
final Class stype = Sncp.getServiceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs != null && rs.ignore()) return;
if (mustsign && rs == null) return;
@@ -181,18 +174,16 @@ public class NodeHttpServer extends NodeServer {
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
RestHttpServlet servlet = httpServer.addRestServlet(wrapper.getName(), stype, wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
RestHttpServlet servlet = httpServer.addRestServlet(name, stype, service, baseServletClass, prefix, (AnyValue) null);
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest("Create RestServlet[resource=" + wrapper.getName() + "] = " + servlet);
if (finest) logger.finest(threadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (ss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix + mappings[i];
}
if (servlet.getClass().getSimpleName().charAt(0) != '_') {
ss.add(new AbstractMap.SimpleEntry<>(servlet.getClass().getName(), mappings));
}
}
});
//输出信息
if (ss != null && sb != null) {
@@ -201,6 +192,7 @@ public class NodeHttpServer extends NodeServer {
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
}
sb.append(threadName).append(" ").append(LINE_SEPARATOR);
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(threadName).append(" Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
@@ -209,6 +201,5 @@ public class NodeHttpServer extends NodeServer {
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
}

View File

@@ -5,9 +5,6 @@
*/
package org.redkale.boot;
import java.util.Objects;
import org.redkale.service.Service;
/**
* NodeServer的拦截类
*
@@ -38,63 +35,4 @@ public class NodeInterceptor {
}
public static class InterceptorServiceWrapper<T extends Service> {
private String name;
private Class<T> type;
private T service;
public InterceptorServiceWrapper() {
}
public InterceptorServiceWrapper(String name, Class<T> type, T service) {
this.name = name;
this.type = type;
this.service = service;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<T> getType() {
return type;
}
public void setType(Class<T> type) {
this.type = type;
}
public T getService() {
return service;
}
public void setService(T service) {
this.service = service;
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + Objects.hashCode(this.name);
hash = 97 * hash + Objects.hashCode(this.type);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final InterceptorServiceWrapper<?> other = (InterceptorServiceWrapper<?>) obj;
return Objects.equals(this.name, other.name) && Objects.equals(this.type, other.type);
}
}
}

View File

@@ -8,7 +8,7 @@ package org.redkale.boot;
import java.lang.annotation.*;
/**
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑
* 根据application.xml中的server节点中的protocol值来适配Server的加载逻辑, 只能注解在NodeServer子类上
*
* <p>
* 详情见: https://redkale.org

View File

@@ -69,7 +69,7 @@ public abstract class NodeServer {
private InetSocketAddress sncpAddress;
//加载Service时的处理函数
protected Consumer<ServiceWrapper> consumer;
protected Consumer<Service> consumer;
//server节点的配置
protected AnyValue serverConf;
@@ -78,13 +78,17 @@ public abstract class NodeServer {
protected NodeInterceptor interceptor;
//供interceptor使用的Service对象集合
protected final Set<NodeInterceptor.InterceptorServiceWrapper> interceptorServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> interceptorServices = new LinkedHashSet<>();
//本地模式的Service对象集合
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> localServices = new LinkedHashSet<>();
//远程模式的Service对象集合
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>();
protected final Set<Service> remoteServices = new LinkedHashSet<>();
private volatile int maxClassNameLength = 0;
private volatile int maxNameLength = 0;
public NodeServer(Application application, Server server) {
this.application = application;
@@ -116,7 +120,7 @@ public abstract class NodeServer {
if (context == null) {
t.run();
} else {
context.submit(t);
context.submitAsync(t);
}
}
@@ -191,11 +195,36 @@ public abstract class NodeServer {
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
//------------------------------------- 注册Resource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
Resource res = field.getAnnotation(Resource.class);
if (res == null || !res.name().startsWith("properties.")) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
Class type = field.getType();
if (type != AnyValue.class && type != AnyValue[].class) return;
Object resource = null;
final AnyValue resources = application.config.getAnyValue("resources");
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
if (properties != null && type == AnyValue.class) {
resource = properties.getAnyValue(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue.class, resource);
} else if (properties != null && type == AnyValue[].class) {
resource = properties.getAnyValues(res.name().substring("properties.".length()));
appResFactory.register(resourceName, AnyValue[].class, resource);
}
field.set(src, resource);
} catch (Exception e) {
logger.log(Level.SEVERE, "Resource inject error", e);
}
}, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 DataSource
DataSource source = new DataDefaultSource(resourceName);
DataSource source = DataSources.createDataSource(resourceName);
application.dataSources.add(source);
appResFactory.register(resourceName, DataSource.class, source);
@@ -204,33 +233,34 @@ public abstract class NodeServer {
List<Transport> diffGroupTransports = Arrays.asList(Sncp.getDiffGroupTransports((Service) src));
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
if ((src instanceof DataSource) && sncpAddr != null && resourceFactory.find(resourceName, DataCacheListener.class) == null) { //只有DataSourceService 才能赋值 DataCacheListener
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
final NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpServer.getSncpGroup(), gs, null);
localServiceWrappers.add(wrapper);
sncpServer.consumerAccept(wrapper);
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, DataCacheListenerService.class, sncpAddr, sncpServer.getSncpGroup(), gs, Sncp.getConf((Service) src), sameGroupTransport, diffGroupTransports);
appResFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
localServices.add(cacheListenerService);
sncpServer.consumerAccept(cacheListenerService);
rf.inject(cacheListenerService, self);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + cacheListenerService);
}
field.set(src, source);
rf.inject(source, self); // 给 "datasource.nodeid" 赋值;
rf.inject(source, self); // 给其可能包含@Resource的字段赋值;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
}
}, DataSource.class);
//------------------------------------- 注册CacheSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不注入 CacheSource
SncpClient client = Sncp.getSncpClient((Service) src);
Transport sameGroupTransport = Sncp.getSameGroupTransport((Service) src);
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不需要注入 CacheSource
final Service srcService = (Service) src;
SncpClient client = Sncp.getSncpClient(srcService);
Transport sameGroupTransport = Sncp.getSameGroupTransport(srcService);
Transport[] dts = Sncp.getDiffGroupTransports((Service) src);
List<Transport> diffGroupTransports = dts == null ? new ArrayList<>() : Arrays.asList(dts);
final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress();
final CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheSourceService.class, sncpAddr, sameGroupTransport, diffGroupTransports);
final CacheMemorySource source = Sncp.createLocalService(resourceName, getExecutor(), appResFactory, CacheMemorySource.class, sncpAddr, Sncp.getSncpGroup(srcService), Sncp.getGroups(srcService), Sncp.getConf(srcService), sameGroupTransport, diffGroupTransports);
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
@@ -243,12 +273,11 @@ public abstract class NodeServer {
rf.inject(source, self); //
((Service) source).init(null);
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheSourceService
if ((src instanceof WebSocketNodeService) && sncpAddr != null) { //只有WebSocketNodeService的服务才需要给SNCP服务注入CacheMemorySource
NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr);
Set<String> gs = application.findSncpGroups(sameGroupTransport, diffGroupTransports);
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, sncpServer.getSncpGroup(), gs, null);
sncpServer.getSncpServer().addSncpServlet(wrapper);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
sncpServer.getSncpServer().addSncpServlet((Service) source);
logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source);
}
logger.info("[" + Thread.currentThread().getName() + "] Load Source " + source);
} catch (Exception e) {
@@ -265,55 +294,55 @@ public abstract class NodeServer {
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
for (FilterEntry<Service> entry : entrys) { //service实现类
final Class<? extends Service> type = entry.getType();
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(type.getModifiers())) continue;
final Class<? extends Service> serviceImplClass = entry.getType();
if (Modifier.isFinal(serviceImplClass.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(serviceImplClass.getModifiers())) continue;
if (entry.isExpect()) {
if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(type)) continue;
if (CacheSource.class.isAssignableFrom(type)) continue;
if (DataCacheListener.class.isAssignableFrom(type)) continue;
if (WebSocketNode.class.isAssignableFrom(type)) continue;
if (Modifier.isAbstract(serviceImplClass.getModifiers())) continue; //修饰abstract的类跳过
if (DataSource.class.isAssignableFrom(serviceImplClass)) continue;
if (CacheSource.class.isAssignableFrom(serviceImplClass)) continue;
if (DataCacheListener.class.isAssignableFrom(serviceImplClass)) continue;
if (WebSocketNode.class.isAssignableFrom(serviceImplClass)) continue;
}
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
Service oldother = resourceFactory.find(entry.getName(), type);
Service oldother = resourceFactory.find(entry.getName(), serviceImplClass);
if (oldother != null) { //Server加载Service时需要判断是否已经加载过了。
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, oldother));
interceptorServices.add(oldother);
continue;
}
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
if (groups.isEmpty() && isSNCP() && this.sncpGroup != null) groups.add(this.sncpGroup);
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) //非SNCP的Server通常是单点服务
final boolean localed = (this.sncpAddress == null && entry.isEmptyGroups() && !serviceImplClass.isInterface() && !Modifier.isAbstract(serviceImplClass.getModifiers())) //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的
|| (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置
|| type.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
|| serviceImplClass.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final BiConsumer<ResourceFactory, Boolean> runner = (ResourceFactory rf, Boolean needinject) -> {
try {
Service service;
if (localed) { //本地模式
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type,
NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups));
service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), serviceImplClass,
NodeServer.this.sncpAddress, NodeServer.this.sncpGroup, groups, entry.getProperty(), loadTransport(NodeServer.this.sncpGroup), loadTransports(groups));
} else {
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups));
service = Sncp.createRemoteService(entry.getName(), getExecutor(), serviceImplClass, NodeServer.this.sncpAddress, null, groups, entry.getProperty(), loadTransport(groups));
}
if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法 通常为BaseService
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : wrapper.getTypes()) {
if (resourceFactory.find(wrapper.getName(), restype) == null) {
regFactory.register(wrapper.getName(), restype, wrapper.getService());
if (needinject) rf.inject(wrapper.getService()); //动态加载的Service也存在按需加载的注入资源
if (SncpClient.parseMethod(serviceImplClass).isEmpty()) return; //class没有可用的方法 通常为BaseService
//final ServiceWrapper wrapper = new ServiceWrapper(serviceImplClass, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty());
for (final Class restype : Sncp.getResourceTypes(service)) {
if (resourceFactory.find(entry.getName(), restype) == null) {
regFactory.register(entry.getName(), restype, service);
if (needinject) rf.inject(service); //动态加载的Service也存在按需加载的注入资源
} else if (isSNCP() && !entry.isAutoload()) {
throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
throw new RuntimeException(restype.getSimpleName() + "(class:" + serviceImplClass.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat.");
}
}
if (wrapper.isRemote()) {
remoteServiceWrappers.add(wrapper);
if (Sncp.isRemote(service)) {
remoteServices.add(service);
} else {
localServiceWrappers.add(wrapper);
interceptorServiceWrappers.add(new NodeInterceptor.InterceptorServiceWrapper(entry.getName(), type, service));
if (consumer != null) consumer.accept(wrapper);
localServices.add(service);
interceptorServices.add(service);
if (consumer != null) consumer.accept(service);
}
} catch (RuntimeException ex) {
throw ex;
@@ -325,7 +354,9 @@ public abstract class NodeServer {
ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> {
runner.accept(rf, true);
};
for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) {
ResourceType rty = entry.getType().getAnnotation(ResourceType.class);
Class[] resTypes = rty == null ? new Class[]{} : rty.value();
for (final Class restype : resTypes) {
resourceFactory.register(resourceLoader, restype);
}
} else {
@@ -339,30 +370,38 @@ public abstract class NodeServer {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
//---------------- inject ----------------
new ArrayList<>(localServiceWrappers).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
new ArrayList<>(localServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
});
new ArrayList<>(remoteServiceWrappers).forEach(y -> {
resourceFactory.inject(y.getService(), NodeServer.this);
new ArrayList<>(remoteServices).forEach(y -> {
resourceFactory.inject(y, NodeServer.this);
calcMaxLength(y);
});
if (sb != null) {
remoteServiceWrappers.forEach(y -> {
sb.append(threadName).append(y.toSimpleString()).append(" load and inject").append(LINE_SEPARATOR);
remoteServices.forEach(y -> {
sb.append(threadName).append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" load and inject").append(LINE_SEPARATOR);
});
}
//----------------- init -----------------
List<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers);
Collections.sort(swlist);
localServiceWrappers.clear();
localServiceWrappers.addAll(swlist);
List<Service> swlist = new ArrayList<>(localServices);
Collections.sort(swlist, (o1, o2) -> {
int rs = Sncp.getResourceTypes(o1)[0].getName().compareTo(Sncp.getResourceTypes(o2)[0].getName());
if (rs == 0) rs = Sncp.getResourceName(o1).compareTo(Sncp.getResourceName(o2));
return rs;
});
localServices.clear();
localServices.addAll(swlist);
final List<String> slist = sb == null ? null : new CopyOnWriteArrayList<>();
CountDownLatch clds = new CountDownLatch(localServiceWrappers.size());
localServiceWrappers.parallelStream().forEach(y -> {
CountDownLatch clds = new CountDownLatch(localServices.size());
localServices.parallelStream().forEach(y -> {
try {
long s = System.currentTimeMillis();
y.getService().init(y.getConf());
y.init(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
if (slist != null) slist.add(new StringBuilder().append(threadName).append(y.toSimpleString()).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
String serstr = Sncp.toSimpleString(y, maxNameLength, maxClassNameLength);
if (slist != null) slist.add(new StringBuilder().append(threadName).append(serstr).append(" load and init in ").append(e).append(" ms").append(LINE_SEPARATOR).toString());
} finally {
clds.countDown();
}
@@ -378,6 +417,20 @@ public abstract class NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
private void calcMaxLength(Service y) { //计算toString中的长度
maxNameLength = Math.max(maxNameLength, Sncp.getResourceName(y).length());
StringBuilder s = new StringBuilder();
Class[] types = Sncp.getResourceTypes(y);
if (types.length == 1) {
s.append(types[0].getName());
} else {
s.append('[');
s.append(Arrays.asList(types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
}
maxClassNameLength = Math.max(maxClassNameLength, s.length() + 1);
}
protected List<Transport> loadTransports(final HashSet<String> groups) {
if (groups == null) return null;
final List<Transport> transports = new ArrayList<>();
@@ -532,12 +585,12 @@ public abstract class NodeServer {
public void shutdown() throws IOException {
if (interceptor != null) interceptor.preShutdown(this);
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
localServiceWrappers.forEach(y -> {
localServices.forEach(y -> {
long s = System.currentTimeMillis();
y.getService().destroy(y.getConf());
y.destroy(Sncp.getConf(y));
long e = System.currentTimeMillis() - s;
if (e > 2 && sb != null) {
sb.append(y.toSimpleString()).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
sb.append(Sncp.toSimpleString(y, maxNameLength, maxClassNameLength)).append(" destroy ").append(e).append("ms").append(LINE_SEPARATOR);
}
});
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
@@ -548,16 +601,16 @@ public abstract class NodeServer {
return (T) server;
}
public Set<NodeInterceptor.InterceptorServiceWrapper> getInterceptorServiceWrappers() {
return new LinkedHashSet<>(interceptorServiceWrappers);
public Set<Service> getInterceptorServices() {
return new LinkedHashSet<>(interceptorServices);
}
public Set<ServiceWrapper> getLocalServiceWrappers() {
return new LinkedHashSet<>(localServiceWrappers);
public Set<Service> getLocalServices() {
return new LinkedHashSet<>(localServices);
}
public Set<ServiceWrapper> getRemoteServiceWrappers() {
return new LinkedHashSet<>(remoteServiceWrappers);
public Set<Service> getRemoteServices() {
return new LinkedHashSet<>(remoteServices);
}
}

View File

@@ -10,9 +10,11 @@ import java.util.*;
import java.util.logging.*;
import org.redkale.net.*;
import org.redkale.net.sncp.*;
import org.redkale.service.Service;
import org.redkale.util.*;
/**
* SNCP Server节点的配置Server
*
* <p>
* 详情见: https://redkale.org
@@ -47,8 +49,8 @@ public class NodeSncpServer extends NodeServer {
return sncpServer == null ? null : sncpServer.getSocketAddress();
}
public void consumerAccept(ServiceWrapper wrapper) {
if (this.consumer != null) this.consumer.accept(wrapper);
public void consumerAccept(Service service) {
if (this.consumer != null) this.consumer.accept(service);
}
@Override

View File

@@ -36,8 +36,8 @@
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>请求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.actions.length; k++) {
var action = servlet.actions[k];
for (var k = 0; k < servlet.mappings.length; k++) {
var action = servlet.mappings[k];
html.push(' <tr>');
html.push('<td style="color:#ff00ff;">' + action.url + '</td>');
html.push('<td>' + action.comment + '</td>');

View File

@@ -92,6 +92,7 @@ public abstract class ConvertFactory<R extends Reader, W extends Writer> {
this.register(InetSocketAddress.class, InetSocketAddressSimpledCoder.instance);
this.register(Pattern.class, PatternSimpledCoder.instance);
this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance);
this.register(AsyncHandler.class, AsyncHandlerSimpledCoder.instance);
this.register(URL.class, URLSimpledCoder.instance);
this.register(URI.class, URISimpledCoder.instance);
//---------------------------------------------------------

View File

@@ -11,7 +11,7 @@ import java.lang.reflect.Type;
import java.util.Map;
/**
* Map的反序列化操作类
* Map的反序列化操作类 <br>
*
* <p>
* 详情见: https://redkale.org

View File

@@ -67,6 +67,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
clazz = (Class) type;
}
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
final Set<DeMember> list = new HashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
@@ -76,7 +77,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(field.getGenericType(), this.type);
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, field, null, null), factory.loadDecoder(t)));
}
final boolean reversible = factory.isReversible();
@@ -99,7 +100,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = ObjectEncoder.createClassType(method.getGenericParameterTypes()[0], this.type);
Type t = TypeToken.createClassType(method.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, null, method), factory.loadDecoder(t)));
}
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
@@ -115,7 +116,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
//不存在setter方法
try {
Field f = clazz.getDeclaredField(constructorField);
Type t = ObjectEncoder.createClassType(f.getGenericType(), this.type);
Type t = TypeToken.createClassType(f.getGenericType(), this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, f, null, null), factory.loadDecoder(t)));
} catch (NoSuchFieldException nsfe) { //不存在field 可能存在getter方法
char[] fs = constructorField.toCharArray();
@@ -127,7 +128,7 @@ public final class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T
} catch (NoSuchMethodException ex) {
getter = clazz.getMethod("is" + mn);
}
Type t = ObjectEncoder.createClassType(getter.getGenericParameterTypes()[0], this.type);
Type t = TypeToken.createClassType(getter.getGenericParameterTypes()[0], this.type);
list.add(new DeMember(ObjectEncoder.createAttribute(factory, clazz, null, getter, null), factory.loadDecoder(t)));
}
}

View File

@@ -68,7 +68,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
if (Modifier.isStatic(field.getModifiers())) continue;
ref = factory.findRef(field);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(field.getGenericType(), this.type);
Type t = TypeToken.createClassType(field.getGenericType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, field, null, null), factory.loadEncoder(t)));
}
for (final Method method : clazz.getMethods()) {
@@ -91,7 +91,7 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
}
ref = factory.findRef(method);
if (ref != null && ref.ignore()) continue;
Type t = createClassType(method.getGenericReturnType(), this.type);
Type t = TypeToken.createClassType(method.getGenericReturnType(), this.type);
list.add(new EnMember(createAttribute(factory, clazz, null, method, null), factory.loadEncoder(t)));
}
this.members = list.toArray(new EnMember[list.size()]);
@@ -146,42 +146,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
}
static Type createClassType(final Type type, final Type declaringType0) {
if (TypeToken.isClassType(type)) return type;
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
final ParameterizedType pt = (ParameterizedType) type;
final Type[] paramTypes = pt.getActualTypeArguments();
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
}
return TypeToken.createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
}
Type declaringType = declaringType0;
if (declaringType instanceof Class) {
do {
declaringType = ((Class) declaringType).getGenericSuperclass();
if (declaringType == Object.class) return Object.class;
} while (declaringType instanceof Class);
}
//存在通配符则declaringType 必须是 ParameterizedType
if (!(declaringType instanceof ParameterizedType)) return Object.class;
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
final Type[] desTypes = declaringPType.getActualTypeArguments();
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
for (Type f : wt.getUpperBounds()) {
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
return type;
}
//
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
// if (type instanceof Class) { //e.g. String
@@ -230,7 +194,6 @@ public final class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T
// }
// return type;
// }
static boolean contains(String[] values, String value) {
for (String str : values) {
if (str.equals(value)) return true;

View File

@@ -9,8 +9,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 简易类的序列化和反序列化操作类
* 能序列化为Boolean、Number或者字符串的类视为简易类
* 简易类的序列化和反序列化操作类 <br>
* 能序列化为Boolean、Number或者字符串的类视为简易类 <br>
*
* <p>
* 详情见: https://redkale.org

View File

@@ -11,6 +11,7 @@ import static org.redkale.convert.Reader.SIGN_NULL;
import org.redkale.util.*;
/**
* 以ByteBuffer为数据载体的BsonReader
*
* 详情见: https://redkale.org
*

View File

@@ -10,6 +10,7 @@ import java.util.function.*;
import org.redkale.util.Utility;
/**
* 以ByteBuffer为数据载体的BsonWriter
*
* <p>
* 详情见: https://redkale.org

View File

@@ -10,6 +10,7 @@ import org.redkale.convert.*;
import org.redkale.util.AnyValue;
/**
* BSON的ConvertFactory
*
* <p>
* 详情见: https://redkale.org

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
* BSON数据源
*
* <p>
* 详情见: https://redkale.org

View File

@@ -236,11 +236,11 @@ public class BsonWriter extends Writer {
return;
}
char[] chars = Utility.charArray(value);
if (chars.length > 255) throw new ConvertException("'" + value + "' has very long length");
if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length");
byte[] bytes = new byte[chars.length + 1];
bytes[0] = (byte) chars.length;
for (int i = 0; i < chars.length; i++) {
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' has double-word");
if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word");
bytes[i + 1] = (byte) chars[i];
}
writeTo(bytes);

View File

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

View File

@@ -38,7 +38,7 @@ public class TypeSimpledCoder<R extends Reader, W extends Writer> extends Simple
if (str == null) return null;
try {
return Class.forName(str);
} catch (Exception e) {
} catch (Throwable e) {
return null;
}
}

View File

@@ -11,6 +11,7 @@ import org.redkale.convert.*;
import static org.redkale.convert.Reader.*;
/**
* 以ByteBuffer为数据载体的JsonReader <br>
*
* 只支持UTF-8格式
*

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.*;
import org.redkale.util.*;
/**
* 以ByteBuffer为数据载体的JsonWriter
*
* <p>
* 详情见: https://redkale.org

View File

@@ -13,6 +13,7 @@ import org.redkale.convert.ext.*;
import org.redkale.util.*;
/**
* JSON的ConvertFactory
*
* <p>
* 详情见: https://redkale.org

View File

@@ -10,6 +10,7 @@ import static org.redkale.convert.Reader.*;
import org.redkale.util.*;
/**
* JSON数据源
*
* <p>
* 详情见: https://redkale.org

View File

@@ -109,8 +109,12 @@ public class Context {
return charset;
}
public void submit(Runnable r) {
executor.submit(r);
public Future<?> submitAsync(Runnable r) {
return executor.submit(r);
}
public void runAsync(Runnable r) {
executor.execute(r);
}
public int getBufferCapacity() {

View File

@@ -34,9 +34,33 @@ public abstract class PrepareServlet<K extends Serializable, C extends Context,
protected final AtomicLong illRequestCounter = new AtomicLong(); //错误请求次数
protected final Set<S> servlets = new HashSet<>();
private final Object lock1 = new Object();
protected final Map<K, S> mappings = new HashMap<>();
private Set<S> servlets = new HashSet<>();
private final Object lock2 = new Object();
private Map<K, S> mappings = new HashMap<>();
protected void putServlet(S servlet) {
synchronized (lock1) {
Set<S> newservlets = new HashSet<>(servlets);
newservlets.add(servlet);
this.servlets = newservlets;
}
}
protected void putMapping(K key, S value) {
synchronized (lock2) {
Map<K, S> newmappings = new HashMap<>(mappings);
newmappings.put(key, value);
this.mappings = newmappings;
}
}
protected S mappingServlet(K key) {
return mappings.get(key);
}
public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings);

View File

@@ -92,7 +92,7 @@ public abstract class ProtocolServer {
SocketAddress address = serchannel.receive(buffer);
buffer.flip();
AsyncConnection conn = AsyncConnection.create(serchannel, address, false, readTimeoutSecond, writeTimeoutSecond);
context.submit(new PrepareRunner(context, conn, buffer));
context.runAsync(new PrepareRunner(context, conn, buffer));
} catch (Exception e) {
context.offerBuffer(buffer);
}
@@ -160,7 +160,7 @@ public abstract class ProtocolServer {
@Override
public void completed(final AsynchronousSocketChannel channel, Void attachment) {
serchannel.accept(null, this);
context.submit(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
context.submitAsync(new PrepareRunner(context, AsyncConnection.create(channel, null, context.readTimeoutSecond, context.writeTimeoutSecond), null));
}
@Override

View File

@@ -117,7 +117,7 @@ public abstract class Response<C extends Context, R extends Request<C>> {
request.recycle();
if (channel != null) {
if (keepAlive) {
this.context.submit(new PrepareRunner(context, channel, null));
this.context.runAsync(new PrepareRunner(context, channel, null));
} else {
try {
if (channel.isOpen()) channel.close();
@@ -162,12 +162,14 @@ public abstract class Response<C extends Context, R extends Request<C>> {
}
public void finish(boolean kill) {
if (!this.inited) return; //避免重复关闭
//System.println("耗时: " + (System.currentTimeMillis() - request.createtime));
if (kill) refuseAlive();
this.context.responsePool.offer(this);
}
public void finish(final byte[] bs) {
if (!this.inited) return; //避免重复关闭
if (this.context.bufferCapacity == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
@@ -179,19 +181,23 @@ public abstract class Response<C extends Context, R extends Request<C>> {
}
public void finish(ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(boolean kill, ByteBuffer buffer) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffer, buffer, finishHandler);
}
public void finish(ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
this.channel.write(buffers, buffers, finishHandler2);
}
public void finish(boolean kill, ByteBuffer... buffers) {
if (!this.inited) return; //避免重复关闭
if (kill) refuseAlive();
this.channel.write(buffers, buffers, finishHandler2);
}

View File

@@ -165,7 +165,7 @@ public final class Transport {
public AsyncConnection pollConnection(SocketAddress addr) {
if (addr == null && remoteAddres.length == 1) addr = remoteAddres[0];
final boolean rand = addr == null;
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") has no remoteAddress list");
if (rand && remoteAddres.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list");
try {
if (tcp) {
AsynchronousSocketChannel channel = null;

View File

@@ -25,8 +25,8 @@ public class WorkThread extends Thread {
this.setDaemon(true);
}
public void submit(Runnable runner) {
executor.submit(runner);
public void runAsync(Runnable runner) {
executor.execute(runner);
}
public ExecutorService getExecutor() {

View File

@@ -22,8 +22,8 @@ public class DefaultRestServlet extends RestHttpServlet<Object> {
}
@Override
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
next.execute(request, response);
}
}

View File

@@ -66,8 +66,8 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
/**
* 配合 &#64;WebAction 使用。
* 用于对&#64;WebAction方法中参数描述
* 配合 &#64;WebMapping 使用。
* 用于对&#64;WebMapping方法中参数描述
*
* <p>
* 详情见: https://redkale.org
@@ -101,6 +101,34 @@ public abstract class HttpBaseServlet extends HttpServlet {
WebParam[] value();
}
/**
* 使用 WebMapping 替代。
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Deprecated
@Documented
@Target({METHOD})
@Retention(RUNTIME)
protected @interface WebAction {
int actionid() default 0;
String url();
String[] methods() default {};//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法
String comment() default ""; //备注描述
boolean inherited() default true; //是否能被继承, 当 HttpBaseServlet 被继承后该方法是否能被子类继承
String result() default "Object"; //输出结果的数据类型
Class[] results() default {}; //输出结果的数据类型集合,由于结果类型可能是泛型而注解的参数值不支持泛型,因此加入明细数据类型集合
}
/**
* 配合 HttpBaseServlet 使用。
* 用于对&#64;WebServlet对应的url进行细分。 其url必须是包含WebServlet中定义的前缀 且不能是正则表达式
@@ -113,7 +141,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
@Documented
@Target({METHOD})
@Retention(RUNTIME)
protected @interface WebAction {
protected @interface WebMapping {
int actionid() default 0;
@@ -153,23 +181,12 @@ public abstract class HttpBaseServlet extends HttpServlet {
int seconds() default 15;
}
private Map.Entry<String, Entry>[] actions;
public boolean preExecute(HttpRequest request, HttpResponse response) throws IOException {
return true;
}
private Map.Entry<String, Entry>[] mappings;
private final HttpServlet authSuccessServlet = new HttpServlet() {
@Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
if (!preExecute(request, response)) return;
for (Map.Entry<String, Entry> en : actions) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
if (entry.ignore || authenticate(entry.moduleid, entry.actionid, request, response)) {
public void execute(HttpRequest request, HttpResponse response) throws IOException {
Entry entry = (Entry) request.attachment;
if (entry.cacheseconds > 0) {//有缓存设置
CacheEntry ce = entry.cache.get(request.getRequestURI());
if (ce != null && ce.time + entry.cacheseconds > System.currentTimeMillis()) { //缓存有效
@@ -182,31 +199,125 @@ public abstract class HttpBaseServlet extends HttpServlet {
}
entry.servlet.execute(request, response);
}
};
private final HttpServlet preSuccessServlet = new HttpServlet() {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
for (Map.Entry<String, Entry> en : mappings) {
if (request.getRequestURI().startsWith(en.getKey())) {
Entry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
return;
}
request.attachment = entry;
if (entry.ignore) {
authSuccessServlet.execute(request, response);
} else {
authenticate(entry.moduleid, entry.actionid, request, response, authSuccessServlet);
}
return;
}
}
throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")");
}
};
/**
* <p>
* 预执行方法在execute方法之前运行通常用于常规统计或基础检测例如 : <br>
* <blockquote><pre>
* &#64;Override
* public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
* if (finer) response.setRecycleListener((req, resp) -&#62; { //记录处理时间比较长的请求
* long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
* if (e &#62; 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
* });
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public void preExecute(HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
next.execute(request, response);
}
/**
* 使用 public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException 代替
*
* @param moduleid int
* @param actionid int
* @param request HttpRequest
* @param response HttpResponse
*
* @return boolean
* @throws IOException IOException
* @deprecated
*/
@Deprecated
public boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException {
return true;
}
/**
* <p>
* 用户登录或权限验证, 没有注解为&#64;AuthIgnore 的方法会执行authenticate方法, 若验证成功则必须调用next.execute(request, response);进行下一步操作, 例如: <br>
* <blockquote><pre>
* &#64;Override
* public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException {
* UserInfo info = currentUser(request);
* if (info == null) {
* response.finishJson(RET_UNLOGIN);
* return;
* } else if (!info.checkAuth(module, actionid)) {
* response.finishJson(RET_AUTHILLEGAL);
* return;
* }
* next.execute(request, response);
* }
* </pre></blockquote>
* <p>
*
*
* @param moduleid 模块ID来自&#64;WebServlet.moduleid()
* @param actionid 操作ID来自&#64;WebMapping.actionid()
* @param request HttpRequest
* @param response HttpResponse
* @param next HttpServlet
*
* @throws IOException IOException
*/
public abstract void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, final HttpServlet next) throws IOException;
@Override
public final void execute(HttpRequest request, HttpResponse response) throws IOException {
preExecute(request, response, preSuccessServlet);
}
public final void preInit(HttpContext context, AnyValue config) {
String path = _prefix == null ? "" : _prefix;
WebServlet ws = this.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) path = "";
HashMap<String, Entry> map = load();
this.actions = new Map.Entry[map.size()];
this.mappings = new Map.Entry[map.size()];
int i = -1;
for (Map.Entry<String, Entry> en : map.entrySet()) {
actions[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue());
}
//必须要倒排序, /query /query1 /query12 确保含子集的优先匹配 /query12 /query1 /query
Arrays.sort(actions, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey()));
}
public final void postDestroy(HttpContext context, AnyValue config) {
}
public abstract boolean authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response) throws IOException;
protected void setHeader(HttpRequest request, String name, Serializable value) {
request.header.setValue(name, String.valueOf(value));
}
@@ -242,17 +353,20 @@ public abstract class HttpBaseServlet extends HttpServlet {
if (exps.length > 0 && (exps.length != 1 || exps[0] != IOException.class)) continue;
//-----------------------------------------------
final WebMapping mapping = method.getAnnotation(WebMapping.class);
final WebAction action = method.getAnnotation(WebAction.class);
if (action == null) continue;
if (!action.inherited() && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = action.actionid();
final String name = action.url().trim();
if (mapping == null && action == null) continue;
final boolean inherited = mapping == null ? action.inherited() : mapping.inherited();
if (!inherited && selfClz != clz) continue; //忽略不被继承的方法
final int actionid = mapping == null ? action.actionid() : mapping.actionid();
final String name = mapping == null ? action.url().trim() : mapping.url().trim();
final String[] methods = mapping == null ? action.methods() : mapping.methods();
if (nameset.containsKey(name)) {
if (nameset.get(name) != clz) continue;
throw new RuntimeException(this.getClass().getSimpleName() + " has two same " + WebAction.class.getSimpleName() + "(" + name + ")");
throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + WebMapping.class.getSimpleName() + "(" + name + ")");
}
nameset.put(name, clz);
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, action.methods(), method, createHttpServlet(method)));
map.put(name, new Entry(typeIgnore, serviceid, actionid, name, methods, method, createHttpServlet(method)));
}
} while ((clz = clz.getSuperclass()) != HttpBaseServlet.class);
return map;
@@ -273,7 +387,7 @@ public abstract class HttpBaseServlet extends HttpServlet {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_" + (++i);
} catch (Exception ex) {
} catch (Throwable ex) {
break;
}
}

View File

@@ -37,7 +37,8 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
@Override
public void init(HttpContext context, AnyValue config) {
this.servlets.forEach(s -> {
Collection<HttpServlet> servlets = getServlets();
servlets.forEach(s -> {
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).preInit(context, getServletConf(s));
} else if (s instanceof HttpBaseServlet) {
@@ -47,7 +48,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
});
final WatchFactory watch = context.getWatchFactory();
if (watch != null) {
this.servlets.forEach(s -> {
servlets.forEach(s -> {
watch.inject(s);
});
}
@@ -71,7 +72,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName());
try {
this.resourceHttpServlet = (HttpServlet) Class.forName(resServlet).newInstance();
} catch (Exception e) {
} catch (Throwable e) {
this.resourceHttpServlet = new HttpResourceServlet();
logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e);
}
@@ -82,7 +83,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
public void execute(HttpRequest request, HttpResponse response) throws IOException {
try {
final String uri = request.getRequestURI();
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = this.mappings.isEmpty() ? null : this.mappings.get(uri);
Servlet<HttpContext, HttpRequest, HttpResponse> servlet = mappingServlet(uri);
if (servlet == null && this.regArray != null) {
for (SimpleEntry<Predicate<String>, HttpServlet> en : regArray) {
if (en.getKey().test(uri)) {
@@ -138,7 +139,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
regArray[regArray.length - 1] = new SimpleEntry<>(Pattern.compile(mapping).asPredicate(), servlet);
}
} else if (mapping != null && !mapping.isEmpty()) {
super.mappings.put(mapping, servlet);
putMapping(mapping, servlet);
}
if (this.allMapStrings.containsKey(mapping)) {
Class old = this.allMapStrings.get(mapping);
@@ -148,7 +149,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
}
setServletConf(servlet, conf);
servlet._prefix = prefix.toString();
this.servlets.add(servlet);
putServlet(servlet);
}
}
@@ -175,7 +176,7 @@ public class HttpPrepareServlet extends PrepareServlet<String, HttpContext, Http
@Override
public void destroy(HttpContext context, AnyValue config) {
this.resourceHttpServlet.destroy(context, config);
this.servlets.forEach(s -> {
getServlets().forEach(s -> {
s.destroy(context, getServletConf(s));
if (s instanceof WebSocketServlet) {
((WebSocketServlet) s).postDestroy(context, getServletConf(s));

View File

@@ -66,6 +66,8 @@ public class HttpRequest extends Request<HttpContext> {
private final String remoteAddrHeader;
Object attachment; //供 HttpBaseServlet传递Entry使用
public HttpRequest(HttpContext context, String remoteAddrHeader) {
super(context);
this.remoteAddrHeader = remoteAddrHeader;
@@ -336,6 +338,8 @@ public class HttpRequest extends Request<HttpContext> {
this.boundary = false;
this.bodyparsed = false;
this.attachment = null;
this.header.clear();
this.params.clear();
this.array.clear();
@@ -512,6 +516,123 @@ public class HttpRequest extends Request<HttpContext> {
return requestURI.substring(requestURI.lastIndexOf('/') + 1);
}
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2
*
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val);
}
/**
* 获取请求URL最后的一个/后面的部分的short值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: short type = request.getRequstURILastPath(16, (short)0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认short值
*
* @return short值
*/
public short getRequstURILastPath(int radix, short defvalue) {
String val = getRequstURILastPath();
if (val.isEmpty()) return defvalue;
return val.isEmpty() ? defvalue : Short.parseShort(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(0); //type = 2
*
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: int type = request.getRequstURILastPath(16, 0); //type = 2
*
* @param radix 进制数
* @param defvalue 默认int值
*
* @return int值
*/
public int getRequstURILastPath(int radix, int defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Integer.parseInt(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的float值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: float type = request.getRequstURILastPath(0.0f); //type = 2.0f
*
* @param defvalue 默认float值
*
* @return float值
*/
public float getRequstURILastPath(float defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Float.parseFloat(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2
*
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val);
}
/**
* 获取请求URL最后的一个/后面的部分的int值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: long type = request.getRequstURILastPath(16, 0L); //type = 2
*
* @param radix 进制数
* @param defvalue 默认long值
*
* @return long值
*/
public long getRequstURILastPath(int radix, long defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Long.parseLong(val, radix);
}
/**
* 获取请求URL最后的一个/后面的部分的double值 <br>
* 例如请求URL /pipes/record/query/2 <br>
* 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0
*
* @param defvalue 默认double值
*
* @return double值
*/
public double getRequstURILastPath(double defvalue) {
String val = getRequstURILastPath();
return val.isEmpty() ? defvalue : Double.parseDouble(val);
}
/**
*
* 从prefix之后截取getRequestURI再对"/"进行分隔

View File

@@ -13,7 +13,9 @@ import java.nio.channels.*;
import java.nio.file.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
@@ -200,6 +202,26 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
return this;
}
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出
*
* @return AsyncHandler
*/
public AsyncHandler createAsyncHandler() {
return AsyncHandler.create((v, a) -> {
if (v instanceof org.redkale.service.RetResult) {
finishJson((org.redkale.service.RetResult) v);
} else if (v instanceof CharSequence) {
finish(String.valueOf(v));
} else {
finishJson(v);
}
}, (t, a) -> {
request.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, t);
finish(500, null);
});
}
/**
* 将对象以JSON格式输出
*
@@ -290,12 +312,69 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
finish(convert.convertTo(context.getBufferSupplier(), ret));
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param future 输出对象的句柄
*/
public void finishJson(final CompletableFuture future) {
finishJson(request.getJsonConvert(), future);
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param future 输出对象的句柄
*/
public void finishJson(final JsonConvert convert, final CompletableFuture future) {
future.whenComplete((v, e) -> {
if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, v);
}
});
}
/**
* 将CompletableFuture的结果对象以JSON格式输出
*
* @param convert 指定的JsonConvert
* @param type 指定的类型
* @param future 输出对象的句柄
*/
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future) {
future.whenComplete((v, e) -> {
if (e != null) {
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
finish(500, null);
return;
}
if (v instanceof CharSequence) {
finish(v.toString());
} else if (v instanceof org.redkale.service.RetResult) {
finishJson(convert, (org.redkale.service.RetResult) v);
} else {
finishJson(convert, type, v);
}
});
}
/**
* 将指定字符串以响应结果输出
*
* @param obj 输出内容
*/
public void finish(String obj) {
if (isClosed()) return;
if (this.recycleListener != null) this.output = obj;
if (obj == null || obj.isEmpty()) {
final ByteBuffer headbuf = createHeader();
@@ -337,6 +416,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param message 输出内容
*/
public void finish(int status, String message) {
if (isClosed()) return;
this.status = status;
if (status != 200) super.refuseAlive();
finish(message);
@@ -363,6 +443,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/
@Override
public void finish(final byte[] bs) {
if (isClosed()) return; //避免重复关闭
if (this.context.getBufferCapacity() == bs.length) {
ByteBuffer buffer = this.context.pollBuffer();
buffer.put(bs);
@@ -391,6 +472,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/
@Override
public void finish(boolean kill, ByteBuffer buffer) {
if (isClosed()) return; //避免重复关闭
if (!this.headsended) {
this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader();
@@ -423,6 +505,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
*/
@Override
public void finish(boolean kill, ByteBuffer... buffers) {
if (isClosed()) return; //避免重复关闭
if (bufferHandler != null) {
ByteBuffer[] bufs = bufferHandler.execute(this, buffers);
if (bufs != null) buffers = bufs;
@@ -457,7 +540,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
* @param attachment 异步回调参数
* @param handler 异步回调函数
*/
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler) {
public <A> void sendBody(ByteBuffer buffer, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) {
if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining();
ByteBuffer headbuf = createHeader();
@@ -472,6 +555,37 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
}
}
/**
* 异步输出指定内容
*
* @param <A> 泛型
* @param buffers 输出内容
* @param attachment 异步回调参数
* @param handler 异步回调函数
*/
public <A> void sendBody(ByteBuffer[] buffers, A attachment, AsyncHandler<Integer, A> handler) {
if (!this.headsended) {
if (this.contentLength < 0) {
int len = 0;
if (buffers != null && buffers.length > 0) {
for (ByteBuffer b : buffers) {
len += b.remaining();
}
}
this.contentLength = len;
}
ByteBuffer headbuf = createHeader();
headbuf.flip();
if (buffers == null || buffers.length == 0) {
super.send(headbuf, attachment, handler);
} else {
super.send(Utility.unshift(buffers, headbuf), attachment, handler);
}
} else {
super.send(buffers, attachment, handler);
}
}
/**
* 将指定文件按响应结果输出
*
@@ -796,7 +910,7 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
this.bufferHandler = bufferHandler;
}
protected final class TransferFileHandler implements CompletionHandler<Integer, ByteBuffer> {
protected final class TransferFileHandler implements AsyncHandler<Integer, ByteBuffer> {
private final AsynchronousFileChannel filechannel;

View File

@@ -11,6 +11,7 @@ import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
@@ -36,6 +37,8 @@ public final class Rest {
static final String REST_SERVICEMAP_FIELD_NAME = "_servicemap"; //如果只有name=""的Service资源则实例中_servicemap必须为null
private static final String REST_PARAMTYPES_FIELD_NAME = "_paramtypes"; //存在泛型的参数数组 Type[][] 第1维度是方法的下标 第二维度是参数的下标
private static final Set<String> EXCLUDERMETHODS = new HashSet<>();
static {
@@ -58,6 +61,42 @@ public final class Rest {
private Rest() {
}
public static class MethodParamClassVisitor extends ClassVisitor {
private final Map<String, List<String>> fieldmap;
public MethodParamClassVisitor(int api, final Map<String, List<String>> fieldmap) {
super(api);
this.fieldmap = fieldmap;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (java.lang.reflect.Modifier.isStatic(access)) return null;
List<String> fieldnames = new ArrayList<>();
fieldmap.put(name + ":" + desc, fieldnames);
return new MethodVisitor(Opcodes.ASM5) {
@Override
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
if (index > 0) fieldnames.add(name);
}
};
}
//返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多
public static Map<String, List<String>> getMethodParamNames(Class clazz) {
String n = clazz.getName();
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
Map<String, List<String>> map = new HashMap<>();
if (in == null) return map;
try {
new ClassReader(Utility.readBytesThenClose(in)).accept(new MethodParamClassVisitor(Opcodes.ASM5, map), 0);
} catch (Exception e) { //无需理会
}
return map;
}
}
static String getWebModuleName(Class<? extends Service> serviceType) {
final RestService controller = serviceType.getAnnotation(RestService.class);
if (controller == null) return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
@@ -72,17 +111,20 @@ public final class Rest {
if (!java.lang.reflect.Modifier.isPublic(mod)) return null;
if (java.lang.reflect.Modifier.isAbstract(mod)) return null;
final java.lang.reflect.Type futureRestOutputType = new TypeToken<CompletableFuture<RestOutput>>() {
}.getType();
final String serviceDesc = Type.getDescriptor(serviceType);
final String webServletDesc = Type.getDescriptor(WebServlet.class);
final String reqDesc = Type.getDescriptor(HttpRequest.class);
final String respDesc = Type.getDescriptor(HttpResponse.class);
final String retDesc = Type.getDescriptor(RetResult.class);
final String futureDesc = Type.getDescriptor(CompletableFuture.class);
final String flipperDesc = Type.getDescriptor(Flipper.class);
final String restoutputDesc = Type.getDescriptor(RestOutput.class);
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
final String authDesc = Type.getDescriptor(HttpBaseServlet.AuthIgnore.class);
final String cacheDesc = Type.getDescriptor(HttpBaseServlet.HttpCacheable.class);
final String actionDesc = Type.getDescriptor(HttpBaseServlet.WebAction.class);
final String mappingDesc = Type.getDescriptor(HttpBaseServlet.WebMapping.class);
final String webparamDesc = Type.getDescriptor(HttpBaseServlet.WebParam.class);
final String webparamsDesc = Type.getDescriptor(HttpBaseServlet.WebParams.class);
final String sourcetypeDesc = Type.getDescriptor(HttpBaseServlet.ParamSourceType.class);
@@ -99,10 +141,7 @@ public final class Rest {
if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = serviceTypeInternalName.substring(0, serviceTypeInternalName.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";
try {
return ((Class<T>) Class.forName(newDynName.replace('/', '.'))).newInstance();
} catch (Exception ex) {
}
Method currentUserMethod = null;
try {
currentUserMethod = baseServletClass.getDeclaredMethod("currentUser", HttpRequest.class);
@@ -113,7 +152,7 @@ public final class Rest {
final String defmodulename = getWebModuleName(serviceType);
for (char ch : defmodulename.toCharArray()) {
if (!((ch >= '0' && ch <= '9') || ch == '$' || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //不能含特殊字符
throw new RuntimeException(serviceType.getName() + " has illeal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ $");
throw new RuntimeException(serviceType.getName() + " have illeal " + RestService.class.getSimpleName() + ".value, only 0-9 a-z A-Z _ $");
}
}
@@ -122,7 +161,7 @@ public final class Rest {
AsmMethodVisitor mv;
AnnotationVisitor av0;
Map<String, Object> classMap = new LinkedHashMap<>();
List<Map<String, Object>> actionMaps = new ArrayList<>();
List<Map<String, Object>> mappingMaps = new ArrayList<>();
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{ //RestDynamic
@@ -163,6 +202,10 @@ public final class Rest {
fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null);
fv.visitEnd();
}
{ //_paramtypes字段 java.lang.reflect.Type[][]
fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null);
fv.visitEnd();
}
{ //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
@@ -175,7 +218,9 @@ public final class Rest {
final List<MappingEntry> entrys = new ArrayList<>();
final Map<String, org.redkale.util.Attribute> restAttributes = new LinkedHashMap<>();
//获取所有可以转换成WebMapping的方法
int methodidex = 0;
final List<java.lang.reflect.Type[]> paramtypes = new ArrayList<>();
for (final Method method : serviceType.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue;
Class[] extypes = method.getExceptionTypes();
@@ -195,22 +240,28 @@ public final class Rest {
}
}
if (ignore) continue;
paramtypes.add(method.getGenericParameterTypes());
if (mappings.length == 0) { //没有Mapping设置一个默认值
MappingEntry entry = new MappingEntry(null, defmodulename, method);
MappingEntry entry = new MappingEntry(methodidex, null, defmodulename, method);
if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
entrys.add(entry);
} else {
for (RestMapping mapping : mappings) {
MappingEntry entry = new MappingEntry(mapping, defmodulename, method);
MappingEntry entry = new MappingEntry(methodidex, mapping, defmodulename, method);
if (entrys.contains(entry)) throw new RuntimeException(serviceType.getName() + " on " + method.getName() + " 's mapping(" + entry.name + ") is repeat");
entrys.add(entry);
}
}
methodidex++;
}
if (entrys.isEmpty()) return null; //没有可WebAction的方法
if (entrys.isEmpty()) return null; //没有可WebMapping的方法
//将每个Service可转换的方法生成HttpServlet对应的WebMapping方法
final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(serviceType);
for (final MappingEntry entry : entrys) {
final Method method = entry.mappingMethod;
final Class returnType = method.getReturnType();
final java.lang.reflect.Type returnGenericType = method.getGenericReturnType();
final String methodDesc = Type.getMethodDescriptor(method);
final Parameter[] params = method.getParameters();
@@ -254,10 +305,12 @@ public final class Rest {
final int maxStack = 3 + params.length;
List<int[]> varInsns = new ArrayList<>();
int maxLocals = 4;
int argIndex = 0;
List<String> asmParamNames = asmParamMap == null ? null : asmParamMap.get(method.getName() + ":" + Type.getMethodDescriptor(method));
List<Object[]> paramlist = new ArrayList<>();
for (final Parameter param : params) {
//解析方法中的每个参数
for (int i = 0; i < params.length; i++) {
final Parameter param = params[i];
final Class ptype = param.getType();
String n = null;
String comment = "";
@@ -300,13 +353,14 @@ public final class Rest {
if (annpara != null) required = annpara.required();
if (n == null) n = (annpara == null || annpara.name().isEmpty()) ? null : annpara.name();
if (n == null && ptype == userType) n = "&"; //用户类型特殊处理
if (n == null && asmParamNames != null && asmParamNames.size() > i) n = asmParamNames.get(i);
if (n == null) {
if (param.isNamePresent()) {
n = param.getName();
} else if (ptype == Flipper.class) {
n = "flipper";
} else {
n = (++argIndex > 1) ? ("bean" + argIndex) : "bean";
n = ("bean" + i);
}
}
if (annhead == null && anncookie == null && annaddr == null
@@ -316,9 +370,9 @@ public final class Rest {
paramlist.add(new Object[]{param, n, ptype, radix, comment, required, annpara, annsid, annaddr, annhead, anncookie});
}
Map<String, Object> actionMap = new LinkedHashMap<>();
{
//设置 WebAction
Map<String, Object> mappingMap = new LinkedHashMap<>();
{ // 设置 Annotation
//设置 WebMapping
boolean reqpath = false;
for (Object[] ps : paramlist) {
if ("#".equals((String) ps[1])) {
@@ -326,7 +380,7 @@ public final class Rest {
break;
}
}
av0 = mv.visitAnnotation(actionDesc, true);
av0 = mv.visitAnnotation(mappingDesc, true);
String url = "/" + defmodulename.toLowerCase() + "/" + entry.name + (reqpath ? "/" : "");
av0.visit("url", url);
av0.visit("actionid", entry.actionid);
@@ -342,16 +396,16 @@ public final class Rest {
av0.visit("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
av0.visitEnd();
actionMap.put("url", url);
actionMap.put("auth", entry.auth);
actionMap.put("cachetimeout", entry.cacheseconds);
actionMap.put("actionid", entry.actionid);
actionMap.put("comment", entry.comment);
actionMap.put("methods", entry.methods);
actionMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
mappingMap.put("url", url);
mappingMap.put("auth", entry.auth);
mappingMap.put("cachetimeout", entry.cacheseconds);
mappingMap.put("actionid", entry.actionid);
mappingMap.put("comment", entry.comment);
mappingMap.put("methods", entry.methods);
mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt));
}
{
{ // 设置 Annotation
av0 = mv.visitAnnotation(webparamsDesc, true);
AnnotationVisitor av1 = av0.visitArray("value");
//设置 WebParam
@@ -373,10 +427,13 @@ public final class Rest {
av0.visitEnd();
}
List<Map<String, Object>> paramMaps = new ArrayList<>();
//获取每个参数的值
boolean hasAsyncHandler = false;
for (Object[] ps : paramlist) {
Map<String, Object> paramMap = new LinkedHashMap<>();
final Parameter param = (Parameter) ps[0]; //参数类型
String pname = (String) ps[1]; //参数名
Class ptype = (Class) ps[2];
Class ptype = (Class) ps[2]; //参数类型
int radix = (Integer) ps[3];
String comment = (String) ps[4];
boolean required = (Boolean) ps[5];
@@ -391,7 +448,23 @@ public final class Rest {
paramMap.put("name", pname);
paramMap.put("type", ptype.getName());
if (annsid != null) { //HttpRequest.getSessionid(true|false)
if (AsyncHandler.class.isAssignableFrom(ptype)) { //HttpResponse.createAsyncHandler() or HttpResponse.createAsyncHandler(Class)
if (ptype == AsyncHandler.class) {
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "()Lorg/redkale/util/AsyncHandler;", false);
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "createAsyncHandler", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/Class;)Lorg/redkale/util/AsyncHandler;", false);
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
}
hasAsyncHandler = true;
} else if (annsid != null) { //HttpRequest.getSessionid(true|false)
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(annsid.create() ? ICONST_1 : ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getSessionid", "(Z)Ljava/lang/String;", false);
@@ -633,7 +706,31 @@ public final class Rest {
varInsns.add(new int[]{ALOAD, maxLocals});
} else { //其他Json对象
mv.visitVarInsn(ALOAD, 1);
if (param.getType() == param.getParameterizedType()) {
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
} else {
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;");
if (entry.methodidx <= 5) { //方法下标
mv.visitInsn(ICONST_0 + entry.methodidx);
} else {
mv.visitIntInsn(BIPUSH, entry.methodidx);
}
mv.visitInsn(AALOAD);
int paramidx = 0;
for (int i = 0; i < params.length; i++) {
if (params[i] == param) {
paramidx = i;
break;
}
}
if (paramidx <= 5) { //参数下标
mv.visitInsn(ICONST_0 + paramidx);
} else {
mv.visitIntInsn(BIPUSH, paramidx);
}
mv.visitInsn(AALOAD);
}
mv.visitLdcInsn(pname);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, ishead ? "getJsonHeader" : "getJsonParameter", "(Ljava/lang/reflect/Type;Ljava/lang/String;)Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
@@ -723,7 +820,9 @@ public final class Rest {
mv.visitVarInsn(ins[0], ins[1]);
}
mv.visitMethodInsn(INVOKEVIRTUAL, serviceTypeInternalName, method.getName(), methodDesc, false);
if (returnType == void.class) {
if (hasAsyncHandler) {
mv.visitInsn(RETURN);
} else if (returnType == void.class) {
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESTATIC, retInternalName, "success", "()" + retDesc, false);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
@@ -829,6 +928,21 @@ public final class Rest {
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
mv.visitInsn(RETURN);
maxLocals++;
} else if (futureRestOutputType == returnGenericType) {
mv.visitVarInsn(ASTORE, maxLocals);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + futureDesc + ")V", false);
mv.visitInsn(RETURN);
maxLocals++;
} else if (CompletableFuture.class.isAssignableFrom(returnType)) {
mv.visitVarInsn(ASTORE, maxLocals);
mv.visitVarInsn(ALOAD, 2);//response
mv.visitVarInsn(ALOAD, maxLocals);
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + futureDesc + ")V", false);
mv.visitInsn(RETURN);
maxLocals++;
} else {
mv.visitVarInsn(ASTORE, maxLocals);
mv.visitVarInsn(ALOAD, 2); //response
@@ -838,8 +952,8 @@ public final class Rest {
maxLocals++;
}
mv.visitMaxs(maxStack, maxLocals);
actionMap.put("params", paramMaps);
actionMaps.add(actionMap);
mappingMap.put("params", paramMaps);
mappingMaps.add(mappingMap);
} // end for each
for (String attrname : restAttributes.keySet()) {
@@ -847,7 +961,7 @@ public final class Rest {
fv.visitEnd();
}
classMap.put("actions", actionMaps);
classMap.put("mappings", mappingMaps);
{ //toString函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
@@ -872,6 +986,12 @@ public final class Rest {
attrField.setAccessible(true);
attrField.set(obj, en.getValue());
}
Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME);
typesfield.setAccessible(true);
java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramtypes.size()][];
paramtypeArray = paramtypes.toArray(paramtypeArray);
typesfield.set(obj, paramtypeArray);
return obj;
} catch (Exception e) {
throw new RuntimeException(e);
@@ -903,8 +1023,9 @@ public final class Rest {
}
}
public MappingEntry(RestMapping mapping, final String defmodulename, Method method) {
public MappingEntry(int methodidx, RestMapping mapping, final String defmodulename, Method method) {
if (mapping == null) mapping = DEFAULT__MAPPING;
this.methodidx = methodidx;
this.ignore = mapping.ignore();
String n = mapping.name().toLowerCase();
if (n.isEmpty()) n = method.getName().toLowerCase().replace(defmodulename.toLowerCase(), "");
@@ -917,6 +1038,8 @@ public final class Rest {
this.comment = mapping.comment();
}
public final int methodidx; // _paramtypes 的下标从0开始
public final Method mappingMethod;
public final boolean ignore;

View File

@@ -6,6 +6,11 @@
package org.redkale.net.http;
import java.io.*;
import java.util.concurrent.*;
import java.util.logging.Level;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.util.*;
/**
*
@@ -18,6 +23,22 @@ public abstract class RestHttpServlet<T> extends HttpBaseServlet {
protected abstract T currentUser(HttpRequest req) throws IOException;
protected void finishJson(final HttpResponse response, CompletableFuture<RestOutput> future) throws IOException {
future.whenComplete((output, e) -> {
if (e != null) {
response.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + response.getRequest(), e);
response.finish(500, null);
return;
}
try {
finishJson(response, output);
} catch (IOException ioe) {
response.getContext().getLogger().log(Level.WARNING, "Servlet finish RestOutput occur, forece to close channel. request = " + response.getRequest(), ioe);
response.finish(500, null);
}
});
}
protected void finishJson(final HttpResponse response, RestOutput output) throws IOException {
if (output == null) {
response.finishJson(output);
@@ -26,14 +47,139 @@ public abstract class RestHttpServlet<T> extends HttpBaseServlet {
if (output.getContentType() != null) response.setContentType(output.getContentType());
response.addHeader(output.getHeaders());
response.addCookie(output.getCookies());
response.setStatus(output.getStatus() < 1 ? 200 : output.getStatus());
if (output.getResult() instanceof File) {
response.finish((File) output.getResult());
} else if (output.getResult() instanceof String) {
response.finish((String) output.getResult());
} else if (output.getResult() == null) {
response.finish(output.getMessage());
} else {
response.finishJson(output.getResult());
}
}
/**
* 创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出 <br>
*
* 传入的AsyncHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
*
* @param <H> AsyncHandler泛型
* @param response HttpResponse
* @param handlerClass Class
*
* @return AsyncHandler
*/
protected final <H extends AsyncHandler> H createAsyncHandler(HttpResponse response, final Class<H> handlerClass) {
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) response.createAsyncHandler();
Creator<H> creator = creators.get(handlerClass);
if (creator == null) {
creator = createCreator(handlerClass);
creators.put(handlerClass, creator);
}
return (H) creator.create(response.createAsyncHandler());
}
private static final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap<>();
private static <H extends AsyncHandler> Creator<H> createCreator(Class<H> handlerClass) {
//生成规则与SncpAsyncHandler.Factory 很类似
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String handlerName = AsyncHandler.class.getName().replace('.', '/');
final String handlerDesc = Type.getDescriptor(AsyncHandler.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + handlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "handler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<AsyncHandler> newHandlerClazz = (Class<AsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return (Creator<H>) Creator.create(newHandlerClazz);
}
}

View File

@@ -40,7 +40,7 @@ public @interface RestMapping {
String name() default "";
/**
* 备注描述, 对应&#64;WebAction.comment
* 备注描述, 对应&#64;WebMapping.comment
*
* @return String
*/
@@ -54,7 +54,7 @@ public @interface RestMapping {
boolean auth() default false;
/**
* 操作ID值鉴权时用到, 对应&#64;WebAction.actionid
* 操作ID值鉴权时用到, 对应&#64;WebMapping.actionid
*
* @return int
*/
@@ -68,7 +68,7 @@ public @interface RestMapping {
int cacheseconds() default 0;
/**
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebAction.methods
* 允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;WebMapping.methods
*
* @return String[]
*/

View File

@@ -27,6 +27,10 @@ public class RestOutput<T> {
private T result;
private int status = 0; //不设置则为 200
private String message;
public RestOutput() {
}
@@ -34,14 +38,16 @@ public class RestOutput<T> {
this.result = result;
}
public void addHeader(String name, Serializable value) {
public RestOutput<T> addHeader(String name, Serializable value) {
if (this.headers == null) this.headers = new HashMap<>();
this.headers.put(name, String.valueOf(value));
return this;
}
public void addCookie(HttpCookie cookie) {
public RestOutput<T> addCookie(HttpCookie cookie) {
if (this.cookies == null) this.cookies = new ArrayList<>();
this.cookies.add(cookie);
return this;
}
public Map<String, String> getHeaders() {
@@ -76,4 +82,20 @@ public class RestOutput<T> {
this.result = result;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -32,6 +32,7 @@ public @interface RestParam {
* name='&#38;'表示当前用户; <br>
* name='#'表示截取uri最后一段; <br>
* name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值 <br>
* 若方法名以find、delete开头且方法的参数只有一个且参数类型是基本数据类型或String则默认值为"#" <br>
*
* @return String
*/

View File

@@ -1,43 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.http;
import java.lang.annotation.*;
/**
* 功能同JSR 315 (java-servlet 3.0) 规范中的 @WebInitParam
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebInitParam {
/**
* 参数名
*
* @return String
*/
String name();
/**
* 参数值
*
* @return String
*/
String value();
/**
* 参数描述
*
* @return String
*/
String description() default "";
}

View File

@@ -49,13 +49,6 @@ public @interface WebServlet {
*/
int moduleid() default 0;
/**
* 参数
*
* @return WebInitParam[]
*/
WebInitParam[] initParams() default {};
/**
* 备注描述
*

View File

@@ -10,6 +10,7 @@ import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.util.Comment;
@@ -76,6 +77,8 @@ public abstract class WebSocket {
String _remoteAddr;//不可能为空
JsonConvert _jsonConvert; //不可能为空
private final long createtime = System.currentTimeMillis();
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
@@ -85,7 +88,7 @@ public abstract class WebSocket {
//----------------------------------------------------------------
/**
* 发送消息体, 包含二进制/文本
* 给自身发送消息体, 包含二进制/文本
*
* @param packet WebSocketPacket
*
@@ -99,7 +102,7 @@ public abstract class WebSocket {
}
/**
* 发送单一的文本消息
* 给自身发送单一的文本消息
*
* @param text 不可为空
*
@@ -110,7 +113,7 @@ public abstract class WebSocket {
}
/**
* 发送文本消息
* 给自身发送文本消息
*
* @param text 不可为空
* @param last 是否最后一条
@@ -139,7 +142,7 @@ public abstract class WebSocket {
}
/**
* 发送单一的二进制消息
* 给自身发送单一的二进制消息
*
* @param data byte[]
*
@@ -150,7 +153,7 @@ public abstract class WebSocket {
}
/**
* 发送二进制消息
* 给自身发送二进制消息
*
* @param data 不可为空
* @param last 是否最后一条
@@ -162,15 +165,30 @@ public abstract class WebSocket {
}
/**
* 发送消息, 消息类型是String或byte[]
* 给自身发送消息, 消息类型是String或byte[]或可JSON化对象
*
* @param message 不可为空, 只能是String或byte[]
* @param message 不可为空, 只能是String或byte[]或可JSON化对象
*
* @return 0表示成功 非0表示错误码
*/
public final int send(Object message) {
return send(message, true);
}
/**
* 给自身发送消息, 消息类型是String或byte[]或可JSON化对象
*
* @param message 不可为空, 只能是String或byte[]或可JSON化对象
* @param last 是否最后一条
*
* @return 0表示成功 非0表示错误码
*/
public final int send(Serializable message, boolean last) {
return send(new WebSocketPacket(message, last));
public final int send(Object message, boolean last) {
if (message == null || message instanceof CharSequence || message instanceof byte[]) {
return send(new WebSocketPacket((Serializable) message, last));
} else {
return send(new WebSocketPacket(_jsonConvert.convertTo(message), last));
}
}
//----------------------------------------------------------------
@@ -195,7 +213,19 @@ public abstract class WebSocket {
* @return 为0表示成功 其他值表示异常
*/
public final int sendEachMessage(Serializable groupid, byte[] data) {
return WebSocket.this.sendEachMessage(groupid, data, true);
return sendEachMessage(groupid, data, true);
}
/**
* 给指定groupid的WebSocketGroup下所有WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendEachMessage(Serializable groupid, Object message) {
return sendEachMessage(groupid, message, true);
}
/**
@@ -224,6 +254,19 @@ public abstract class WebSocket {
return sendMessage(groupid, false, data, last);
}
/**
* 给指定groupid的WebSocketGroup下所有WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
* @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendEachMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, false, message, last);
}
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息
*
@@ -248,6 +291,18 @@ public abstract class WebSocket {
return sendRecentMessage(groupid, data, true);
}
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendRecentMessage(Serializable groupid, Object message) {
return sendMessage(groupid, true, message, true);
}
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送文本消息
*
@@ -274,6 +329,19 @@ public abstract class WebSocket {
return sendMessage(groupid, true, data, last);
}
/**
* 给指定groupid的WebSocketGroup下最近接入的WebSocket节点发送可JSON化对象消息
*
* @param groupid groupid
* @param message 不可为空
* @param last 是否最后一条
*
* @return 为0表示成功 其他值表示异常
*/
public final int sendRecentMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, true, message, last);
}
private int sendMessage(Serializable groupid, boolean recent, String text, boolean last) {
if (_engine.node == null) return RETCODE_NODESERVICE_NULL;
int rs = _engine.node.sendMessage(groupid, recent, text, last);
@@ -288,8 +356,15 @@ public abstract class WebSocket {
return rs;
}
private int sendMessage(Serializable groupid, boolean recent, Object message, boolean last) {
if (_engine.node == null) return RETCODE_NODESERVICE_NULL;
int rs = _engine.node.sendMessage(groupid, recent, message, last);
if (_engine.finest) _engine.logger.finest("wsgroupid:" + groupid + " " + (recent ? "recent " : "") + "send websocket result is " + rs + " on " + this + " by message(" + _jsonConvert.convertTo(message) + ")");
return rs;
}
/**
* 获取在线用户的节点地址列表
* 获取指定groupid在线用户的节点地址列表
*
* @param groupid groupid
*
@@ -300,7 +375,7 @@ public abstract class WebSocket {
}
/**
* 获取在线用户的详细连接信息
* 获取指定groupid在线用户的详细连接信息
*
* @param groupid groupid
*

View File

@@ -15,7 +15,9 @@ import org.redkale.util.*;
/**
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public final class WebSocketEngine {

View File

@@ -83,7 +83,7 @@ public final class WebSocketGroup {
attributes.put(name, value);
}
public final int send(boolean recent, Serializable message, boolean last) {
public final int send(boolean recent, Object message, boolean last) {
if (recent) {
return recentWebSocket.send(message, last);
} else {
@@ -91,7 +91,7 @@ public final class WebSocketGroup {
}
}
public final int sendEach(Serializable message) {
public final int sendEach(Object message) {
return sendEach(message, true);
}
@@ -111,7 +111,7 @@ public final class WebSocketGroup {
return rs;
}
public final int sendRecent(Serializable message) {
public final int sendRecent(Object message) {
return sendRecent(message, true);
}
@@ -119,7 +119,10 @@ public final class WebSocketGroup {
return recentWebSocket.send(packet);
}
public final int sendEach(Serializable message, boolean last) {
public final int sendEach(Object message, boolean last) {
if (message != null && !(message instanceof byte[]) && !(message instanceof CharSequence)) {
message = recentWebSocket._jsonConvert.convertTo(message);
}
int rs = 0;
for (WebSocket s : list) {
rs |= s.send(message, last);
@@ -127,7 +130,7 @@ public final class WebSocketGroup {
return rs;
}
public final int sendRecent(Serializable message, boolean last) {
public final int sendRecent(Object message, boolean last) {
return recentWebSocket.send(message, last);
}

View File

@@ -38,7 +38,7 @@ public abstract class WebSocketNode {
//存放所有用户分布在节点上的队列信息,Set<InetSocketAddress> 为 sncpnode 的集合
@Resource(name = "$")
protected CacheSource<Serializable, InetSocketAddress> source;
protected CacheSource<Serializable, InetSocketAddress> sncpNodes;
//存放本地节点上所有在线用户的队列信息,Set<String> 为 engineid 的集合
protected final ConcurrentHashMap<Serializable, Set<String>> localNodes = new ConcurrentHashMap();
@@ -60,7 +60,7 @@ public abstract class WebSocketNode {
protected abstract List<String> getOnlineRemoteAddresses(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid);
protected abstract int sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Serializable message, boolean last);
protected abstract int sendMessage(@RpcTargetAddress InetSocketAddress targetAddress, Serializable groupid, boolean recent, Object message, boolean last);
protected abstract void connect(Serializable groupid, InetSocketAddress addr);
@@ -85,7 +85,7 @@ public abstract class WebSocketNode {
* @return 地址列表
*/
public Collection<InetSocketAddress> getOnlineNodes(final Serializable groupid) {
return source == null ? null : source.getCollection(groupid);
return sncpNodes == null ? null : sncpNodes.getCollection(groupid);
}
/**
@@ -133,7 +133,7 @@ public abstract class WebSocketNode {
engines.put(engine.getEngineid(), engine);
}
public final int sendMessage(Serializable groupid, boolean recent, Serializable message, boolean last) {
public final int sendMessage(Serializable groupid, boolean recent, Object message, boolean last) {
final Set<String> engineids = localNodes.get(groupid);
if (finest) logger.finest("websocket want send message {groupid:" + groupid + ", content:'" + message + "'} from locale node to " + engineids);
int rscode = RETCODE_GROUP_EMPTY;
@@ -152,7 +152,7 @@ public abstract class WebSocketNode {
}
}
}
if ((recent && rscode == 0) || remoteNode == null || source == null) {
if ((recent && rscode == 0) || remoteNode == null || sncpNodes == null) {
if (finest) {
if ((recent && rscode == 0)) {
logger.finest("websocket want send recent message success");
@@ -163,7 +163,7 @@ public abstract class WebSocketNode {
return rscode;
}
//-----------------------发送远程的-----------------------------
Collection<InetSocketAddress> addrs = source.getCollection(groupid);
Collection<InetSocketAddress> addrs = sncpNodes.getCollection(groupid);
if (finest) logger.finest("websocket found groupid:" + groupid + " on " + addrs);
if (addrs != null && !addrs.isEmpty()) { //对方连接在远程节点(包含本地节点)所以正常情况下addrs不会为空。
if (recent) {
@@ -187,44 +187,44 @@ public abstract class WebSocketNode {
//--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, String text) {
return sendMessage(groupid, false, text);
return sendMessage(groupid, false, (Object) text, true);
}
public final int sendEachMessage(Serializable groupid, String text, boolean last) {
return sendMessage(groupid, false, text, last);
return sendMessage(groupid, false, (Object) text, last);
}
public final int sendRecentMessage(Serializable groupid, String text) {
return sendMessage(groupid, true, text);
return sendMessage(groupid, true, (Object) text, true);
}
public final int sendRecentMessage(Serializable groupid, String text, boolean last) {
return sendMessage(groupid, true, text, last);
return sendMessage(groupid, true, (Object) text, last);
}
public final int sendMessage(Serializable groupid, boolean recent, String text) {
return sendMessage(groupid, recent, text, true);
return sendMessage(groupid, recent, (Object) text, true);
}
public final int sendMessage(Serializable groupid, boolean recent, String text, boolean last) {
return sendMessage(groupid, recent, (Serializable) text, last);
return sendMessage(groupid, recent, (Object) text, last);
}
//--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, byte[] data) {
return sendMessage(groupid, false, data);
return sendMessage(groupid, false, (Object) data, true);
}
public final int sendEachMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, false, data, last);
return sendMessage(groupid, false, (Object) data, last);
}
public final int sendRecentMessage(Serializable groupid, byte[] data) {
return sendMessage(groupid, true, data);
return sendMessage(groupid, true, (Object) data, true);
}
public final int sendRecentMessage(Serializable groupid, byte[] data, boolean last) {
return sendMessage(groupid, true, data, last);
return sendMessage(groupid, true, (Object) data, last);
}
public final int sendMessage(Serializable groupid, boolean recent, byte[] data) {
@@ -232,6 +232,28 @@ public abstract class WebSocketNode {
}
public final int sendMessage(Serializable groupid, boolean recent, byte[] data, boolean last) {
return sendMessage(groupid, recent, (Serializable) data, last);
return sendMessage(groupid, recent, (Object) data, last);
}
//--------------------------------------------------------------------------------
public final int sendEachMessage(Serializable groupid, Object message) {
return sendMessage(groupid, false, message, true);
}
public final int sendEachMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, false, message, last);
}
public final int sendRecentMessage(Serializable groupid, Object message) {
return sendMessage(groupid, true, message, true);
}
public final int sendRecentMessage(Serializable groupid, Object message, boolean last) {
return sendMessage(groupid, true, message, last);
}
public final int sendMessage(Serializable groupid, boolean recent, Object message) {
return sendMessage(groupid, recent, message, true);
}
}

View File

@@ -8,11 +8,11 @@ package org.redkale.net.http;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.security.*;
import java.util.*;
import java.util.logging.*;
import javax.annotation.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.WebSocketNodeService;
import org.redkale.util.*;
@@ -40,7 +40,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
public abstract class WebSocketServlet extends HttpServlet {
public abstract class WebSocketServlet extends HttpServlet implements Resourcable {
@Comment("WebScoket服务器给客户端进行ping操作的间隔时间, 单位: 秒")
public static final String WEBPARAM__LIVEINTERVAL = "liveinterval";
@@ -63,6 +63,9 @@ public abstract class WebSocketServlet extends HttpServlet {
@Comment("是否用于二进制流传输")
protected final boolean wsbinary = getClass().getAnnotation(WebSocketBinary.class) != null;
@Resource
protected JsonConvert jsonConvert;
@Resource(name = "$")
protected WebSocketNode node;
@@ -70,7 +73,7 @@ public abstract class WebSocketServlet extends HttpServlet {
public final void preInit(HttpContext context, AnyValue conf) {
InetSocketAddress addr = context.getServerAddress();
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + name() + "]", this.node, logger);
this.engine = new WebSocketEngine(addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", this.node, logger);
if (this.node == null) this.node = createWebSocketNode();
if (this.node == null) {
this.node = new WebSocketNodeService();
@@ -87,7 +90,8 @@ public abstract class WebSocketServlet extends HttpServlet {
engine.close();
}
public String name() {
@Override
public String resourceName() {
return this.getClass().getSimpleName().replace("Servlet", "").replace("WebSocket", "").toLowerCase();
}
@@ -109,6 +113,7 @@ public abstract class WebSocketServlet extends HttpServlet {
}
final WebSocket webSocket = this.createWebSocket();
webSocket._engine = engine;
webSocket._jsonConvert = jsonConvert;
webSocket._remoteAddress = request.getRemoteAddress();
webSocket._remoteAddr = request.getRemoteAddr();
Serializable sessionid = webSocket.onOpen(request);
@@ -128,7 +133,7 @@ public abstract class WebSocketServlet extends HttpServlet {
response.setHeader("Connection", "Upgrade");
response.addHeader("Upgrade", "websocket");
response.addHeader("Sec-WebSocket-Accept", key);
response.sendBody((ByteBuffer) null, null, new CompletionHandler<Integer, Void>() {
response.sendBody((ByteBuffer) null, null, new AsyncHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
@@ -141,7 +146,7 @@ public abstract class WebSocketServlet extends HttpServlet {
}
webSocket._groupid = groupid;
engine.add(webSocket);
context.submit(new WebSocketRunner(context, webSocket, response.removeChannel(), wsbinary));
context.runAsync(new WebSocketRunner(context, webSocket, response.removeChannel(), wsbinary));
response.finish(true);
}

View File

@@ -1,156 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.sncp;
import java.util.*;
import java.util.stream.Collectors;
import org.redkale.service.Service;
import org.redkale.util.*;
/**
* Service对象的封装类
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <T> Service的子类
*/
public final class ServiceWrapper<T extends Service> implements Comparable<ServiceWrapper> {
private static volatile int maxClassNameLength = 0;
private static volatile int maxNameLength = 0;
private final T service;
private final AnyValue conf;
private final String sncpGroup; //自身的组节点名 可能为null
private final Set<String> groups; //所有的组节点,包含自身
private final String name;
private final boolean remote;
private final Class[] types;
public ServiceWrapper(T service, String name, String sncpGroup, Set<String> groups, AnyValue conf) {
this(null, service, name, sncpGroup, groups, conf);
}
@SuppressWarnings("unchecked")
public ServiceWrapper(Class<T> type, T service, String name, String sncpGroup, Set<String> groups, AnyValue conf) {
this.service = service;
this.conf = conf;
this.sncpGroup = sncpGroup;
this.groups = groups;
this.name = name;
this.remote = Sncp.isRemote(service);
ResourceType rty = service.getClass().getAnnotation(ResourceType.class);
this.types = rty == null ? new Class[]{type == null ? (Class<T>) service.getClass() : type} : rty.value();
maxNameLength = Math.max(maxNameLength, name.length());
StringBuilder s = new StringBuilder();
if (this.types.length == 1) {
s.append(types[0].getName());
} else {
s.append('[');
s.append(Arrays.asList(this.types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
}
maxClassNameLength = Math.max(maxClassNameLength, s.length() + 1);
}
public static Class[] parseTypes(final Class<? extends Service> servicetype) {
ResourceType rty = servicetype.getAnnotation(ResourceType.class);
return rty == null ? new Class[]{servicetype} : rty.value();
}
@Override
public String toString() {
return toSimpleString();
}
public String toSimpleString() {
StringBuilder sb = new StringBuilder();
sb.append(remote ? "RemoteService" : "LocalService ");
int len;
if (types.length == 1) {
sb.append("(type= ").append(types[0].getName());
len = maxClassNameLength - types[0].getName().length();
} else {
StringBuilder s = new StringBuilder();
s.append('[');
s.append(Arrays.asList(this.types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
sb.append("(types=").append(s);
len = maxClassNameLength - s.length();
}
for (int i = 0; i < len; i++) {
sb.append(' ');
}
sb.append(", name='").append(name).append("'");
for (int i = 0; i < maxNameLength - name.length(); i++) {
sb.append(' ');
}
sb.append(")");
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (!(obj instanceof ServiceWrapper)) return false;
ServiceWrapper other = (ServiceWrapper) obj;
return (this.types[0].equals(other.types[0]) && this.remote == other.remote && this.name.equals(other.name) && Objects.equals(this.sncpGroup, other.sncpGroup));
}
@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.types[0]);
hash = 67 * hash + Objects.hashCode(this.sncpGroup);
hash = 67 * hash + Objects.hashCode(this.name);
hash = 67 * hash + (this.remote ? 1 : 0);
return hash;
}
@Override
public int compareTo(ServiceWrapper o) {
int rs = this.types[0].getName().compareTo(o.types[0].getName());
if (rs == 0) rs = this.name.compareTo(o.name);
return rs;
}
public Class[] getTypes() {
return types;
}
public Service getService() {
return service;
}
public AnyValue getConf() {
return conf;
}
public String getName() {
return name;
}
public boolean isRemote() {
return remote;
}
public Set<String> getGroups() {
return groups;
}
}

View File

@@ -11,6 +11,7 @@ import java.net.InetSocketAddress;
import java.security.*;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import jdk.internal.org.objectweb.asm.*;
@@ -55,11 +56,6 @@ public abstract class Sncp {
private Sncp() {
}
public static long nodeid(InetSocketAddress ip) {
byte[] bytes = ip.getAddress().getAddress();
return ((0L + ip.getPort()) << 32) | ((0xffffffff & bytes[0]) << 24) | ((0xffffff & bytes[1]) << 16) | ((0xffff & bytes[2]) << 8) | (0xff & bytes[3]);
}
public static DLong hash(final java.lang.reflect.Method method) {
if (method == null) return DLong.ZERO;
StringBuilder sb = new StringBuilder(); //不能使用method.toString() 因为包含declaringClass信息导致接口与实现类的方法hash不一致
@@ -97,6 +93,62 @@ public abstract class Sncp {
return dyn != null && dyn.remote();
}
public static String getResourceName(Service service) {
if (service == null) return null;
Resource res = service.getClass().getAnnotation(Resource.class);
return res == null ? null : res.name();
}
public static Class getServiceType(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_service_type");
ts.setAccessible(true);
return (Class) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_service_type");
}
}
public static Class[] getResourceTypes(Service service) {
if (service == null) return null;
ResourceType types = service.getClass().getAnnotation(ResourceType.class);
return types == null ? new Class[]{getServiceType(service)} : types.value();
}
public static String getSncpGroup(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_sncpGroup");
ts.setAccessible(true);
return (String) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_sncpGroup");
}
}
public static Set<String> getGroups(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_groups");
ts.setAccessible(true);
return (Set) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_groups");
}
}
public static AnyValue getConf(Service service) {
if (service == null) return null;
try {
Field ts = service.getClass().getDeclaredField(FIELDPREFIX + "_conf");
ts.setAccessible(true);
return (AnyValue) ts.get(service);
} catch (Exception e) {
throw new RuntimeException(service + " not found " + FIELDPREFIX + "_conf");
}
}
public static SncpClient getSncpClient(Service service) {
if (service == null) return null;
try {
@@ -130,6 +182,73 @@ public abstract class Sncp {
}
}
static void checkAsyncModifier(Class param, Method method) {
if (param == AsyncHandler.class) return;
if (Modifier.isFinal(param.getModifiers())) {
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} cannot final modifier");
}
if (!Modifier.isPublic(param.getModifiers())) {
throw new RuntimeException("AsyncHandler Type Parameter on {" + method + "} must be public modifier");
}
if (param.isInterface()) return;
boolean constructorflag = false;
for (Constructor c : param.getDeclaredConstructors()) {
if (c.getParameterCount() == 0) {
int mod = c.getModifiers();
if (Modifier.isPublic(mod) || Modifier.isProtected(mod)) {
constructorflag = true;
break;
}
}
}
if (param.getDeclaredConstructors().length == 0) constructorflag = true;
if (!constructorflag) throw new RuntimeException(param + " must have a empty parameter Constructor");
for (Method m : param.getMethods()) {
if (m.getName().equals("completed") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s completed method cannot final modifier");
} else if (m.getName().equals("failed") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s failed method cannot final modifier");
} else if (m.getName().equals("sncp_getParams") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_getParams method cannot final modifier");
} else if (m.getName().equals("sncp_setParams") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_setParams method cannot final modifier");
} else if (m.getName().equals("sncp_setFuture") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_setFuture method cannot final modifier");
} else if (m.getName().equals("sncp_getFuture") && Modifier.isFinal(m.getModifiers())) {
throw new RuntimeException(param + "'s sncp_getFuture method cannot final modifier");
}
}
}
public static String toSimpleString(final Service service, int maxNameLength, int maxClassNameLength) {
StringBuilder sb = new StringBuilder();
sb.append(isRemote(service) ? "RemoteService" : "LocalService ");
int len;
Class[] types = getResourceTypes(service);
String name = getResourceName(service);
if (types.length == 1) {
sb.append("(type= ").append(types[0].getName());
len = maxClassNameLength - types[0].getName().length();
} else {
StringBuilder s = new StringBuilder();
s.append('[');
s.append(Arrays.asList(types).stream().map((Class t) -> t.getName()).collect(Collectors.joining(",")));
s.append(']');
sb.append("(types=").append(s);
len = maxClassNameLength - s.length();
}
for (int i = 0; i < len; i++) {
sb.append(' ');
}
sb.append(", name='").append(name).append("'");
for (int i = 0; i < maxNameLength - name.length(); i++) {
sb.append(' ');
}
sb.append(")");
return sb.toString();
}
/**
* <blockquote><pre>
* public class TestService implements Service{
@@ -139,16 +258,16 @@ public abstract class Sncp {
* }
*
* &#64;RpcMultiRun(selfrun = false)
public void createSomeThing(TestBean bean){
//do something
}
&#64;RpcMultiRun
public String updateSomeThing(String id){
return "hello" + id;
}
}
</pre></blockquote>
* public void createSomeThing(TestBean bean){
* //do something
* }
*
* &#64;RpcMultiRun
* public String updateSomeThing(String id){
* return "hello" + id;
* }
* }
* </pre></blockquote>
*
* <blockquote><pre>
* &#64;Resource(name = "")
@@ -156,12 +275,20 @@ public abstract class Sncp {
* &#64;ResourceType({TestService.class})
* public final class _DynLocalTestService extends TestService{
*
* private static final Class _redkale_service_type = TestService.class;
*
* &#64;Resource
* private BsonConvert _redkale_bsonConvert;
*
* &#64;Resource
* private JsonConvert _redkale_jsonConvert;
*
* private AnyValue _redkale_conf;
*
* private String _redkale_sncpGroup; //自身的组节点名 可能为null
*
* private Set&lt;String&gt; groups; //所有的组节点,包含自身
*
* private Transport _redkale_sameGroupTransport;
*
* private Transport[] _redkale_diffGroupTransports;
@@ -184,8 +311,8 @@ public abstract class Sncp {
* public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
* if(selfrunnable) super.createSomeThing(bean);
* if (_redkale_client== null) return;
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 0, true, false, false, bean);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 0, true, true, false, bean);
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_sameGroupTransport, 0, true, false, false, bean);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_diffGroupTransports, 0, true, true, false, bean);
* }
*
* &#64;Override
@@ -196,9 +323,9 @@ public abstract class Sncp {
* &#64;SncpDyn(remote = false, index = 1)
* public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
* String rs = super.updateSomeThing(id);
* if (_redkale_client== null) return;
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _sameGroupTransport, 1, true, false, false, id);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _diffGroupTransports, 1, true, true, false, id);
* if (_redkale_client== null) return rs;
* if (samerunnable) _redkale_client.remoteSameGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_sameGroupTransport, 1, true, false, false, id);
* if (diffrunnable) _redkale_client.remoteDiffGroup(_redkale_bsonConvert, _redkale_jsonConvert, _redkale_diffGroupTransports, 1, true, true, false, id);
* return rs;
* }
* }
@@ -208,38 +335,41 @@ public abstract class Sncp {
*
* @param <T> Service子类
* @param name 资源名
* @param serviceClass Service类
* @param serviceImplClass Service类
*
* @return Service实例
*/
@SuppressWarnings("unchecked")
protected static <T extends Service> Class<? extends T> createLocalServiceClass(final String name, final Class<T> serviceClass) {
if (serviceClass == null) return null;
if (!Service.class.isAssignableFrom(serviceClass)) return serviceClass;
int mod = serviceClass.getModifiers();
if (!java.lang.reflect.Modifier.isPublic(mod)) return serviceClass;
if (java.lang.reflect.Modifier.isAbstract(mod)) return serviceClass;
final List<Method> methods = SncpClient.parseMethod(serviceClass);
final String supDynName = serviceClass.getName().replace('.', '/');
protected static <T extends Service> Class<? extends T> createLocalServiceClass(final String name, final Class<T> serviceImplClass) {
if (serviceImplClass == null) return null;
if (!Service.class.isAssignableFrom(serviceImplClass)) return serviceImplClass;
int mod = serviceImplClass.getModifiers();
if (!java.lang.reflect.Modifier.isPublic(mod)) return serviceImplClass;
if (java.lang.reflect.Modifier.isAbstract(mod)) return serviceImplClass;
final List<Method> methods = SncpClient.parseMethod(serviceImplClass);
final String supDynName = serviceImplClass.getName().replace('.', '/');
final String clientName = SncpClient.class.getName().replace('.', '/');
final String clientDesc = Type.getDescriptor(SncpClient.class);
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
final String stringDesc = Type.getDescriptor(String.class);
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
final String transportDesc = Type.getDescriptor(Transport.class);
final String transportsDesc = Type.getDescriptor(Transport[].class);
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceClass.getSimpleName();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceImplClass.getSimpleName();
if (!name.isEmpty()) {
boolean normal = true;
for (char ch : name.toCharArray()) {
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false;
}
if (!normal) throw new RuntimeException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z");
newDynName += "_" + (normal ? name : hash(name));
}
try {
return (Class<T>) Class.forName(newDynName.replace('/', '.'));
} catch (Exception ex) {
} catch (Throwable ex) {
}
//------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
@@ -259,7 +389,7 @@ public abstract class Sncp {
av0.visitEnd();
}
{ //给新类加上 原有的Annotation
for (Annotation ann : serviceClass.getAnnotations()) {
for (Annotation ann : serviceImplClass.getAnnotations()) {
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue;
visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
}
@@ -268,9 +398,9 @@ public abstract class Sncp {
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{
AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class);
ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class);
if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass)));
av1.visit(null, Type.getType(Type.getDescriptor(serviceImplClass)));
} else {
for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl)));
@@ -280,7 +410,10 @@ public abstract class Sncp {
}
av0.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, FIELDPREFIX + "_service_type", "Ljava/lang/Class;", null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
@@ -293,6 +426,18 @@ public abstract class Sncp {
av0.visitEnd();
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpGroup", stringDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_groups", "Ljava/util/Set;", "Ljava/util/Set<Ljava/lang/String;>;", null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sameGroupTransport", transportDesc, null, null);
fv.visitEnd();
@@ -310,6 +455,14 @@ public abstract class Sncp {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null);
fv.visitEnd();
}
{//静态构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(serviceImplClass)));
mv.visitFieldInsn(PUTSTATIC, newDynName, FIELDPREFIX + "_service_type", "Ljava/lang/Class;");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
{ //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
@@ -362,7 +515,13 @@ public abstract class Sncp {
mv.visitInsn(mrun.samerun() ? ICONST_1 : ICONST_0);
mv.visitInsn(mrun.diffrun() ? ICONST_1 : ICONST_0);
int varindex = 0;
boolean handlerFuncFlag = false;
for (Class pt : paramtypes) {
if (AsyncHandler.class.isAssignableFrom(pt)) {
if (handlerFuncFlag) throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
checkAsyncModifier(pt, method);
handlerFuncFlag = true;
}
if (pt.isPrimitive()) {
if (pt == long.class) {
mv.visitVarInsn(LLOAD, ++varindex);
@@ -403,8 +562,15 @@ public abstract class Sncp {
//mv.setDebug(true);
{ //给参数加上 Annotation
final Annotation[][] anns = method.getParameterAnnotations();
boolean handlerAttachFlag = false;
for (int k = 0; k < anns.length; k++) {
for (Annotation ann : anns[k]) {
if (ann.annotationType() == RpcAttachment.class) {
if (handlerAttachFlag) {
throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
}
handlerAttachFlag = true;
}
if (ann instanceof SncpDyn || ann instanceof RpcMultiRun) continue; //必须过滤掉 RpcMultiRun、SncpDyn否则生成远程模式Service时会出错
visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
}
@@ -501,7 +667,7 @@ public abstract class Sncp {
mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransport
mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_sameGroupTransport", transportDesc);
final int preparams = 4; //调用selfrunnable之前的参数个数; _client/_bsonConvert/_jsonConvert/_sameGroupTransport
final int preparams = 3; //调用selfrunnable之前的参数个数; _client/_bsonConvert/_jsonConvert/_sameGroupTransport
if (index <= 5) { //第几个 SncpAction
mv.visitInsn(ICONST_0 + index);
@@ -524,13 +690,13 @@ public abstract class Sncp {
mv.visitInsn(DUP);
mv.visitInsn(ICONST_1);
mv.visitInsn(ICONST_0); //第个参数 samerunnable
mv.visitInsn(ICONST_0); //第个参数 samerunnable
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(AASTORE);
mv.visitInsn(DUP);
mv.visitInsn(ICONST_2);
mv.visitInsn(ICONST_0); //第个参数 diffrunnable
mv.visitInsn(ICONST_0); //第个参数 diffrunnable
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(AASTORE);
@@ -719,6 +885,10 @@ public abstract class Sncp {
}
}
public static <T extends Service> T createSimpleLocalService(final String name, final Class<T> serviceImplClass, final InetSocketAddress clientAddress, final Transport sameGroupTransport) {
return createLocalService(name, null, ResourceFactory.root(), serviceImplClass, clientAddress, null, new HashSet<>(), null, sameGroupTransport, null);
}
/**
*
* 创建本地模式Service实例
@@ -727,18 +897,30 @@ public abstract class Sncp {
* @param name 资源名
* @param executor 线程池
* @param resourceFactory 资源容器
* @param serviceClass Service类
* @param serviceImplClass Service类
* @param clientAddress 本地IP地址
* @param sncpGroup 自身的组节点名 可能为null
* @param groups 所有的组节点,包含自身
* @param conf 启动配置项
* @param sameGroupTransport 同组的通信组件
* @param diffGroupTransports 异组的通信组件列表
*
* @return Service的本地模式实例
*/
@SuppressWarnings("unchecked")
public static <T extends Service> T createLocalService(final String name, final Consumer<Runnable> executor, final ResourceFactory resourceFactory,
final Class<T> serviceClass, final InetSocketAddress clientAddress, final Transport sameGroupTransport, final Collection<Transport> diffGroupTransports) {
public static <T extends Service> T createLocalService(
final String name,
final Consumer<Runnable> executor,
final ResourceFactory resourceFactory,
final Class<T> serviceImplClass,
final InetSocketAddress clientAddress,
final String sncpGroup,
final Set<String> groups,
final AnyValue conf,
final Transport sameGroupTransport,
final Collection<Transport> diffGroupTransports) {
try {
final Class newClazz = createLocalServiceClass(name, serviceClass);
final Class newClazz = createLocalServiceClass(name, serviceImplClass);
T rs = (T) newClazz.newInstance();
//--------------------------------------
Service remoteService = null;
@@ -770,7 +952,7 @@ public abstract class Sncp {
}
}
if (remoteService == null && remoteTransport != null) {
remoteService = createRemoteService(name, executor, serviceClass, clientAddress, remoteTransport);
remoteService = createRemoteService(name, executor, serviceImplClass, clientAddress, sncpGroup, groups, conf, remoteTransport);
}
if (remoteService != null) field.set(rs, remoteService);
}
@@ -781,7 +963,7 @@ public abstract class Sncp {
try {
Field e = newClazz.getDeclaredField(FIELDPREFIX + "_client");
e.setAccessible(true);
client = new SncpClient(name, serviceClass, rs, executor, false, newClazz, clientAddress);
client = new SncpClient(name, serviceImplClass, rs, executor, false, newClazz, clientAddress);
e.set(rs, client);
} catch (NoSuchFieldException ne) {
}
@@ -793,13 +975,13 @@ public abstract class Sncp {
sb.append(", serviceid = ").append(client.getServiceid());
sb.append(", serviceversion = ").append(client.getServiceversion());
sb.append(", action.size = ").append(client.getActionCount());
List<String> groups = new ArrayList<>();
if (sameGroupTransport != null) groups.add(sameGroupTransport.getName());
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
groups.add(t.getName());
}
}
// List<String> groups = new ArrayList<>();
// if (sameGroupTransport != null) groups.add(sameGroupTransport.getName());
// if (diffGroupTransports != null) {
// for (Transport t : diffGroupTransports) {
// groups.add(t.getName());
// }
// }
sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups);
sb.append(", sameaddrs = ").append(sameGroupTransport == null ? null : Arrays.asList(sameGroupTransport.getRemoteAddresses()));
@@ -819,6 +1001,21 @@ public abstract class Sncp {
s.set(rs, sb.toString());
}
if (client == null) return rs;
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncpGroup");
c.setAccessible(true);
c.set(rs, sncpGroup);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_groups");
c.setAccessible(true);
c.set(rs, groups);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
c.setAccessible(true);
c.set(rs, conf);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sameGroupTransport");
c.setAccessible(true);
@@ -838,6 +1035,10 @@ public abstract class Sncp {
}
public static <T extends Service> T createSimpleRemoteService(final String name, final Class<T> serviceTypeOrImplClass, final InetSocketAddress clientAddress, final Transport transport) {
return createRemoteService(name, null, serviceTypeOrImplClass, clientAddress, (String) null, new HashSet<>(), (AnyValue) null, transport);
}
/**
* <blockquote><pre>
* &#64;Resource(name = "")
@@ -845,12 +1046,20 @@ public abstract class Sncp {
* &#64;ResourceType({TestService.class})
* public final class _DynRemoteTestService extends TestService{
*
* private static final Class _redkale_service_type = TestService.class;
*
* &#64;Resource
* private BsonConvert _redkale_bsonConvert;
*
* &#64;Resource
* private JsonConvert _redkale_jsonConvert;
*
* private String _redkale_sncpGroup; //自身的组节点名 可能为null
*
* private Set&lt;String&gt; groups; //所有的组节点,包含自身
*
* private AnyValue _redkale_conf;
*
* private Transport _redkale_transport;
*
* private SncpClient _redkale_client;
@@ -894,34 +1103,45 @@ public abstract class Sncp {
* @param <T> Service泛型
* @param name 资源名
* @param executor 线程池
* @param serviceClass Service类
* @param serviceTypeOrImplClass Service类
* @param clientAddress 本地IP地址
* @param sncpGroup 自身的组节点名 可能为null
* @param groups 所有的组节点,包含自身
* @param conf 启动配置项
* @param transport 通信组件
*
* @return Service的远程模式实例
*/
@SuppressWarnings("unchecked")
public static <T extends Service> T createRemoteService(final String name, final Consumer<Runnable> executor, final Class<T> serviceClass,
final InetSocketAddress clientAddress, final Transport transport) {
if (serviceClass == null) return null;
if (!Service.class.isAssignableFrom(serviceClass)) return null;
int mod = serviceClass.getModifiers();
boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceClass.isInterface());
public static <T extends Service> T createRemoteService(
final String name,
final Consumer<Runnable> executor,
final Class<T> serviceTypeOrImplClass,
final InetSocketAddress clientAddress,
final String sncpGroup,
final Set<String> groups,
final AnyValue conf,
final Transport transport) {
if (serviceTypeOrImplClass == null) return null;
if (!Service.class.isAssignableFrom(serviceTypeOrImplClass)) return null;
int mod = serviceTypeOrImplClass.getModifiers();
boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface());
if (!java.lang.reflect.Modifier.isPublic(mod)) return null;
final String supDynName = serviceClass.getName().replace('.', '/');
final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
final String clientName = SncpClient.class.getName().replace('.', '/');
final String clientDesc = Type.getDescriptor(SncpClient.class);
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
final String bsonConvertDesc = Type.getDescriptor(BsonConvert.class);
final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
final String transportDesc = Type.getDescriptor(Transport.class);
final String stringDesc = Type.getDescriptor(String.class);
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceClass.getSimpleName();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceTypeOrImplClass.getSimpleName();
try {
Class newClazz = Class.forName(newDynName.replace('/', '.'));
T rs = (T) newClazz.newInstance();
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
c.setAccessible(true);
c.set(rs, client);
@@ -942,7 +1162,7 @@ public abstract class Sncp {
s.set(rs, sb.toString());
}
return rs;
} catch (Exception ex) {
} catch (Throwable ex) {
}
//------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
@@ -950,7 +1170,7 @@ public abstract class Sncp {
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceClass.isInterface() ? "java/lang/Object" : supDynName, serviceClass.isInterface() ? new String[]{supDynName} : null);
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, serviceTypeOrImplClass.isInterface() ? new String[]{supDynName} : null);
{
av0 = cw.visitAnnotation("Ljavax/annotation/Resource;", true);
av0.visit("name", name);
@@ -960,9 +1180,9 @@ public abstract class Sncp {
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{
AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class);
ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class);
if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass)));
av1.visit(null, Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
} else {
for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl)));
@@ -978,11 +1198,15 @@ public abstract class Sncp {
av0.visitEnd();
}
{ //给新类加上 原有的Annotation
for (Annotation ann : serviceClass.getAnnotations()) {
for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType) continue;
visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
}
}
{
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, FIELDPREFIX + "_service_type", "Ljava/lang/Class;", null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_bsonConvert", bsonConvertDesc, null, null);
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
@@ -995,6 +1219,18 @@ public abstract class Sncp {
av0.visitEnd();
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_sncpGroup", stringDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_groups", "Ljava/util/Set;", "Ljava/util/Set<Ljava/lang/String;>;", null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_transport", transportDesc, null, null);
fv.visitEnd();
@@ -1007,11 +1243,19 @@ public abstract class Sncp {
fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_selfstring", "Ljava/lang/String;", null, null);
fv.visitEnd();
}
{//静态构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(serviceTypeOrImplClass)));
mv.visitFieldInsn(PUTSTATIC, newDynName, FIELDPREFIX + "_service_type", "Ljava/lang/Class;");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
{ //构造函数
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
//mv.setDebug(true);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, serviceClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false);
mv.visitMethodInsn(INVOKESPECIAL, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
@@ -1047,7 +1291,7 @@ public abstract class Sncp {
mv.visitEnd();
}
int i = -1;
for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(name, serviceClass) : serviceClass)) {
for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass)) {
final int index = ++i;
final java.lang.reflect.Method method = entry.method;
{
@@ -1156,13 +1400,32 @@ public abstract class Sncp {
}.loadClass(newDynName.replace('/', '.'), bytes);
try {
T rs = (T) newClazz.newInstance();
SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
c.setAccessible(true);
SncpClient client = new SncpClient(name, serviceClass, rs, executor, true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
c.set(rs, client);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
c.setAccessible(true);
c.set(rs, conf);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_sncpGroup");
c.setAccessible(true);
c.set(rs, sncpGroup);
}
{
Field c = newClazz.getDeclaredField(FIELDPREFIX + "_groups");
c.setAccessible(true);
c.set(rs, groups);
}
{
Field t = newClazz.getDeclaredField(FIELDPREFIX + "_transport");
t.setAccessible(true);
t.set(rs, transport);
}
{
StringBuilder sb = new StringBuilder();
sb.append(newClazz.getName()).append("{name = '").append(name);

View File

@@ -0,0 +1,307 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.net.sncp;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import org.redkale.convert.bson.*;
import org.redkale.net.sncp.SncpDynServlet.SncpServletAction;
import org.redkale.util.*;
/**
* 异步回调函数 <br>
*
* public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <V> 结果对象的泛型
* @param <A> 附件对象的泛型
*/
public interface SncpAsyncHandler<V, A> extends AsyncHandler<V, A> {
public Object[] sncp_getParams();
public void sncp_setParams(Object... params);
public void sncp_setFuture(CompletableFuture future);
public CompletableFuture sncp_getFuture();
static class Factory {
/**
* <blockquote><pre>
*
* 考虑点:
* 1、AsyncHandler子类是接口且还有其他多个方法
* 2、AsyncHandler子类是类 需要继承,且必须有空参数构造函数
* 3、AsyncHandler子类无论是接口还是类都可能存在其他泛型
*
* public class XXXAsyncHandler_DyncSncpAsyncHandler_4323 extends XXXAsyncHandler implements SncpAsyncHandler {
*
* private SncpAsyncHandler sncphandler;
*
* private CompletableFuture sncpfuture;
*
* &#64;java.beans.ConstructorProperties({"sncphandler"})
* public XXXAsyncHandler_DyncSncpAsyncHandler_4323(SncpAsyncHandler sncphandler) {
* super();
* this.sncphandler = sncphandler;
* }
*
* &#64;Override
* public void completed(Object result, Object attachment) {
* sncphandler.completed(result, attachment);
* }
*
* &#64;Override
* public void failed(Throwable exc, Object attachment) {
* sncphandler.failed(exc, attachment);
* }
*
* &#64;Override
* public Object[] sncp_getParams() {
* return sncphandler.sncp_getParams();
* }
*
* &#64;Override
* public void sncp_setParams(Object... params) {
* sncphandler.sncp_setParams(params);
* }
*
* &#64;Override
* public void sncp_setFuture(CompletableFuture future) {
* this.sncpfuture = future;
* }
*
* &#64;Override
* public CompletableFuture sncp_getFuture() {
* return this.sncpfuture;
* }
* }
*
* </pre></blockquote>
*
* @param handlerClass AsyncHandler类型或子类
*
* @return Creator
*/
public static Creator<SncpAsyncHandler> createCreator(Class<? extends AsyncHandler> handlerClass) {
//-------------------------------------------------------------
final boolean handlerinterface = handlerClass.isInterface();
final String handlerClassName = handlerClass.getName().replace('.', '/');
final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/');
final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class);
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + SncpAsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
AsmMethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName});
{ //handler 属性
fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null);
fv.visitEnd();
}
{ //future 属性
fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null);
fv.visitEnd();
}
{//构造方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + sncpHandlerDesc + ")V", null, null));
//mv.setDebug(true);
{
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
{
AnnotationVisitor av1 = av0.visitArray("value");
av1.visit(null, "sncphandler");
av1.visitEnd();
}
av0.visitEnd();
}
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
Class returnType = method.getReturnType();
if (returnType == void.class) {
mv.visitInsn(RETURN);
mv.visitMaxs(0, 1);
} else if (returnType.isPrimitive()) {
mv.visitInsn(ICONST_0);
if (returnType == long.class) {
mv.visitInsn(LRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == float.class) {
mv.visitInsn(FRETURN);
mv.visitMaxs(2, 1);
} else if (returnType == double.class) {
mv.visitInsn(DRETURN);
mv.visitMaxs(2, 1);
} else {
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
}
} else {
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
}
mv.visitEnd();
}
}
{ // sncp_getParams
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{ // sncp_setParams
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{ // sncp_setFuture
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{ // sncp_getFuture
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class<SncpAsyncHandler> newHandlerClazz = (Class<SncpAsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}.loadClass(newDynName.replace('/', '.'), bytes);
return Creator.create(newHandlerClazz);
}
}
static class DefaultSncpAsyncHandler<V, A> implements SncpAsyncHandler<V, A> {
//为了在回调函数中调用_callParameter方法
protected Object[] params;
protected SncpServletAction action;
protected BsonReader in;
protected BsonWriter out;
protected SncpRequest request;
protected SncpResponse response;
protected CompletableFuture future;
public DefaultSncpAsyncHandler(SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) {
this.action = action;
this.in = in;
this.out = out;
this.request = request;
this.response = response;
}
@Override
public void completed(Object result, Object attachment) {
try {
action._callParameter(out, sncp_getParams());
action.convert.convertTo(out, Object.class, result);
response.finish(0, out);
} catch (Exception e) {
failed(e, attachment);
} finally {
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
}
}
@Override
public void failed(Throwable exc, Object attachment) {
response.getContext().getLogger().log(Level.INFO, "sncp execute error(" + request + ")", exc);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
}
@Override
public Object[] sncp_getParams() {
return params;
}
@Override
public void sncp_setParams(Object... params) {
this.params = params;
}
@Override
public void sncp_setFuture(CompletableFuture future) {
this.future = future;
}
@Override
public CompletableFuture sncp_getFuture() {
return this.future;
}
}
}

View File

@@ -41,35 +41,66 @@ public final class SncpClient {
protected final Type[] paramTypes;
protected final Class[] paramClass;
protected final Attribute[] paramAttrs; // 为null表示无RpcCall处理index=0固定为null, 其他为参数标记的RpcCall回调方法
protected final int handlerFuncParamIndex;
protected final int handlerAttachParamIndex;
protected final int addressTargetParamIndex;
protected final int addressSourceParamIndex;
public SncpAction(Method method, DLong actionid) {
this.actionid = actionid;
protected final boolean boolReturnTypeFuture; // 返回结果类型是否为 CompletableFuture
protected final Creator<? extends CompletableFuture> futureCreator;
public SncpAction(final Class clazz, Method method, DLong actionid) {
this.actionid = actionid == null ? Sncp.hash(method) : actionid;
Type rt = method.getGenericReturnType();
if (rt instanceof TypeVariable) {
TypeVariable tv = (TypeVariable) rt;
if (tv.getBounds().length == 1) rt = tv.getBounds()[0];
}
this.resultTypes = rt == void.class ? null : rt;
this.boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
this.futureCreator = boolReturnTypeFuture ? Creator.create((Class<? extends CompletableFuture>) method.getReturnType()) : null;
this.paramTypes = method.getGenericParameterTypes();
this.paramClass = method.getParameterTypes();
this.method = method;
Annotation[][] anns = method.getParameterAnnotations();
int targetAddrIndex = -1;
int sourceAddrIndex = -1;
int handlerAttachIndex = -1;
int handlerFuncIndex = -1;
boolean hasattr = false;
Attribute[] atts = new Attribute[paramTypes.length + 1];
if (anns.length > 0) {
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (AsyncHandler.class.isAssignableFrom(params[i])) {
if (boolReturnTypeFuture) {
throw new RuntimeException(method + " have both AsyncHandler and CompletableFuture");
}
if (handlerFuncIndex >= 0) {
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
}
Sncp.checkAsyncModifier(params[i], method);
handlerFuncIndex = i;
break;
}
}
for (int i = 0; i < anns.length; i++) {
if (anns[i].length > 0) {
for (Annotation ann : anns[i]) {
if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
if (ann.annotationType() == RpcAttachment.class) {
if (handlerAttachIndex >= 0) {
throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
}
handlerAttachIndex = i;
} else if (ann.annotationType() == RpcTargetAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
targetAddrIndex = i;
} else if (ann.annotationType() == RpcSourceAddress.class && SocketAddress.class.isAssignableFrom(params[i])) {
sourceAddrIndex = i;
@@ -91,7 +122,12 @@ public final class SncpClient {
}
this.addressTargetParamIndex = targetAddrIndex;
this.addressSourceParamIndex = sourceAddrIndex;
this.handlerFuncParamIndex = handlerFuncIndex;
this.handlerAttachParamIndex = handlerAttachIndex;
this.paramAttrs = hasattr ? atts : null;
if (this.handlerFuncParamIndex >= 0 && method.getReturnType() != void.class) {
throw new RuntimeException(method + " have AsyncHandler type parameter but return type is not void");
}
}
@Override
@@ -126,19 +162,22 @@ public final class SncpClient {
protected final Consumer<Runnable> executor;
public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceType, final T service, final Consumer<Runnable> executor,
public <T extends Service> SncpClient(final String serviceName, final Class<T> serviceTypeOrImplClass, final T service, final Consumer<Runnable> executor,
final boolean remote, final Class serviceClass, final InetSocketAddress clientAddress) {
this.remote = remote;
this.executor = executor;
this.serviceClass = serviceClass;
this.serviceversion = service.version();
this.serviceversion = 0;
this.clientAddress = clientAddress;
this.name = serviceName;
this.serviceid = Sncp.hash(serviceType.getName() + ':' + serviceName);
Class tn = serviceTypeOrImplClass;
ResourceType rt = (ResourceType) tn.getAnnotation(ResourceType.class);
if (rt != null && rt.value().length > 0) tn = rt.value()[0];
this.serviceid = Sncp.hash(tn.getName() + ':' + serviceName);
final List<SncpAction> methodens = new ArrayList<>();
//------------------------------------------------------------------------------
for (java.lang.reflect.Method method : parseMethod(serviceClass)) {
methodens.add(new SncpAction(method, Sncp.hash(method)));
methodens.add(new SncpAction(serviceClass, method, Sncp.hash(method)));
}
this.actions = methodens.toArray(new SncpAction[methodens.size()]);
this.addrBytes = clientAddress == null ? new byte[4] : clientAddress.getAddress().getAddress();
@@ -149,7 +188,7 @@ public final class SncpClient {
final List<SncpAction> actions = new ArrayList<>();
//------------------------------------------------------------------------------
for (java.lang.reflect.Method method : parseMethod(serviceClass)) {
actions.add(new SncpAction(method, Sncp.hash(method)));
actions.add(new SncpAction(serviceClass, method, Sncp.hash(method)));
}
return actions;
}
@@ -193,7 +232,7 @@ public final class SncpClient {
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
if (method.getName().equals("version") || method.getName().equals("name")) continue;
//if (method.getName().equals("version") || method.getName().equals("name")) continue;
//if (onlySncpDyn && method.getAnnotation(SncpDyn.class) == null) continue;
DLong actionid = Sncp.hash(method);
Method old = actionids.get(actionid);
@@ -221,13 +260,16 @@ public final class SncpClient {
}
public void remoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
if (transport == null) return;
final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (InetSocketAddress addr : transport.getRemoteAddresses()) {
remote0(bsonConvert, jsonConvert, transport, addr, action, params);
remote0(null, bsonConvert, jsonConvert, transport, addr, action, params);
}
}
public void asyncRemoteSameGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
if (transport == null) return;
if (executor != null) {
executor.accept(() -> {
remoteSameGroup(bsonConvert, jsonConvert, transport, index, params);
@@ -240,8 +282,9 @@ public final class SncpClient {
public void remoteDiffGroup(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return;
final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (Transport transport : transports) {
remote0(bsonConvert, jsonConvert, transport, null, action, params);
remote0(null, bsonConvert, jsonConvert, transport, null, action, params);
}
}
@@ -259,9 +302,34 @@ public final class SncpClient {
//只给远程模式调用的
public <T> T remote(final BsonConvert bsonConvert, final JsonConvert jsonConvert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index];
SncpFuture<byte[]> future = remote0(bsonConvert, jsonConvert, transport, null, action, params);
final AsyncHandler handlerFunc = action.handlerFuncParamIndex >= 0 ? (AsyncHandler) params[action.handlerFuncParamIndex] : null;
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null;
final BsonReader reader = bsonConvert.pollBsonReader();
CompletableFuture<byte[]> future = remote0(handlerFunc, bsonConvert, jsonConvert, transport, null, action, params);
if (action.boolReturnTypeFuture) {
CompletableFuture result = action.futureCreator.create();
future.whenComplete((v, e) -> {
try {
if (e != null) {
result.completeExceptionally(e);
} else {
reader.setBytes(v);
byte i;
while ((i = reader.readByte()) != 0) {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
Object rs = bsonConvert.convertFrom(Object.class, reader);
result.complete(rs);
}
} finally {
bsonConvert.offerBsonReader(reader);
}
}); //需要获取 Executor
return (T) result;
}
if (handlerFunc != null) return null;
try {
reader.setBytes(future.get(5, TimeUnit.SECONDS));
byte i;
@@ -269,7 +337,7 @@ public final class SncpClient {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
return bsonConvert.convertFrom(action.resultTypes, reader);
return bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.log(Level.SEVERE, actions[index].method + " sncp (params: " + jsonConvert.convertTo(params) + ") remote error", e);
throw new RuntimeException(actions[index].method + " sncp remote error", e);
@@ -282,28 +350,30 @@ public final class SncpClient {
if (transports == null || transports.length < 1) return;
remote(bsonConvert, jsonConvert, transports[0], index, params);
for (int i = 1; i < transports.length; i++) {
remote0(bsonConvert, jsonConvert, transports[i], null, actions[index], params);
remote0(null, bsonConvert, jsonConvert, transports[i], null, actions[index], params);
}
}
private SncpFuture<byte[]> remote0(final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
private CompletableFuture<byte[]> remote0(final AsyncHandler handler, final BsonConvert bsonConvert, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
if ("rest".equalsIgnoreCase(transport.getSubprotocol())) {
return remoteRest0(jsonConvert, transport, addr0, action, params);
return remoteRest0(handler, jsonConvert, transport, addr0, action, params);
}
return remoteSncp0(bsonConvert, transport, addr0, action, params);
return remoteSncp0(handler, bsonConvert, transport, addr0, action, params);
}
private SncpFuture<byte[]> remoteRest0(final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
//尚未实现
private CompletableFuture<byte[]> remoteRest0(final AsyncHandler handler, final JsonConvert jsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
return null;
}
private SncpFuture<byte[]> remoteSncp0(final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
Type[] myparamtypes = action.paramTypes;
private CompletableFuture<byte[]> remoteSncp0(final AsyncHandler handler, final BsonConvert bsonConvert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
final Type[] myparamtypes = action.paramTypes;
final Class[] myparamclass = action.paramClass;
if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.clientAddress;
final BsonWriter writer = bsonConvert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
writer.writeTo(DEFAULT_HEADER);
for (int i = 0; i < params.length; i++) {
bsonConvert.convertTo(writer, myparamtypes[i], params[i]);
for (int i = 0; i < params.length; i++) { //params 可能包含: 3 个 boolean
bsonConvert.convertTo(writer, AsyncHandler.class.isAssignableFrom(myparamclass[i]) ? AsyncHandler.class : myparamtypes[i], params[i]);
}
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
final long seqid = System.nanoTime();
@@ -318,7 +388,7 @@ public final class SncpClient {
fillHeader(sendBuffers[0], seqid, actionid, reqBodyLength);
final ByteBuffer buffer = transport.pollBuffer();
final SncpFuture<byte[]> future = new SncpFuture(false);
final CompletableFuture<byte[]> future = new CompletableFuture();
conn.write(sendBuffers, sendBuffers, new CompletionHandler<Integer, ByteBuffer[]>() {
@Override
@@ -352,7 +422,7 @@ public final class SncpClient {
@Override
public void completed(Integer count, Void attachment2) {
if (count < 1 && buffer.remaining() == buffer.limit()) { //没有数据可读
future.set(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
future.completeExceptionally(new RuntimeException(action.method + " sncp[" + conn.getRemoteAddress() + "] remote no response data"));
transport.offerBuffer(buffer);
transport.offerConnection(true, conn);
return;
@@ -397,17 +467,39 @@ public final class SncpClient {
}
public void success() {
future.set(this.body);
future.complete(this.body);
transport.offerBuffer(buffer);
transport.offerConnection(false, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
final BsonReader reader = bsonConvert.pollBsonReader();
try {
reader.setBytes(this.body);
int i;
while ((i = (reader.readByte() & 0xff)) != 0) {
final Attribute attr = action.paramAttrs[i];
attr.set(params[i - 1], bsonConvert.convertFrom(attr.type(), reader));
}
Object rs = bsonConvert.convertFrom(action.handlerFuncParamIndex >= 0 ? Object.class : action.resultTypes, reader);
handler.completed(rs, handlerAttach);
} catch (Exception e) {
handler.failed(e, handlerAttach);
} finally {
bsonConvert.offerBsonReader(reader);
}
}
}
@Override
public void failed(Throwable exc, Void attachment2) {
logger.log(Level.SEVERE, action.method + " sncp (params: " + convert.convertTo(params) + ") remote read exec failed", exc);
future.set(new RuntimeException(action.method + " sncp remote exec failed"));
future.completeExceptionally(new RuntimeException(action.method + " sncp remote exec failed"));
transport.offerBuffer(buffer);
transport.offerConnection(true, conn);
if (handler != null) {
final Object handlerAttach = action.handlerAttachParamIndex >= 0 ? params[action.handlerAttachParamIndex] : null;
handler.failed(exc, handlerAttach);
}
}
});
}
@@ -431,7 +523,8 @@ public final class SncpClient {
int version = buffer.getInt();
if (version != this.serviceversion) throw new RuntimeException("sncp(" + action.method + ") response.serviceversion = " + serviceversion + ", but request.serviceversion =" + version);
DLong raction = DLong.read(buffer);
if (!action.actionid.equals(raction)) throw new RuntimeException("sncp(" + action.method + ") response.actionid = " + action.actionid + ", but request.actionid =(" + raction + ")");
DLong actid = action.actionid;
if (!actid.equals(raction)) throw new RuntimeException("sncp(" + action.method + ") response.actionid = " + action.actionid + ", but request.actionid =(" + raction + ")");
buffer.getInt(); //地址
buffer.getChar(); //端口
}
@@ -452,91 +545,4 @@ public final class SncpClient {
buffer.position(currentpos);
}
protected static final class SncpFuture<T> implements Future<T> {
private volatile boolean done;
private T result;
private RuntimeException ex;
private final boolean rest;
public SncpFuture(boolean rest) {
this.rest = rest;
}
public SncpFuture(boolean rest, T result) {
this.rest = rest;
this.result = result;
this.done = true;
}
public boolean isRest() {
return this.rest;
}
public void set(T result) {
this.result = result;
this.done = true;
synchronized (this) {
notifyAll();
}
}
public void set(RuntimeException ex) {
this.ex = ex;
this.done = true;
synchronized (this) {
notifyAll();
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return done;
}
@Override
public T get() throws InterruptedException, ExecutionException {
if (done) {
if (ex != null) throw ex;
return result;
}
synchronized (this) {
if (!done) wait(10_000);
}
if (done) {
if (ex != null) throw ex;
return result;
}
throw new InterruptedException();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (done) {
if (ex != null) throw ex;
return result;
}
synchronized (this) {
if (!done) wait(unit.toMillis(timeout));
}
if (done) {
if (ex != null) throw ex;
return result;
}
throw new TimeoutException();
}
}
}

View File

@@ -11,6 +11,7 @@ import java.lang.annotation.*;
import java.lang.reflect.*;
import java.nio.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.*;
import java.util.logging.*;
import javax.annotation.*;
@@ -19,6 +20,7 @@ import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import jdk.internal.org.objectweb.asm.Type;
import org.redkale.convert.bson.*;
import org.redkale.net.sncp.SncpAsyncHandler.DefaultSncpAsyncHandler;
import org.redkale.service.*;
import org.redkale.util.*;
import org.redkale.service.RpcCall;
@@ -63,7 +65,7 @@ public final class SncpDynServlet extends SncpServlet {
if (method.getName().equals("equals") || method.getName().equals("hashCode")) continue;
if (method.getName().equals("notify") || method.getName().equals("notifyAll") || method.getName().equals("wait")) continue;
if (method.getName().equals("init") || method.getName().equals("destroy")) continue;
if (method.getName().equals("version") || method.getName().equals("name")) continue;
//if (method.getName().equals("version") || method.getName().equals("name")) continue;
final DLong actionid = Sncp.hash(method);
SncpServletAction action = SncpServletAction.create(service, actionid, method);
action.convert = convert;
@@ -112,7 +114,7 @@ public final class SncpDynServlet extends SncpServlet {
if (bufferSupplier == null) {
bufferSupplier = request.getContext().getBufferSupplier();
}
SncpServletAction action = actions.get(request.getActionid());
final SncpServletAction action = actions.get(request.getActionid());
//if (finest) logger.log(Level.FINEST, "sncpdyn.execute: " + request + ", " + (action == null ? "null" : action.method));
if (action == null) {
response.finish(SncpResponse.RETCODE_ILLACTIONID, null); //无效actionid
@@ -120,16 +122,52 @@ public final class SncpDynServlet extends SncpServlet {
BsonWriter out = action.convert.pollBsonWriter(bufferSupplier);
out.writeTo(DEFAULT_HEADER);
BsonReader in = action.convert.pollBsonReader();
SncpAsyncHandler handler = null;
try {
if (action.handlerFuncParamIndex >= 0) {
if (action.handlerFuncParamClass == AsyncHandler.class) {
handler = new DefaultSncpAsyncHandler(action, in, out, request, response);
} else {
Creator<SncpAsyncHandler> creator = action.handlerCreator;
if (creator == null) {
creator = SncpAsyncHandler.Factory.createCreator(action.handlerFuncParamClass);
action.handlerCreator = creator;
}
handler = creator.create(new DefaultSncpAsyncHandler(action, in, out, request, response));
}
} else if (action.boolReturnTypeFuture) {
handler = new DefaultSncpAsyncHandler(action, in, out, request, response);
}
in.setBytes(request.getBody());
action.action(in, out);
action.action(in, out, handler);
if (handler == null) {
response.finish(0, out);
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
} else if (action.boolReturnTypeFuture) {
CompletableFuture future = handler.sncp_getFuture();
if (future == null) {
action._callParameter(out, handler.sncp_getParams());
action.convert.convertTo(out, Object.class, null);
} else {
Object[] sncpParams = handler.sncp_getParams();
future.whenComplete((v, e) -> {
if (e != null) {
response.getContext().getLogger().log(Level.INFO, "sncp CompleteAsync error(" + request + ")", e);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
return;
}
action._callParameter(out, sncpParams);
action.convert.convertTo(out, Object.class, v);
response.finish(0, out);
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
});
}
}
} catch (Throwable t) {
response.getContext().getLogger().log(Level.INFO, "sncp execute error(" + request + ")", t);
response.finish(SncpResponse.RETCODE_THROWEXCEPTION, null);
} finally {
action.convert.offerBsonReader(in);
action.convert.offerBsonWriter(out);
}
}
}
@@ -138,6 +176,8 @@ public final class SncpDynServlet extends SncpServlet {
public Method method;
public Creator<SncpAsyncHandler> handlerCreator;
@Resource
protected BsonConvert convert;
@@ -145,8 +185,15 @@ public final class SncpDynServlet extends SncpServlet {
protected java.lang.reflect.Type[] paramTypes; //index=0表示返回参数的type void的返回参数类型为null
public abstract void action(final BsonReader in, final BsonWriter out) throws Throwable;
protected int handlerFuncParamIndex = -1; //handlerFuncParamIndex>=0表示存在AsyncHandler参数
protected boolean boolReturnTypeFuture = false; // 返回结果类型是否为 CompletableFuture
protected Class handlerFuncParamClass; //AsyncHandler参数的类型
public abstract void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable;
//只有同步方法才调用 (没有AsyncHandler、CompletableFuture)
public final void _callParameter(final BsonWriter out, final Object... params) {
if (paramAttrs != null) {
for (int i = 1; i < paramAttrs.length; i++) {
@@ -162,17 +209,29 @@ public final class SncpDynServlet extends SncpServlet {
/**
* <blockquote><pre>
* public class TestService implements Service {
*
* public boolean change(TestBean bean, String name, int id) {
* return false;
* }
*
* public void insert(AsyncHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* public void update(long show, short v2, AsyncHandler&#60;Boolean, TestBean&#62; handler, TestBean bean, String name, int id) {
* }
*
* public CompletableFuture&#60;String&#62; changeName(TestBean bean, String name, int id) {
* return null;
* }
* }
*
* public class DynActionTestService_change extends SncpServletAction {
*
* class DynActionTestService_change extends SncpServletAction {
*
* public TestService service;
*
* &#64;Override
* public void action(final BsonReader in, final BsonWriter out) throws Throwable {
* &#064;Override
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
@@ -181,6 +240,57 @@ public final class SncpDynServlet extends SncpServlet {
* convert.convertTo(out, paramTypes[0], rs);
* }
* }
*
* class DynActionTestService_insert extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* SncpAsyncHandler arg0 = handler;
* convert.convertFrom(AsyncHandler.class, in);
* TestBean arg1 = convert.convertFrom(paramTypes[2], in);
* String arg2 = convert.convertFrom(paramTypes[3], in);
* int arg3 = convert.convertFrom(paramTypes[4], in);
* handler.sncp_setParams(arg0, arg1, arg2, arg3);
* service.insert(arg0, arg1, arg2, arg3);
* }
* }
*
* class DynActionTestService_update extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(BsonReader in, BsonWriter out, SncpAsyncHandler handler) throws Throwable {
* long a1 = convert.convertFrom(paramTypes[1], in);
* short a2 = convert.convertFrom(paramTypes[2], in);
* SncpAsyncHandler a3 = handler;
* convert.convertFrom(AsyncHandler.class, in);
* TestBean arg1 = convert.convertFrom(paramTypes[4], in);
* String arg2 = convert.convertFrom(paramTypes[5], in);
* int arg3 = convert.convertFrom(paramTypes[6], in);
* handler.sncp_setParams(a1, a2, a3, arg1, arg2, arg3);
* service.update(a1, a2, a3, arg1, arg2, arg3);
* }
* }
*
*
* class DynActionTestService_changeName extends SncpServletAction {
*
* public TestService service;
*
* &#064;Override
* public void action(final BsonReader in, final BsonWriter out, final SncpAsyncHandler handler) throws Throwable {
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
* handler.sncp_setParams(arg1, arg2, arg3);
* CompletableFuture future = service.changeName(arg1, arg2, arg3);
* handler.sncp_setFuture(future);
* }
* }
*
* </pre></blockquote>
*
* @param service Service
@@ -195,16 +305,19 @@ public final class SncpDynServlet extends SncpServlet {
final String supDynName = SncpServletAction.class.getName().replace('.', '/');
final String serviceName = serviceClass.getName().replace('.', '/');
final String convertName = BsonConvert.class.getName().replace('.', '/');
final String handlerName = SncpAsyncHandler.class.getName().replace('.', '/');
final String asyncHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class);
final String convertReaderDesc = Type.getDescriptor(BsonReader.class);
final String convertWriterDesc = Type.getDescriptor(BsonWriter.class);
final String serviceDesc = Type.getDescriptor(serviceClass);
final boolean boolReturnTypeFuture = CompletableFuture.class.isAssignableFrom(method.getReturnType());
String newDynName = serviceName.substring(0, serviceName.lastIndexOf('/') + 1)
+ "DynAction" + serviceClass.getSimpleName() + "_" + method.getName() + "_" + actionid;
while (true) {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName += "_";
} catch (Exception ex) {
} catch (Throwable ex) {
break;
}
}
@@ -236,15 +349,42 @@ public final class SncpDynServlet extends SncpServlet {
} catch (Exception ex) {
throw new RuntimeException(ex); //不可能会发生
}
int handlerFuncIndex = -1;
Class handlerFuncClass = null;
{ // action方法
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + ")V", null, new String[]{"java/lang/Throwable"}));
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "action", "(" + convertReaderDesc + convertWriterDesc + asyncHandlerDesc + ")V", null, new String[]{"java/lang/Throwable"}));
//mv.setDebug(true);
int iconst = ICONST_1;
int intconst = 1;
int store = 3; //action的参数个数+1
int store = 4; //action的参数个数+1
final Class[] paramClasses = method.getParameterTypes();
int[][] codes = new int[paramClasses.length][2];
for (int i = 0; i < paramClasses.length; i++) { //参数
for (int i = 0; i < paramClasses.length; i++) { //反序列化方法的每个参数
if (AsyncHandler.class.isAssignableFrom(paramClasses[i])) {
if (boolReturnTypeFuture) {
throw new RuntimeException(method + " have both AsyncHandler and CompletableFuture");
}
if (handlerFuncIndex >= 0) {
throw new RuntimeException(method + " have more than one AsyncHandler type parameter");
}
Sncp.checkAsyncModifier(paramClasses[i], method);
handlerFuncIndex = i;
handlerFuncClass = paramClasses[i];
mv.visitVarInsn(ALOAD, 3);
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
mv.visitVarInsn(ASTORE, store);
codes[i] = new int[]{ALOAD, store};
store++;
iconst++;
intconst++;
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitLdcInsn(Type.getType(Type.getDescriptor(AsyncHandler.class)));
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
mv.visitInsn(POP);
continue;
}
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitVarInsn(ALOAD, 0);
@@ -296,6 +436,43 @@ public final class SncpDynServlet extends SncpServlet {
intconst++;
store++;
}
if (boolReturnTypeFuture || handlerFuncIndex >= 0) { //调用SncpAsyncHandler.setParams(Object... params)
mv.visitVarInsn(ALOAD, 3);
if (paramClasses.length > 5) {
mv.visitIntInsn(BIPUSH, paramClasses.length);
} else {
mv.visitInsn(paramClasses.length + ICONST_0);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 3; //action的参数个数
for (int j = 0; j < paramClasses.length; j++) {
final Class pt = paramClasses[j];
mv.visitInsn(DUP);
insn++;
if (j <= 5) {
mv.visitInsn(ICONST_0 + j);
} else {
mv.visitIntInsn(BIPUSH, j);
}
if (pt.isPrimitive()) {
if (pt == long.class) {
mv.visitVarInsn(LLOAD, insn++);
} else if (pt == float.class) {
mv.visitVarInsn(FLOAD, insn++);
} else if (pt == double.class) {
mv.visitVarInsn(DLOAD, insn++);
} else {
mv.visitVarInsn(ILOAD, insn);
}
Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass();
mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
} else {
mv.visitVarInsn(ALOAD, insn);
}
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true);
}
{ //调用service
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "service", serviceDesc);
@@ -317,7 +494,13 @@ public final class SncpDynServlet extends SncpServlet {
}
}
mv.visitVarInsn(ASTORE, store); //11
if (boolReturnTypeFuture) {
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, store);
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "sncp_setFuture", "(Ljava/util/concurrent/CompletableFuture;)V", true);
}
}
if (!boolReturnTypeFuture && handlerFuncIndex < 0) { //同步方法
//------------------------- _callParameter 方法 --------------------------------
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
@@ -327,7 +510,7 @@ public final class SncpDynServlet extends SncpServlet {
mv.visitIntInsn(BIPUSH, paramClasses.length);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 2;
int insn = 3;//action的参数个数
for (int j = 0; j < paramClasses.length; j++) {
final Class pt = paramClasses[j];
mv.visitInsn(DUP);
@@ -355,13 +538,13 @@ public final class SncpDynServlet extends SncpServlet {
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "_callParameter", "(" + convertWriterDesc + "[Ljava/lang/Object;)V", false);
}
//-------------------------直接返回 或者 调用convertTo方法 --------------------------------
int maxStack = codes.length > 0 ? codes[codes.length - 1][1] : 1;
if (returnClass == void.class) { //返回
if (boolReturnTypeFuture || returnClass == void.class) { //返回
mv.visitInsn(RETURN);
maxStack = 8;
} else {
} else { //同步方法调用
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitVarInsn(ALOAD, 2);
@@ -398,6 +581,9 @@ public final class SncpDynServlet extends SncpServlet {
types[0] = rt;
System.arraycopy(ptypes, 0, types, 1, ptypes.length);
instance.paramTypes = types;
instance.handlerFuncParamIndex = handlerFuncIndex;
instance.handlerFuncParamClass = handlerFuncClass;
instance.boolReturnTypeFuture = boolReturnTypeFuture;
org.redkale.util.Attribute[] atts = new org.redkale.util.Attribute[ptypes.length + 1];
Annotation[][] anns = method.getParameterAnnotations();

View File

@@ -30,26 +30,22 @@ public class SncpPrepareServlet extends PrepareServlet<DLong, SncpContext, SncpR
public void addServlet(SncpServlet servlet, AnyValue conf) {
setServletConf(servlet, conf);
synchronized (mappings) {
mappings.put(servlet.getServiceid(), servlet);
servlets.add(servlet);
}
putMapping(servlet.getServiceid(), servlet);
putServlet(servlet);
}
public List<SncpServlet> getSncpServlets() {
ArrayList<SncpServlet> list = new ArrayList<>(servlets.size());
servlets.forEach(x -> list.add((SncpServlet) x));
return list;
return new ArrayList<>(getServlets());
}
@Override
public void init(SncpContext context, AnyValue config) {
servlets.forEach(s -> s.init(context, getServletConf(s)));
getServlets().forEach(s -> s.init(context, getServletConf(s)));
}
@Override
public void destroy(SncpContext context, AnyValue config) {
servlets.forEach(s -> s.destroy(context, getServletConf(s)));
getServlets().forEach(s -> s.destroy(context, getServletConf(s)));
}
@Override
@@ -58,7 +54,7 @@ public class SncpPrepareServlet extends PrepareServlet<DLong, SncpContext, SncpR
response.finish(pongBuffer.duplicate());
return;
}
SncpServlet servlet = (SncpServlet) mappings.get(request.getServiceid());
SncpServlet servlet = (SncpServlet) mappingServlet(request.getServiceid());
if (servlet == null) {
response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //无效serviceid
} else {

View File

@@ -38,15 +38,15 @@ public final class SncpServer extends Server<DLong, SncpContext, SncpRequest, Sn
super.init(config);
}
public void addSncpServlet(ServiceWrapper entry) {
for (Class type : entry.getTypes()) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), entry.getName(), type, entry.getService());
this.prepare.addServlet(sds, null, entry.getConf());
public void addSncpServlet(Service sncpService) {
for (Class type : Sncp.getResourceTypes(sncpService)) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), Sncp.getResourceName(sncpService), type, sncpService);
this.prepare.addServlet(sds, null, Sncp.getConf(sncpService));
}
}
public <T extends Service> void addSncpServlet(Class<T> serviceType, String name, T service, AnyValue conf) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), name, serviceType, service);
public <T extends Service> void addSncpServlet(Class<T> serviceTypeClass, String name, T service, AnyValue conf) {
SncpDynServlet sds = new SncpDynServlet(BsonFactory.root().getConvert(), name, serviceTypeClass, service);
this.prepare.addServlet(sds, null, conf);
}

View File

@@ -6,6 +6,7 @@
package org.redkale.net.sncp;
import java.util.Objects;
import java.util.concurrent.*;
import org.redkale.net.*;
import org.redkale.util.*;
@@ -20,6 +21,14 @@ public abstract class SncpServlet extends Servlet<SncpContext, SncpRequest, Sncp
public abstract DLong getServiceid();
protected ExecutorService getExecutor() {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
return ((WorkThread) thread).getExecutor();
}
return ForkJoinPool.commonPool();
}
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof SncpServlet)) return false;

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.service;
import java.util.concurrent.*;
import org.redkale.net.WorkThread;
/**
*
* @author zhangjx
*/
public abstract class AbstractService implements Service {
protected void runAsync(Runnable runner) {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
((WorkThread) thread).runAsync(runner);
} else {
ForkJoinPool.commonPool().execute(runner);
}
}
protected ExecutorService getExecutor() {
Thread thread = Thread.currentThread();
if (thread instanceof WorkThread) {
return ((WorkThread) thread).getExecutor();
}
return ForkJoinPool.commonPool();
}
}

View File

@@ -11,6 +11,7 @@ import org.redkale.source.*;
import org.redkale.util.*;
/**
* 实现进程间DataSource的缓存数据同步
*
* <p>
* 详情见: https://redkale.org
@@ -26,20 +27,23 @@ public class DataCacheListenerService implements DataCacheListener, Service {
@Override
@RpcMultiRun(selfrun = false, async = true)
public <T> void insertCache(Class<T> clazz, T... entitys) {
((DataDefaultSource) source).insertCache(clazz, entitys);
public <T> int insertCache(Class<T> clazz, T... entitys) {
if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).insertCache(clazz, entitys);
}
@Override
@RpcMultiRun(selfrun = false, async = true)
public <T> void updateCache(Class<T> clazz, T... entitys) {
((DataDefaultSource) source).updateCache(clazz, entitys);
public <T> int updateCache(Class<T> clazz, T... entitys) {
if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).updateCache(clazz, entitys);
}
@Override
@RpcMultiRun(selfrun = false, async = true)
public <T> void deleteCache(Class<T> clazz, Serializable... ids) {
((DataDefaultSource) source).deleteCache(clazz, ids);
public <T> int deleteCache(Class<T> clazz, Serializable... ids) {
if (!(source instanceof DataCacheListener)) return -2;
return ((DataCacheListener) source).deleteCache(clazz, ids);
}
}

View File

@@ -1,381 +0,0 @@
/*
* 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.service;
import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.function.*;
import javax.annotation.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* DataSource对应的Service类 该类主要特点是将所有含FilterBean参数的方法重载成FilterNode对应的方法。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({DataSourceService.class, DataSource.class})
public class DataSourceService implements DataSource, Service, AutoCloseable {
@Resource(name = "$")
private DataSource source;
@Override
public <T> void insert(@RpcCall(DataCallArrayAttribute.class) T... values) {
source.insert(values);
}
@Override
public <T> int delete(T... values) {
return source.delete(values);
}
@Override
public <T> int delete(final Class<T> clazz, final Serializable... ids) {
return source.delete(clazz, ids);
}
@Override
public <T> int delete(final Class<T> clazz, FilterNode node) {
return source.delete(clazz, node);
}
@Override
public <T> int delete(final Class<T> clazz, final Flipper flipper, FilterNode node) {
return source.delete(clazz, flipper, node);
}
@Override
public <T> int update(T... values) {
return source.update(values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final String column, final Serializable value) {
return source.updateColumn(clazz, id, column, value);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node) {
return source.updateColumn(clazz, column, value, node);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
return source.updateColumn(clazz, id, values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
return source.updateColumn(clazz, node, values);
}
@Override
public <T> int updateColumn(final Class<T> clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) {
return source.updateColumn(clazz, node, flipper, values);
}
@Override
public <T> int updateColumn(T bean, final String... columns) {
return source.updateColumn(bean, columns);
}
@Override
public <T> int updateColumn(T bean, final FilterNode node, final String... columns) {
return source.updateColumn(bean, node, columns);
}
@Override
public <T> int updateColumn(T bean, final SelectColumn selects) {
return source.updateColumn(bean, selects);
}
@Override
public <T> int updateColumn(T bean, final FilterNode node, final SelectColumn selects) {
return source.updateColumn(bean, node, selects);
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column) {
return source.getNumberResult(entityClass, func, column);
}
@Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, column, node);
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column) {
return source.getNumberResult(entityClass, func, defVal, column);
}
@Override
public final Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterBean bean) {
return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean));
}
@Override
public Number getNumberResult(final Class entityClass, FilterFunc func, final Number defVal, final String column, FilterNode node) {
return source.getNumberResult(entityClass, func, defVal, column, node);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, columns);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, bean, columns);
}
@Override
public <N extends Number> Map<String, N> getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) {
return source.getNumberMap(entityClass, node, columns);
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn);
}
@Override
public final <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterBean bean) {
return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, K extends Serializable, N extends Number> Map<K, N> queryColumnMap(final Class<T> entityClass, final String keyColumn, FilterFunc func, final String funcColumn, FilterNode node) {
return source.queryColumnMap(entityClass, keyColumn, func, funcColumn, node);
}
@Override
public <T> T find(final Class<T> clazz, final Serializable pk) {
return source.find(clazz, pk);
}
@Override
public <T> T find(final Class<T> clazz, SelectColumn selects, final Serializable pk) {
return source.find(clazz, selects, pk);
}
@Override
public <T> T find(final Class<T> clazz, final String column, final Serializable key) {
return source.find(clazz, column, key);
}
@Override
public final <T> T find(final Class<T> clazz, FilterBean bean) {
return find(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> T find(final Class<T> clazz, FilterNode node) {
return source.find(clazz, node);
}
@Override
public final <T> T find(final Class<T> clazz, final SelectColumn selects, FilterBean bean) {
return find(clazz, selects, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> T find(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.find(clazz, selects, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable pk) {
return source.findColumn(clazz, column, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterBean bean) {
return source.findColumn(clazz, column, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final FilterNode node) {
return source.findColumn(clazz, column, node);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final Serializable pk) {
return source.findColumn(clazz, column, defValue, pk);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterBean bean) {
return source.findColumn(clazz, column, defValue, bean);
}
@Override
public <T> Serializable findColumn(final Class<T> clazz, final String column, final Serializable defValue, final FilterNode node) {
return source.findColumn(clazz, column, defValue, node);
}
@Override
public <T> boolean exists(final Class<T> clazz, final Serializable pk) {
return source.exists(clazz, pk);
}
@Override
public final <T> boolean exists(final Class<T> clazz, FilterBean bean) {
return exists(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> boolean exists(final Class<T> clazz, FilterNode node) {
return source.exists(clazz, node);
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnSet(selectedColumn, clazz, column, key);
}
@Override
public final <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> HashSet<V> queryColumnSet(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnSet(selectedColumn, clazz, node);
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, final String column, final Serializable key) {
return source.queryColumnList(selectedColumn, clazz, column, key);
}
@Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, node);
}
@Override
public final <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> List<V> queryColumnList(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnList(selectedColumn, clazz, flipper, node);
}
@Override
public final <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterBean bean) {
return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T, V extends Serializable> Sheet<V> queryColumnSheet(String selectedColumn, Class<T> clazz, Flipper flipper, FilterNode node) {
return source.queryColumnSheet(selectedColumn, clazz, flipper, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final String column, final Serializable key) {
return source.queryList(clazz, column, key);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final FilterNode node) {
return source.queryList(clazz, node);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterBean bean) {
return queryList(clazz, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final FilterNode node) {
return source.queryList(clazz, selects, node);
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final String column, final Serializable key) {
return source.queryList(clazz, flipper, column, key);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, flipper, node);
}
@Override
public final <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> List<T> queryList(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.queryList(clazz, selects, flipper, node);
}
@Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, flipper, node);
}
@Override
public final <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) {
return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean));
}
@Override
public <T> Sheet<T> querySheet(final Class<T> clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return source.querySheet(clazz, selects, flipper, node);
}
@Override
public void close() throws Exception {
source.getClass().getMethod("close").invoke(source);
}
@Override
public final void directQuery(String sql, Consumer<ResultSet> consumer) {
source.directQuery(sql, consumer);
}
@Override
public final int[] directExecute(String... sqls) {
return source.directExecute(sqls);
}
}

View File

@@ -7,6 +7,7 @@ package org.redkale.service;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import java.util.*;
/**
@@ -28,6 +29,39 @@ public @interface RetLabel {
String value();
public static abstract class AbstractRetCode {
protected static final Map<Integer, String> rets = new HashMap();
protected static void load(Class clazz) {
rets.putAll(RetLoader.load(clazz));
}
public static RetResult retResult(int retcode) {
if (retcode == 0) return RetResult.success();
return new RetResult(retcode, retInfo(retcode));
}
public static RetResult retResult(int retcode, Object... args) {
if (retcode == 0) return RetResult.success();
if (args == null || args.length < 1) return new RetResult(retcode, retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return new RetResult(retcode, info);
}
public static RetResult set(RetResult result, int retcode, Object... args) {
if (retcode == 0) return result.retcode(0).retinfo("");
if (args == null || args.length < 1) return result.retcode(retcode).retinfo(retInfo(retcode));
String info = MessageFormat.format(retInfo(retcode), args);
return result.retcode(retcode).retinfo(info);
}
public static String retInfo(int retcode) {
if (retcode == 0) return "成功";
return rets.getOrDefault(retcode, "未知错误");
}
}
public static abstract class RetLoader {
public static Map<Integer, String> load(Class clazz) {

View File

@@ -0,0 +1,26 @@
/*
* 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.service;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* SNCP协议中用于CompletionHandler回调函数中的attach字段。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({PARAMETER})
@Retention(RUNTIME)
public @interface RpcAttachment {
}

View File

@@ -8,8 +8,8 @@ package org.redkale.service;
import org.redkale.util.*;
/**
* 所有Service的实现类不得声明为final 允许远程模式的public方法都不能声明为final。
* 注意: "$"是一个很特殊的Service.name值 。 被标记为@Resource(name = "$") 的Service的资源名与所属父Service的资源名一致。
* 所有Service的实现类不得声明为final 允许远程模式的public方法都不能声明为final。<br>
* 注意: "$"是一个很特殊的Service.name值 。 被标记为&#64;Resource(name = "$") 的Service的资源名与所属父Service的资源名一致。<br>
*
* <blockquote><pre>
* Service的资源类型
@@ -19,6 +19,16 @@ import org.redkale.util.*;
* 第二种方式需要在具体实现类上使用&#64;ResourceType指明资源注入的类型。
* </pre></blockquote>
*
* <blockquote><pre>
* 异步方法:
* Service编写异步方法
* 1、异步方法有且仅有一个类型为AsyncHandler的参数。若参数类型为AsyncHandler子类必须保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
* 2、异步方法返回类型必须是void。
* 例如:
* public void insertRecord(AsyncHandler&#60;Integer, Record&#62; handler, String name, &#64;RpcAttachment Record record);
*
* </pre></blockquote>
*
* <p>
* 详情见: https://redkale.org
*
@@ -46,14 +56,4 @@ public interface Service {
}
/**
* Service的接口版本号
* <b>注: public方法的参数或返回类型或参数类型内部变更后改值必须进行改变</b>
*
* @return 接口版本号
*/
default int version() {
return 0;
}
}

View File

@@ -49,7 +49,7 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
}
@Override
public int sendMessage(@RpcTargetAddress InetSocketAddress addr, Serializable groupid, boolean recent, Serializable message, boolean last) {
public int sendMessage(@RpcTargetAddress InetSocketAddress addr, Serializable groupid, boolean recent, Object message, boolean last) {
final Set<String> engineids = localNodes.get(groupid);
if (engineids == null || engineids.isEmpty()) return RETCODE_GROUP_EMPTY;
int code = RETCODE_GROUP_EMPTY;
@@ -70,13 +70,13 @@ public class WebSocketNodeService extends WebSocketNode implements Service {
@Override
public void connect(Serializable groupid, InetSocketAddress addr) {
source.appendSetItem(groupid, addr);
sncpNodes.appendSetItem(groupid, addr);
if (finest) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + groupid + " connect from " + addr);
}
@Override
public void disconnect(Serializable groupid, InetSocketAddress addr) {
source.removeSetItem(groupid, addr);
sncpNodes.removeSetItem(groupid, addr);
if (finest) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + groupid + " disconnect from " + addr);
}
}

View File

@@ -3,23 +3,24 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.service;
package org.redkale.source;
import java.beans.*;
import java.beans.ConstructorProperties;
import java.io.*;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.function.Consumer;
import java.util.logging.*;
import javax.annotation.*;
import org.redkale.convert.*;
import javax.annotation.Resource;
import org.redkale.convert.ConvertColumn;
import org.redkale.convert.json.*;
import org.redkale.net.sncp.*;
import org.redkale.source.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.util.*;
/**
* CacheSource的默认实现--内存缓存
*
* @param <K> key类型
* @param <V> value类型
@@ -28,9 +29,10 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
@LocalService
@AutoLoad(false)
@ResourceType({CacheSourceService.class, CacheSource.class})
public class CacheSourceService<K extends Serializable, V extends Object> implements CacheSource<K, V>, Service, AutoCloseable {
@ResourceType({CacheSource.class})
public class CacheMemorySource<K extends Serializable, V extends Object> extends AbstractService implements CacheSource<K, V>, Service, AutoCloseable, Resourcable {
@Resource(name = "APP_HOME")
private File home;
@@ -56,10 +58,10 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
protected final ConcurrentHashMap<K, CacheEntry<K, ?>> container = new ConcurrentHashMap<>();
public CacheSourceService() {
public CacheMemorySource() {
}
public final CacheSourceService setStoreType(Class keyType, Class valueType) {
public final CacheMemorySource setStoreType(Class keyType, Class valueType) {
this.keyType = keyType;
this.objValueType = valueType;
this.setValueType = TypeToken.createParameterizedType(null, CopyOnWriteArraySet.class, valueType);
@@ -74,7 +76,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
@Override
public void init(AnyValue conf) {
final CacheSourceService self = this;
final CacheMemorySource self = this;
AnyValue prop = conf == null ? null : conf.getAnyValue("property");
if (keyType == null && prop != null) {
String storeKeyStr = prop.getValue("key-type");
@@ -82,7 +84,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
if (storeKeyStr != null && storeValueStr != null) {
try {
this.setStoreType(Class.forName(storeKeyStr), Class.forName(storeValueStr));
} catch (Exception e) {
} catch (Throwable e) {
logger.log(Level.SEVERE, self.getClass().getSimpleName() + " load key & value store class (" + storeKeyStr + ", " + storeValueStr + ") error", e);
}
}
@@ -92,7 +94,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
if (expireHandlerClass != null) {
try {
this.expireHandler = (Consumer<CacheEntry>) Class.forName(expireHandlerClass).newInstance();
} catch (Exception e) {
} catch (Throwable e) {
logger.log(Level.SEVERE, self.getClass().getSimpleName() + " new expirehandler class (" + expireHandlerClass + ") instance error", e);
}
}
@@ -116,7 +118,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
if (expireHandler != null && entry != null) expireHandler.accept(entry);
}
}, 10, 10, TimeUnit.SECONDS);
logger.finest(self.getClass().getSimpleName() + ":" + self.name() + " start schedule expire executor");
logger.finest(self.getClass().getSimpleName() + ":" + self.resourceName() + " start schedule expire executor");
}
if (Sncp.isRemote(self)) return;
@@ -125,7 +127,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
// TODO
if (!this.needStore) return;
try {
File store = new File(home, "cache/" + name());
File store = new File(home, "cache/" + resourceName());
if (!store.isFile() || !store.canRead()) return;
LineNumberReader reader = new LineNumberReader(new FileReader(store));
if (this.keyType == null) this.keyType = Serializable.class;
@@ -148,7 +150,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
reader.close();
store.delete();
} catch (Exception e) {
logger.log(Level.SEVERE, CacheSource.class.getSimpleName() + "(" + name() + ") load store file error ", e);
logger.log(Level.SEVERE, CacheSource.class.getSimpleName() + "(" + resourceName() + ") load store file error ", e);
}
}
@@ -157,8 +159,10 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
destroy(null);
}
public String name() {
return this.getClass().getAnnotation(Resource.class).name();
@Override
public String resourceName() {
Resource res = this.getClass().getAnnotation(Resource.class);
return res == null ? null : res.name();
}
@Override
@@ -166,7 +170,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
if (scheduler != null) scheduler.shutdownNow();
if (!this.needStore || Sncp.isRemote(this) || container.isEmpty()) return;
try {
File store = new File(home, "cache/" + name());
File store = new File(home, "cache/" + resourceName());
store.getParentFile().mkdirs();
PrintStream stream = new PrintStream(store, "UTF-8");
final Type storeObjType = TypeToken.createParameterizedType(null, CacheEntry.class, keyType, objValueType);
@@ -179,7 +183,7 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
container.clear();
stream.close();
} catch (Exception e) {
logger.log(Level.SEVERE, CacheSource.class.getSimpleName() + "(" + name() + ") store to file error ", e);
logger.log(Level.SEVERE, CacheSource.class.getSimpleName() + "(" + resourceName() + ") store to file error ", e);
}
}
@@ -191,6 +195,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return !entry.isExpired();
}
@Override
public CompletableFuture<Boolean> existsAsync(final K key) {
return CompletableFuture.supplyAsync(() -> exists(key), getExecutor());
}
@Override
public void existsAsync(final AsyncHandler<Boolean, K> handler, @RpcAttachment final K key) {
super.runAsync(() -> {
try {
boolean rs = exists(key);
if (handler != null) handler.completed(rs, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
public V get(K key) {
if (key == null) return null;
@@ -201,6 +222,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return (V) entry.getValue();
}
@Override
public CompletableFuture<V> getAsync(final K key) {
return CompletableFuture.supplyAsync(() -> get(key), getExecutor());
}
@Override
public void getAsync(final AsyncHandler<V, K> handler, @RpcAttachment final K key) {
super.runAsync(() -> {
try {
V rs = get(key);
if (handler != null) handler.completed(rs, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public V getAndRefresh(K key, final int expireSeconds) {
@@ -214,6 +252,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
return (V) entry.getValue();
}
@Override
public CompletableFuture<V> getAndRefreshAsync(final K key, final int expireSeconds) {
return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds), getExecutor());
}
@Override
public void getAndRefreshAsync(final AsyncHandler<V, K> handler, @RpcAttachment final K key, final int expireSeconds) {
super.runAsync(() -> {
try {
V rs = getAndRefresh(key, expireSeconds);
if (handler != null) handler.completed(rs, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void refresh(K key, final int expireSeconds) {
@@ -224,6 +279,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
entry.expireSeconds = expireSeconds;
}
@Override
public CompletableFuture<Void> refreshAsync(final K key, final int expireSeconds) {
return CompletableFuture.runAsync(() -> refresh(key, expireSeconds), getExecutor());
}
@Override
public void refreshAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final int expireSeconds) {
super.runAsync(() -> {
try {
refresh(key, expireSeconds);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void set(K key, V value) {
@@ -239,6 +311,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
}
}
@Override
public CompletableFuture<Void> setAsync(K key, V value) {
return CompletableFuture.runAsync(() -> set(key, value), getExecutor());
}
@Override
public void setAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
set(key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void set(int expireSeconds, K key, V value) {
@@ -254,6 +343,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
}
}
@Override
public CompletableFuture<Void> setAsync(int expireSeconds, K key, V value) {
return CompletableFuture.runAsync(() -> set(expireSeconds, key, value), getExecutor());
}
@Override
public void setAsync(final AsyncHandler<Void, K> handler, final int expireSeconds, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
set(expireSeconds, key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void setExpireSeconds(K key, int expireSeconds) {
@@ -263,6 +369,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
entry.expireSeconds = expireSeconds;
}
@Override
public CompletableFuture<Void> setExpireSecondsAsync(final K key, final int expireSeconds) {
return CompletableFuture.runAsync(() -> setExpireSeconds(key, expireSeconds), getExecutor());
}
@Override
public void setExpireSecondsAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final int expireSeconds) {
super.runAsync(() -> {
try {
setExpireSeconds(key, expireSeconds);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void remove(K key) {
@@ -270,16 +393,67 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
container.remove(key);
}
@Override
public CompletableFuture<Void> removeAsync(final K key) {
return CompletableFuture.runAsync(() -> remove(key), getExecutor());
}
@Override
public void removeAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key) {
super.runAsync(() -> {
try {
remove(key);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
public Collection<V> getCollection(final K key) {
return (Collection<V>) get(key);
}
@Override
public CompletableFuture<Collection<V>> getCollectionAsync(final K key) {
return CompletableFuture.supplyAsync(() -> getCollection(key), getExecutor());
}
@Override
public void getCollectionAsync(final AsyncHandler<Collection<V>, K> handler, @RpcAttachment final K key) {
super.runAsync(() -> {
try {
Collection<V> rs = getCollection(key);
if (handler != null) handler.completed(rs, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
public Collection<V> getCollectionAndRefresh(final K key, final int expireSeconds) {
return (Collection<V>) getAndRefresh(key, expireSeconds);
}
@Override
public CompletableFuture<Collection<V>> getCollectionAndRefreshAsync(final K key, final int expireSeconds) {
return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds), getExecutor());
}
@Override
public void getCollectionAndRefreshAsync(final AsyncHandler<Collection<V>, K> handler, @RpcAttachment final K key, final int expireSeconds) {
super.runAsync(() -> {
try {
Collection<V> rs = getCollectionAndRefresh(key, expireSeconds);
if (handler != null) handler.completed(rs, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void appendListItem(K key, V value) {
@@ -296,6 +470,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
}
}
@Override
public CompletableFuture<Void> appendListItemAsync(final K key, final V value) {
return CompletableFuture.runAsync(() -> appendListItem(key, value), getExecutor());
}
@Override
public void appendListItemAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
appendListItem(key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void removeListItem(K key, V value) {
@@ -305,6 +496,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
((Collection) entry.getValue()).remove(value);
}
@Override
public CompletableFuture<Void> removeListItemAsync(final K key, final V value) {
return CompletableFuture.runAsync(() -> removeListItem(key, value), getExecutor());
}
@Override
public void removeListItemAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
removeListItem(key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void appendSetItem(K key, V value) {
@@ -321,6 +529,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
}
}
@Override
public CompletableFuture<Void> appendSetItemAsync(final K key, final V value) {
return CompletableFuture.runAsync(() -> appendSetItem(key, value), getExecutor());
}
@Override
public void appendSetItemAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
appendSetItem(key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
@Override
@RpcMultiRun
public void removeSetItem(K key, V value) {
@@ -330,6 +555,23 @@ public class CacheSourceService<K extends Serializable, V extends Object> implem
((Set) entry.getValue()).remove(value);
}
@Override
public CompletableFuture<Void> removeSetItemAsync(final K key, final V value) {
return CompletableFuture.runAsync(() -> removeSetItem(key, value), getExecutor());
}
@Override
public void removeSetItemAsync(final AsyncHandler<Void, K> handler, @RpcAttachment final K key, final V value) {
super.runAsync(() -> {
try {
removeSetItem(key, value);
if (handler != null) handler.completed(null, key);
} catch (Throwable t) {
if (handler != null) handler.failed(t, key);
}
});
}
public static enum CacheEntryType {
OBJECT, SET, LIST;
}

View File

@@ -7,6 +7,8 @@ package org.redkale.source;
import java.io.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import org.redkale.util.*;
/**
*
@@ -51,4 +53,84 @@ public interface CacheSource<K extends Serializable, V extends Object> {
public void removeSetItem(final K key, final V value);
//---------------------- CompletableFuture 异步版 ---------------------------------
public CompletableFuture<Boolean> existsAsync(final K key);
public CompletableFuture<V> getAsync(final K key);
public CompletableFuture<V> getAndRefreshAsync(final K key, final int expireSeconds);
public CompletableFuture<Void> refreshAsync(final K key, final int expireSeconds);
public CompletableFuture<Void> setAsync(final K key, final V value);
public CompletableFuture<Void> setAsync(final int expireSeconds, final K key, final V value);
public CompletableFuture<Void> setExpireSecondsAsync(final K key, final int expireSeconds);
public CompletableFuture<Void> removeAsync(final K key);
public CompletableFuture<Collection<V>> getCollectionAsync(final K key);
public CompletableFuture<Collection<V>> getCollectionAndRefreshAsync(final K key, final int expireSeconds);
public CompletableFuture<Void> appendListItemAsync(final K key, final V value);
public CompletableFuture<Void> removeListItemAsync(final K key, final V value);
public CompletableFuture<Void> appendSetItemAsync(final K key, final V value);
public CompletableFuture<Void> removeSetItemAsync(final K key, final V value);
default CompletableFuture<Boolean> isOpenAsync() {
return CompletableFuture.completedFuture(true);
}
//---------------------- AsyncHandler 异步版 ---------------------------------
@Deprecated
public void existsAsync(final AsyncHandler<Boolean, K> handler, final K key);
@Deprecated
public void getAsync(final AsyncHandler<V, K> handler, final K key);
@Deprecated
public void getAndRefreshAsync(final AsyncHandler<V, K> handler, final K key, final int expireSeconds);
@Deprecated
public void refreshAsync(final AsyncHandler<Void, K> handler, final K key, final int expireSeconds);
@Deprecated
public void setAsync(final AsyncHandler<Void, K> handler, final K key, final V value);
@Deprecated
public void setAsync(final AsyncHandler<Void, K> handler, final int expireSeconds, final K key, final V value);
@Deprecated
public void setExpireSecondsAsync(final AsyncHandler<Void, K> handler, final K key, final int expireSeconds);
@Deprecated
public void removeAsync(final AsyncHandler<Void, K> handler, final K key);
@Deprecated
public void getCollectionAsync(final AsyncHandler<Collection<V>, K> handler, final K key);
@Deprecated
public void getCollectionAndRefreshAsync(final AsyncHandler<Collection<V>, K> handler, final K key, final int expireSeconds);
@Deprecated
public void appendListItemAsync(final AsyncHandler<Void, K> handler, final K key, final V value);
@Deprecated
public void removeListItemAsync(final AsyncHandler<Void, K> handler, final K key, final V value);
@Deprecated
public void appendSetItemAsync(final AsyncHandler<Void, K> handler, final K key, final V value);
@Deprecated
public void removeSetItemAsync(final AsyncHandler<Void, K> handler, final K key, final V value);
@Deprecated
default void isOpenAsync(final AsyncHandler<Boolean, Void> handler) {
if (handler != null) handler.completed(Boolean.TRUE, null);
}
}

View File

@@ -9,14 +9,16 @@ import java.io.Serializable;
/**
*
* <p> 详情见: https://redkale.org
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface DataCacheListener {
public <T> void insertCache(Class<T> clazz, T... entitys);
public <T> int insertCache(Class<T> clazz, T... entitys);
public <T> void updateCache(Class<T> clazz, T... entitys);
public <T> int updateCache(Class<T> clazz, T... entitys);
public <T> void deleteCache(Class<T> clazz, Serializable... ids);
public <T> int deleteCache(Class<T> clazz, Serializable... ids);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
/*
* 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.source;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.*;
import javax.xml.stream.*;
/**
*
* @author zhangjx
*/
public final class DataSources {
public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH";
public static final String JDBC_DATASOURCE_CLASS = "javax.persistence.datasource";
public static final String JDBC_CONNECTIONSMAX = "javax.persistence.connections.limit";
public static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate";
public static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
public static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates";
public static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
public static final String JDBC_URL = "javax.persistence.jdbc.url";
public static final String JDBC_USER = "javax.persistence.jdbc.user";
public static final String JDBC_PWD = "javax.persistence.jdbc.password";
public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
public static final String JDBC_SOURCE = "javax.persistence.jdbc.source";
private DataSources() {
}
public static DataSource createDataSource(final String unitName) throws IOException {
return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH) == null
? DataJdbcSource.class.getResource("/META-INF/persistence.xml")
: new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL());
}
public static DataSource createDataSource(final String unitName, URL url) throws IOException {
if (url == null) url = DataSources.class.getResource("/persistence.xml");
InputStream in = url.openStream();
if (in == null) return null;
Map<String, Properties> map = loadPersistenceXml(in);
Properties readprop = null;
Properties writeprop = null;
if (unitName != null) {
readprop = map.get(unitName);
writeprop = readprop;
if (readprop == null) {
readprop = map.get(unitName + ".read");
writeprop = map.get(unitName + ".write");
}
}
if ((unitName == null || unitName.isEmpty()) || readprop == null) {
String key = null;
for (Map.Entry<String, Properties> en : map.entrySet()) {
key = en.getKey();
readprop = en.getValue();
writeprop = readprop;
break;
}
if (key != null && (key.endsWith(".read") || key.endsWith(".write"))) {
if (key.endsWith(".read")) {
writeprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".write");
} else {
readprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".read");
}
}
}
if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource");
String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName());
if (DataJdbcSource.class.getName().equals(impl)) return new DataJdbcSource(unitName, readprop, writeprop);
try {
Class ds = Class.forName(impl);
for (Constructor d : ds.getConstructors()) {
Class<?>[] paramtypes = d.getParameterTypes();
if (paramtypes.length == 1 && paramtypes[0] == Properties.class) {
return (DataSource) d.newInstance(readprop);
} else if (paramtypes.length == 2 && paramtypes[0] == String.class && paramtypes[1] == Properties.class) {
return (DataSource) d.newInstance(unitName, readprop);
} else if (paramtypes.length == 3 && paramtypes[0] == String.class && paramtypes[1] == Properties.class && paramtypes[2] == Properties.class) {
return (DataSource) d.newInstance(unitName, readprop, writeprop);
}
}
throw new IOException("DataSource impl class (" + impl + ") have no Constructor by (Properties prop) or (String name, Properties prop) or (String name, Properties readprop, Propertieswriteprop)");
} catch (IOException ex) {
throw ex;
} catch (Exception e) {
throw new IOException(e);
}
}
static Map<String, Properties> loadPersistenceXml(final InputStream in0) {
final Map<String, Properties> map = new LinkedHashMap();
Properties result = new Properties();
boolean flag = false;
try (final InputStream in = in0) {
XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(in);
while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if ("persistence-unit".equalsIgnoreCase(reader.getLocalName())) {
if (!result.isEmpty()) result = new Properties();
map.put(reader.getAttributeValue(null, "name"), result);
flag = true;
} else if (flag && "property".equalsIgnoreCase(reader.getLocalName())) {
String name = reader.getAttributeValue(null, "name");
String value = reader.getAttributeValue(null, "value");
if (name == null) continue;
result.put(name, value);
} else if (flag && "shared-cache-mode".equalsIgnoreCase(reader.getLocalName())) {
result.put(reader.getLocalName(), reader.getElementText());
}
}
}
in.close();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return map;
}
}

View File

@@ -425,14 +425,16 @@ public final class EntityCache<T> {
return new Sheet<>(total, rs);
}
public void insert(T value) {
if (value == null) return;
public int insert(T value) {
if (value == null) return 0;
final T rs = newReproduce.apply(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
T old = this.map.put(this.primary.get(rs), rs);
if (old == null) {
this.list.add(rs);
return 1;
} else {
logger.log(Level.WARNING, this.type + " cache repeat insert data: " + value);
return 0;
}
}

View File

@@ -264,6 +264,7 @@ public final class EntityInfo<T> {
attributeMap.put(fieldname, attr);
}
} while ((cltmp = cltmp.getSuperclass()) != Object.class);
if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id");
this.primary = idAttr0;
this.aliasmap = aliasmap0;
this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]);
@@ -304,11 +305,11 @@ public final class EntityInfo<T> {
this.cache = null;
}
if (conf == null) conf = new Properties();
this.containSQL = conf.getProperty(JDBCPoolSource.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
this.notcontainSQL = conf.getProperty(JDBCPoolSource.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
this.containSQL = conf.getProperty(DataSources.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0");
this.notcontainSQL = conf.getProperty(DataSources.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0");
this.tablenotexistSqlstates = ";" + conf.getProperty(JDBCPoolSource.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";";
this.tablecopySQL = conf.getProperty(JDBCPoolSource.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
this.tablenotexistSqlstates = ";" + conf.getProperty(DataSources.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";";
this.tablecopySQL = conf.getProperty(DataSources.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} LIKE ${oldtable}");
}
/**
@@ -659,6 +660,8 @@ public final class EntityInfo<T> {
o = ((Number) o).byteValue();
} else if (t == char.class) {
o = (char) ((Number) o).intValue();
} else if (t == boolean.class) {
o = (Boolean) o;
}
} else if (t == int.class) {
o = 0;

View File

@@ -280,6 +280,7 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
}
private static boolean needSplit(final FilterExpress express, final Object val0) {
if(val0 == null) return false;
boolean items = express != IN && express != NOTIN; //是否数组集合的表达式
if (!items) {
if (val0.getClass().isArray()) {
@@ -1709,7 +1710,7 @@ public class FilterNode { //FilterNode 不能实现Serializable接口 否则
protected StringBuilder toString(final String prefix) {
StringBuilder sb = new StringBuilder();
StringBuilder element = toElementString(prefix);
boolean more = element.length() > 0 && this.nodes != null;
boolean more = element != null && element.length() > 0 && this.nodes != null;
if (more) sb.append('(');
sb.append(element);
if (this.nodes != null) {

View File

@@ -5,7 +5,6 @@
*/
package org.redkale.source;
import static org.redkale.source.DataDefaultSource.*;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
@@ -17,6 +16,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import javax.sql.*;
import static org.redkale.source.DataSources.*;
/**
*
@@ -25,29 +25,9 @@ import javax.sql.*;
*
* @author zhangjx
*/
public class JDBCPoolSource {
public class PoolJdbcSource {
static final String JDBC_CONNECTIONSMAX = "javax.persistence.connections.limit";
static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate";
static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate";
static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates";
static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate";
static final String JDBC_URL = "javax.persistence.jdbc.url";
static final String JDBC_USER = "javax.persistence.jdbc.user";
static final String JDBC_PWD = "javax.persistence.jdbc.password";
static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
static final String JDBC_SOURCE = "javax.persistence.jdbc.source";
private static final Map<String, AbstractMap.SimpleEntry<WatchService, List<WeakReference<JDBCPoolSource>>>> maps = new HashMap<>();
private static final Map<String, AbstractMap.SimpleEntry<WatchService, List<WeakReference<PoolJdbcSource>>>> maps = new HashMap<>();
private final AtomicLong usingCounter = new AtomicLong();
@@ -63,7 +43,7 @@ public class JDBCPoolSource {
private final ConnectionEventListener listener;
private final DataDefaultSource dataSource;
private final DataJdbcSource dataSource;
private final String stype; // "" "read" "write"
@@ -77,7 +57,7 @@ public class JDBCPoolSource {
final Properties props;
public JDBCPoolSource(DataDefaultSource source, String stype, Properties prop) {
public PoolJdbcSource(DataJdbcSource source, String stype, Properties prop) {
this.dataSource = source;
this.stype = stype;
this.props = prop;
@@ -151,7 +131,7 @@ public class JDBCPoolSource {
try {
Class.forName("com.mysql.cj.jdbc.MysqlConnectionPoolDataSource");
source = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource";
} catch (Exception e) {
} catch (Throwable e) {
source = "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource";
}
break;
@@ -210,13 +190,13 @@ public class JDBCPoolSource {
final File f = new File(file);
if (!f.isFile() || !f.canRead()) return;
synchronized (maps) {
AbstractMap.SimpleEntry<WatchService, List<WeakReference<JDBCPoolSource>>> entry = maps.get(file);
AbstractMap.SimpleEntry<WatchService, List<WeakReference<PoolJdbcSource>>> entry = maps.get(file);
if (entry != null) {
entry.getValue().add(new WeakReference<>(this));
return;
}
final WatchService watcher = f.toPath().getFileSystem().newWatchService();
final List<WeakReference<JDBCPoolSource>> list = new CopyOnWriteArrayList<>();
final List<WeakReference<PoolJdbcSource>> list = new CopyOnWriteArrayList<>();
Thread watchThread = new Thread() {
@Override
@@ -230,12 +210,12 @@ public class JDBCPoolSource {
Thread.sleep(2000L);
if (d == f.lastModified()) break;
}
final Map<String, Properties> m = loadProperties(new FileInputStream(file));
final Map<String, Properties> m = loadPersistenceXml(new FileInputStream(file));
key.pollEvents().stream().forEach((event) -> {
if (event.kind() != ENTRY_MODIFY) return;
if (!((Path) event.context()).toFile().getName().equals(f.getName())) return;
for (WeakReference<JDBCPoolSource> ref : list) {
JDBCPoolSource pool = ref.get();
for (WeakReference<PoolJdbcSource> ref : list) {
PoolJdbcSource pool = ref.get();
if (pool == null) continue;
try {
Properties property = m.get(pool.dataSource.name);

View File

@@ -56,6 +56,20 @@ public abstract class AnyValue {
return new DefaultAnyValue();
}
/**
* 创建含name-value值的DefaultAnyValue对象
*
* @param name name
* @param value value值
*
* @return DefaultAnyValue对象
*/
public static final DefaultAnyValue create(String name, Number value) {
DefaultAnyValue conf = new DefaultAnyValue();
conf.addValue(name, value);
return conf;
}
/**
* 创建含name-value值的DefaultAnyValue对象
*

View File

@@ -0,0 +1,95 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.util;
import java.util.function.BiConsumer;
import java.nio.channels.CompletionHandler;
import java.util.function.*;
/**
* 异步回调函数
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @param <V> 结果对象的泛型
* @param <A> 附件对象的泛型
*/
public interface AsyncHandler<V, A> extends CompletionHandler<V, A> {
/**
* 创建 AsyncHandler 对象
*
* @param <V> 结果对象的泛型
* @param <A> 附件对象的泛型
* @param success 成功的回调函数
* @param fail 失败的回调函数
*
* @return AsyncHandler
*/
public static <V, A> AsyncHandler<V, A> create(final BiConsumer<V, A> success, final BiConsumer<Throwable, A> fail) {
return new AsyncHandler<V, A>() {
@Override
public void completed(V result, A attachment) {
if (success != null) success.accept(result, attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
if (fail != null) fail.accept(exc, attachment);
}
};
}
/**
* 创建没有返回结果的 AsyncHandler 对象
*
* @param <A> 附件对象的泛型
* @param success 成功的回调函数
* @param fail 失败的回调函数
*
* @return AsyncHandler
*/
public static <A> AsyncHandler<Void, A> create(final Consumer<A> success, final BiConsumer<Throwable, A> fail) {
return new AsyncHandler<Void, A>() {
@Override
public void completed(Void result, A attachment) {
if (success != null) success.accept(attachment);
}
@Override
public void failed(Throwable exc, A attachment) {
if (fail != null) fail.accept(exc, attachment);
}
};
}
/**
* 创建没有附件对象的 AsyncNoResultHandler 对象
*
* @param <V> 结果对象的泛型
* @param success 成功的回调函数
* @param fail 失败的回调函数
*
* @return AsyncHandler
*/
public static <V> AsyncHandler<V, Void> create(final Consumer<V> success, final Consumer<Throwable> fail) {
return new AsyncHandler<V, Void>() {
@Override
public void completed(V result, Void attachment) {
if (success != null) success.accept(result);
}
@Override
public void failed(Throwable exc, Void attachment) {
if (fail != null) fail.accept(exc);
}
};
}
}

View File

@@ -19,7 +19,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
@Inherited
@Documented
@Target({TYPE, METHOD, FIELD, PARAMETER})
@Target({TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER})
@Retention(RUNTIME)
public @interface Comment {

View File

@@ -12,6 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import jdk.internal.org.objectweb.asm.*;
import jdk.internal.org.objectweb.asm.Type;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
@@ -80,12 +81,101 @@ public interface Creator<T> {
public static @interface ConstructorParameters {
String[] value();
static class CreatorInner {
static class SimpleClassVisitor extends ClassVisitor {
private final String constructorDesc;
private final List<String> fieldnames;
private boolean started;
public SimpleClassVisitor(int api, List<String> fieldnames, String constructorDesc) {
super(api);
this.fieldnames = fieldnames;
this.constructorDesc = constructorDesc;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (java.lang.reflect.Modifier.isStatic(access) || !"<init>".equals(name)) return null;
if (constructorDesc != null && !constructorDesc.equals(desc)) return null;
if (this.started) return null;
this.started = true;
//返回的List中参数列表可能会比方法参数量多因为方法内的临时变量也会存入list中 所以需要list的元素集合比方法的参数多
return new MethodVisitor(Opcodes.ASM5) {
@Override
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
if (index > 0) fieldnames.add(name);
}
};
}
}
public static SimpleEntry<String, Class>[] getConstructorField(Class clazz, int paramcount, String constructorDesc) {
String n = clazz.getName();
InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class");
if (in == null) return null;
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
byte[] bytes = new byte[1024];
int pos;
try {
while ((pos = in.read(bytes)) != -1) {
out.write(bytes, 0, pos);
}
in.close();
} catch (IOException io) {
return null;
}
final List<String> fieldnames = new ArrayList<>();
new ClassReader(out.toByteArray()).accept(new SimpleClassVisitor(Opcodes.ASM5, fieldnames, constructorDesc), 0);
if (fieldnames.isEmpty()) return null;
if (paramcount == fieldnames.size()) {
return getConstructorField(clazz, paramcount, fieldnames.toArray(new String[fieldnames.size()]));
} else {
String[] fs = new String[paramcount];
for (int i = 0; i < fs.length; i++) {
fs[i] = fieldnames.get(i);
}
return getConstructorField(clazz, paramcount, fs);
}
}
public static SimpleEntry<String, Class>[] getConstructorField(Class clazz, int paramcount, String[] names) {
SimpleEntry<String, Class>[] se = new SimpleEntry[names.length];
for (int i = 0; i < names.length; i++) { //查询参数名对应的Field
try {
Field field = clazz.getDeclaredField(names[i]);
se[i] = new SimpleEntry<>(field.getName(), field.getType());
} catch (Exception e) {
return null;
}
}
return se;
}
public static SimpleEntry<String, Class>[] getConstructorField(Class clazz, int paramcount, Parameter[] params) {
SimpleEntry<String, Class>[] se = new SimpleEntry[params.length];
for (int i = 0; i < params.length; i++) { //查询参数名对应的Field
try {
Field field = clazz.getDeclaredField(params[i].getName());
se[i] = new SimpleEntry<>(field.getName(), field.getType());
} catch (Exception e) {
return null;
}
}
return se;
}
}
}
/**
* 创建对象
*
* @param params 构造函数的参数
*
* @return 构建的对象
*/
public T create(Object... params);
@@ -95,6 +185,7 @@ public interface Creator<T> {
*
* @param <T> 构建类的数据类型
* @param clazz 构建类
*
* @return Creator对象
*/
@SuppressWarnings("unchecked")
@@ -109,7 +200,7 @@ public interface Creator<T> {
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
throw new RuntimeException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator.");
}
for (final Method method : clazz.getDeclaredMethods()) {
for (final Method method : clazz.getDeclaredMethods()) { //查找类中是否存在提供创建Creator实例的静态方法
if (!Modifier.isStatic(method.getModifiers())) continue;
if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() != Creator.class) continue;
@@ -131,55 +222,88 @@ public interface Creator<T> {
}
try {
return (Creator) Class.forName(newDynName.replace('/', '.')).newInstance();
} catch (Exception ex) {
} catch (Throwable ex) {
}
Constructor<T> constructor0 = null;
for (Constructor c : clazz.getConstructors()) { //优先找public 的构造函数
SimpleEntry<String, Class>[] constructorParameters0 = null; //构造函数的参
if (constructor0 == null) { // 1、查找public的空参数构造函数
for (Constructor c : clazz.getConstructors()) {
if (c.getParameterCount() == 0) {
constructor0 = c;
constructorParameters0 = new SimpleEntry[0];
break;
}
}
if (constructor0 == null) {//其次找非private带ConstructorProperties的构造函数
for (Constructor c : clazz.getDeclaredConstructors()) {
if (Modifier.isPrivate(c.getModifiers())) continue;
if (c.getAnnotation(ConstructorProperties.class) != null) {
}
if (constructor0 == null) { // 2、查找public带ConstructorProperties注解的构造函数
for (Constructor c : clazz.getConstructors()) {
ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
if (cp == null) continue;
SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value());
if (fields != null) {
constructor0 = c;
constructorParameters0 = fields;
break;
}
}
}
if (constructor0 == null) {//再次找非private且带-parameters编译项的构造函数 java 8以上才支持
for (Constructor c : clazz.getDeclaredConstructors()) {
if (Modifier.isPrivate(c.getModifiers())) continue;
Parameter[] params = c.getParameters();
if (params.length == 0) continue;
boolean flag = true;
for (Parameter param : params) {
try {
clazz.getDeclaredField(param.getName());
} catch (Exception e) {
flag = false;
break;
if (constructor0 == null) { // 3、查找public且不带ConstructorProperties注解的构造函数
List<Constructor> cs = new ArrayList<>();
for (Constructor c : clazz.getConstructors()) {
if (c.getAnnotation(ConstructorProperties.class) != null) continue;
if (c.getParameterCount() < 1) continue;
cs.add(c);
}
}
if (flag) {
//优先参数最多的构造函数
cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
for (Constructor c : cs) {
SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c));
if (fields != null) {
constructor0 = c;
constructorParameters0 = fields;
break;
}
}
}
if (constructor0 == null) {//最后找非private的空构造函数
if (constructor0 == null) { // 4、查找非private带ConstructorProperties的构造函数
for (Constructor c : clazz.getDeclaredConstructors()) {
if (Modifier.isPrivate(c.getModifiers())) continue;
if (c.getParameterCount() == 0) {
if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
ConstructorProperties cp = (ConstructorProperties) c.getAnnotation(ConstructorProperties.class);
if (cp == null) continue;
SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value());
if (fields != null) {
constructor0 = c;
constructorParameters0 = fields;
break;
}
}
}
if (constructor0 == null) { // 5、查找非private且不带ConstructorProperties的构造函数
List<Constructor> cs = new ArrayList<>();
for (Constructor c : clazz.getDeclaredConstructors()) {
if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue;
if (c.getAnnotation(ConstructorProperties.class) != null) continue;
if (c.getParameterCount() < 1) continue;
cs.add(c);
}
//优先参数最多的构造函数
cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount());
for (Constructor c : cs) {
SimpleEntry<String, Class>[] fields = ConstructorParameters.CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c));
if (fields != null) {
constructor0 = c;
constructorParameters0 = fields;
break;
}
}
}
final Constructor<T> constructor = constructor0;
if (constructor == null) throw new RuntimeException("[" + clazz + "] have no public or java.beans.ConstructorProperties-Annotation constructor.");
final SimpleEntry<String, Class>[] constructorParameters = constructorParameters0;
if (constructor == null || constructorParameters == null) {
throw new RuntimeException("[" + clazz + "] have no public or java.beans.ConstructorProperties-Annotation constructor.");
}
//-------------------------------------------------------------
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
@@ -187,7 +311,7 @@ public interface Creator<T> {
AnnotationVisitor av0;
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", "java/lang/Object", new String[]{supDynName});
{//构造方法
{//Creator自身的构造方法
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
@@ -197,36 +321,19 @@ public interface Creator<T> {
}
{//create 方法
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null);
ConstructorProperties cps = constructor.getAnnotation(ConstructorProperties.class);
String[] cparams = cps == null ? null : cps.value();
if (cparams == null && constructor.getParameterCount() > 0) { // java 8 以上版本才支持的 -parameters 编译项
Parameter[] params = constructor.getParameters();
String[] ss = new String[params.length];
for (int i = 0; i < ss.length; i++) {
try {
clazz.getDeclaredField(params[i].getName());
} catch (Exception e) { //没有该字段,直接退出
ss = null;
break;
}
ss[i] = params[i].getName();
}
cparams = ss;
}
if (cparams != null) {
if (constructorParameters.length > 0) {
av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true);
AnnotationVisitor av1 = av0.visitArray("value");
for (String n : cparams) {
av1.visit(null, n);
for (SimpleEntry<String, Class> n : constructorParameters) {
av1.visit(null, n.getKey());
}
av1.visitEnd();
av0.visitEnd();
}
final Class[] paramTypes = constructor.getParameterTypes();
final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
{ //有Primitive数据类型且值为null的参数需要赋默认值
for (int i = 0; i < paramTypes.length; i++) {
final Class pt = paramTypes[i];
for (int i = 0; i < constructorParameters.length; i++) {
final Class pt = constructorParameters[i].getValue();
if (!pt.isPrimitive()) continue;
mv.visitVarInsn(ALOAD, 1);
if (i < 6) {
@@ -275,7 +382,7 @@ public interface Creator<T> {
mv.visitInsn(DUP);
//---------------------------------------
{
for (int i = 0; i < paramTypes.length; i++) {
for (int i = 0; i < constructorParameters.length; i++) {
mv.visitVarInsn(ALOAD, 1);
if (i < 6) {
mv.visitInsn(iconsts[i]);
@@ -283,7 +390,7 @@ public interface Creator<T> {
mv.visitIntInsn(BIPUSH, i);
}
mv.visitInsn(AALOAD);
final Class ct = paramTypes[i];
final Class ct = constructorParameters[i].getValue();
if (ct.isPrimitive()) {
final Class bigct = Array.get(Array.newInstance(ct, 1), 0).getClass();
mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/'));
@@ -301,7 +408,7 @@ public interface Creator<T> {
//---------------------------------------
mv.visitMethodInsn(INVOKESPECIAL, interName, "<init>", Type.getConstructorDescriptor(constructor), false);
mv.visitInsn(ARETURN);
mv.visitMaxs((paramTypes.length > 0 ? (paramTypes.length + 3) : 2), 2);
mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2);
mv.visitEnd();
}
{ //虚拟 create 方法

View File

@@ -42,7 +42,7 @@ public interface Reproduce<D, S> extends BiFunction<D, S, D> {
}
try {
return (Reproduce) Class.forName(newDynName.replace('/', '.')).newInstance();
} catch (Exception ex) {
} catch (Throwable ex) {
}
// ------------------------------------------------------------------------------
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);

View File

@@ -0,0 +1,19 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.util;
/**
* 对象的类没有标记为&#64;Resource, 可以通过实现Resourcable接口实现动态获取Resource.name
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
public interface Resourcable {
public String resourceName();
}

View File

@@ -15,10 +15,16 @@ import java.util.regex.Pattern;
import javax.annotation.Resource;
/**
* 如果Resource(name = "$") 表示资源name采用所属对象的name
*
* 依赖注入功能主类 <br>
*
* 如果&#64;Resource(name = "$") 表示资源name采用所属对象的name <br>
* 如果没有&#64;Resource 则会取对象的getResourceName()方法值(若存在)
* <blockquote><pre>
* name规则:
* 1: "$"有特殊含义, 不能表示"$"资源本身
* 2: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
*
@@ -56,7 +62,7 @@ public final class ResourceFactory {
}
public void checkName(String name) {
if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_\\-\\.\\[\\]\\(\\)]+$"))) {
if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_;\\-\\.\\[\\]\\(\\)]+$"))) {
throw new IllegalArgumentException("Resource.name(" + name + ") contains illegal character, must be (a-z,A-Z,0-9,_,.,(,),-,[,])");
}
}
@@ -320,17 +326,17 @@ public final class ResourceFactory {
if (consumer != null) consumer.accept(src, field);
String tname = rc.name();
if (tname.contains(RESOURCE_PARENT_NAME)) {
try {
Resource res = src.getClass().getAnnotation(Resource.class);
if (res == null) {
String srcname = (String) src.getClass().getMethod("name").invoke(src);
tname = tname.replace(RESOURCE_PARENT_NAME, srcname);
if (src instanceof Resourcable) {
tname = tname.replace(RESOURCE_PARENT_NAME, ((Resourcable) src).resourceName());
} else {
logger.log(Level.SEVERE, src.getClass().getName() + " not found @Resource on Class or not implements Resourcable");
}
} else {
tname = res.name();
}
} catch (Exception e) { // 获取src中的name()方法的值, 异常则忽略
logger.log(Level.SEVERE, src.getClass().getName() + " not found @Resource on Class or [public String name()] method", e);
}
}
final String rcname = tname;
ResourceEntry re = findEntry(rcname, genctype);

View File

@@ -14,7 +14,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* 方法在资源被更新以后调用。
*
* <blockquote><pre>
* public class Record {
* public class RecordService implements Service {
*
* &#64;Resource(name = "record.id")
* private int id;

View File

@@ -38,6 +38,7 @@ public abstract class TypeToken<T> {
* 例如: Map&#60; String, String &#62; 返回 ture; Map&#60; ? extends Serializable, String &#62; 返回false;
*
* @param type Type对象
*
* @return 是否可反解析
*/
public final static boolean isClassType(final Type type) {
@@ -55,12 +56,58 @@ public abstract class TypeToken<T> {
return true;
}
/**
* 动态创建类型为ParameterizedType或Class的Type
*
* @param type 当前泛型
* @param declaringType0 子类
*
* @return Type
*/
public static Type createClassType(final Type type, final Type declaringType0) {
if (isClassType(type)) return type;
if (type instanceof ParameterizedType) { // e.g. Map<String, String>
final ParameterizedType pt = (ParameterizedType) type;
final Type[] paramTypes = pt.getActualTypeArguments();
for (int i = 0; i < paramTypes.length; i++) {
paramTypes[i] = createClassType(paramTypes[i], declaringType0);
}
return createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes);
}
Type declaringType = declaringType0;
if (declaringType instanceof Class) {
do {
declaringType = ((Class) declaringType).getGenericSuperclass();
if (declaringType == Object.class) return Object.class;
} while (declaringType instanceof Class);
}
//存在通配符则declaringType 必须是 ParameterizedType
if (!(declaringType instanceof ParameterizedType)) return Object.class;
final ParameterizedType declaringPType = (ParameterizedType) declaringType;
final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters();
final Type[] desTypes = declaringPType.getActualTypeArguments();
if (type instanceof WildcardType) { // e.g. <? extends Serializable>
final WildcardType wt = (WildcardType) type;
for (Type f : wt.getUpperBounds()) {
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
} else if (type instanceof TypeVariable) { // e.g. <? extends E>
for (int i = 0; i < virTypes.length; i++) {
if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i];
}
}
return type;
}
/**
* 动态创建 ParameterizedType
*
* @param ownerType0 ParameterizedType 的 ownerType
* @param rawType0 ParameterizedType 的 rawType
* @param actualTypeArguments0 ParameterizedType 的 actualTypeArguments
*
* @return Type
*/
public static Type createParameterizedType(final Type ownerType0, final Type rawType0, final Type... actualTypeArguments0) {
@@ -136,7 +183,7 @@ public abstract class TypeToken<T> {
try {
Class.forName(newDynName.replace('/', '.'));
newDynName = TypeToken.class.getName().replace('.', '/') + "_Dyn" + Math.abs(System.nanoTime());
} catch (Exception ex) { //异常说明类不存在
} catch (Throwable ex) { //异常说明类不存在
break;
}
}

View File

@@ -96,7 +96,7 @@ public final class Utility {
* @return Map
*/
public static Map<String, String> ofMap(String... items) {
HashMap<String, String> map = new HashMap<>();
HashMap<String, String> map = new LinkedHashMap<>();
int len = items.length / 2;
for (int i = 0; i < len; i++) {
map.put(items[i * 2], items[i * 2 + 1]);
@@ -113,7 +113,7 @@ public final class Utility {
* @return Map
*/
public static Map<Object, Object> ofMap(Object... items) {
HashMap<Object, Object> map = new HashMap<>();
HashMap<Object, Object> map = new LinkedHashMap<>();
int len = items.length / 2;
for (int i = 0; i < len; i++) {
map.put(items[i * 2], items[i * 2 + 1]);
@@ -121,6 +121,34 @@ public final class Utility {
return map;
}
/**
* 将多个元素组合成一个Set
*
* @param <T> 泛型
* @param items 元素
*
* @return Set
*/
public static <T> Set<T> ofSet(T... items) {
Set<T> set = new LinkedHashSet<>();
for (T item : items) set.add(item);
return set;
}
/**
* 将多个元素组合成一个List
*
* @param <T> 泛型
* @param items 元素
*
* @return List
*/
public static <T> List<T> ofList(T... items) {
List<T> list = new ArrayList<>();
for (T item : items) list.add(item);
return list;
}
/**
* 获取不带"-"的UUID值
*
@@ -131,7 +159,54 @@ public final class Utility {
}
/**
* 数组上追加数据
* 将一个或多个新元素添加到数组开始,数组中的元素自动后移
*
* @param <T> 泛型
* @param array 原数组
* @param objs 待追加数据
*
* @return 新数组
*/
public static <T> T[] unshift(final T[] array, final T... objs) {
if (array == null || array.length == 0) return objs;
final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.length);
System.arraycopy(objs, 0, news, 0, objs.length);
System.arraycopy(array, 0, news, objs.length, array.length);
return news;
}
/**
* 将一个或多个新元素添加到数组开始,数组中的元素自动后移
*
* @param <T> 泛型
* @param array 原数组
* @param objs 待追加数据
*
* @return 新数组
*/
public static <T> T[] unshift(final T[] array, final Collection<T> objs) {
if (objs == null || objs.isEmpty()) return array;
if (array == null) {
T one = null;
for (T t : objs) {
if (t != null) one = t;
break;
}
if (one == null) return array;
T[] news = (T[]) Array.newInstance(one.getClass(), objs.size());
return objs.toArray(news);
}
T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.size());
int index = -1;
for (T t : objs) {
news[(++index)] = t;
}
System.arraycopy(array, 0, news, objs.size(), array.length);
return news;
}
/**
* 将一个或多个新元素添加到数组结尾
*
* @param <T> 泛型
* @param array 原数组
@@ -148,7 +223,7 @@ public final class Utility {
}
/**
* 数组上追加数据
* 将一个或多个新元素添加到数组结尾
*
* @param <T> 泛型
* @param array 原数组

View File

@@ -34,8 +34,8 @@ public class FilterNodeTest {
FilterNode joinNode1 = FilterJoinNode.create(UserTestTable.class, new String[]{"userid", "username"}, "username", LIKE, bean.username)
.or(FilterJoinNode.create(UserTestTable.class, new String[]{"userid", "username"}, "createtime", GREATERTHAN, bean.createtime));
FilterNode joinNode2 = FilterJoinNode.create(CarTypeTestTable.class, "cartype", "typename", LIKE, bean.typename);
FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNode.create("carid", GREATERTHAN, bean.carid).and(joinNode1).or(joinNode2);
FilterNode beanNode = FilterNodeBean.createFilterNode(bean);
final FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNode.create("carid", GREATERTHAN, bean.carid).and(joinNode1).or(joinNode2);
final FilterNode beanNode = FilterNodeBean.createFilterNode(bean);
System.out.println("node.string = " + node);
System.out.println("bean.string = " + beanNode);
Map<Class, String> nodeJoinTabalis = node.getJoinTabalis();
@@ -46,8 +46,11 @@ public class FilterNodeTest {
CharSequence beanWhere = beanNode.createSQLExpress(carEntity, beanJoinTabalis);
System.out.println("node.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) + " WHERE " + nodeWhere);
System.out.println("bean.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (beanJoinsql == null ? "" : beanJoinsql) + " WHERE " + beanWhere);
assert node.isCacheUseable(func) : "isCacheUseable 应该是true";
assert beanNode.isCacheUseable(func) : "isCacheUseable 应该是true";
boolean r1 = node.isCacheUseable(func);
if(!r1) System.err.println("node.isCacheUseable 应该是true");
boolean r2 = beanNode.isCacheUseable(func);
if(!r2) System.err.println("beanNode.isCacheUseable 应该是true");
System.out.println("node.Predicate = " + node.createPredicate(carEntity.getCache()));
System.out.println("bean.Predicate = " + beanNode.createPredicate(carEntity.getCache()));
System.out.println("node.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), node));

View File

@@ -44,6 +44,9 @@ public interface HttpRequestDesc {
//更新sessionid
public String changeSessionid();
//指定值更新sessionid
public String changeSessionid(String newsessionid);
//使sessionid失效
public void invalidateSession();
@@ -80,6 +83,46 @@ public interface HttpRequestDesc {
//截取getRequestURI最后的一个/后面的部分
public String getRequstURILastPath();
// 获取请求URL最后的一个/后面的部分的short值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2
public short getRequstURILastPath(short defvalue);
// 获取请求URL最后的一个/后面的部分的short值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2
public short getRequstURILastPath(int radix, short defvalue);
// 获取请求URL最后的一个/后面的部分的int值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2
public int getRequstURILastPath(int defvalue);
// 获取请求URL最后的一个/后面的部分的int值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2
public int getRequstURILastPath(int radix, int defvalue);
// 获取请求URL最后的一个/后面的部分的float值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: float type = request.getRequstURILastPath(0.f); //type = 2.f
public float getRequstURILastPath(float defvalue);
// 获取请求URL最后的一个/后面的部分的long值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2
public long getRequstURILastPath(long defvalue);
// 获取请求URL最后的一个/后面的部分的long值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2
public long getRequstURILastPath(int radix, long defvalue);
// 获取请求URL最后的一个/后面的部分的double值 <br>
// 例如请求URL /pipes/record/query/2 <br>
// 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0
public double getRequstURILastPath(double defvalue);
//从prefix之后截取getRequestURI再对"/"进行分隔
public String[] getRequstURIPaths(String prefix);

View File

@@ -9,11 +9,12 @@ import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import org.redkale.convert.json.*;
import org.redkale.net.http.*;
import org.redkale.util.AsyncHandler;
/**
*
@@ -59,7 +60,10 @@ public interface HttpResponseDesc {
public HttpResponse skipHeader();
//异步输出指定内容
public <A> void sendBody(ByteBuffer buffer, A attachment, CompletionHandler<Integer, A> handler);
public <A> void sendBody(ByteBuffer buffer, A attachment, AsyncHandler<Integer, A> handler);
//创建AsyncHandler实例将非字符串对象以JSON格式输出字符串以文本输出
public AsyncHandler createAsyncHandler();
//关闭HTTP连接如果是keep-alive则不强制关闭
public void finish();
@@ -88,11 +92,14 @@ public interface HttpResponseDesc {
//将RetResult对象以JSON格式输出
public void finishJson(final JsonConvert convert, final org.redkale.service.RetResult ret);
//将对象以JavaScript格式输出
public void finishJsResult(String var, Object result);
//将CompletableFuture的结果对象以JSON格式输出
public void finishJson(final CompletableFuture future);
//将对象以JavaScript格式输出
public void finishJsResult(JsonConvert jsonConvert, String var, Object result);
//将CompletableFuture的结果对象以JSON格式输出
public void finishJson(final JsonConvert convert, final CompletableFuture future);
//将CompletableFuture的结果对象以JSON格式输出
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future);
//将指定字符串以响应结果输出
public void finish(String obj);
@@ -106,6 +113,9 @@ public interface HttpResponseDesc {
//以404状态码输出
public void finish404();
//将指定byte[]按响应结果输出
public void finish(final byte[] bs);
//将指定ByteBuffer按响应结果输出
public void finish(ByteBuffer buffer);

View File

@@ -1,13 +1,13 @@
package org.redkale.test.rest;
import java.util.List;
import java.util.*;
import javax.annotation.Resource;
import org.redkale.net.http.*;
import org.redkale.service.*;
import org.redkale.source.DataSource;
import org.redkale.source.Flipper;
import org.redkale.util.Sheet;
import org.redkale.util.*;
/**
* 类说明:
@@ -70,10 +70,26 @@ public class HelloService implements Service {
return source.queryList(HelloEntity.class, bean);
}
//查询List列表
@RestMapping(name = "listmap")
public List<HelloEntity> queryHello(HelloBean bean, @RestParam(name = "map") Map<String, String> map) { //通过 /pipes/hello/list?bean={...} 查询List列表
System.out.println("map参数: " + map);
if (source != null) return source.queryList(HelloEntity.class, bean);
return new ArrayList<>();
}
//查询单个
@RestMapping(name = "find")
public HelloEntity findHello(@RestParam(name = "#") int id) { //通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象
return source.find(HelloEntity.class, id);
}
//异步查询单个
@RestMapping(name = "asyncfind")
public void findHello(AsyncHandler handler, @RestParam(name = "#") int id) { //通过 /pipes/hello/find/1234、/pipes/hello/jsfind/1234 查询对象
if (source != null) source.findAsync(handler, HelloEntity.class, id);
HelloEntity rs = new HelloEntity();
rs.setHelloname("Hello名称");
if (handler != null) handler.completed(rs, null);
}
}

View File

@@ -6,7 +6,6 @@ import javax.annotation.Resource;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
protected static final RetResult RET_UNLOGIN = RetCodes.retResult(RetCodes.RET_USER_UNLOGIN);
@@ -26,16 +25,16 @@ public class SimpleRestServlet extends RestHttpServlet<UserInfo> {
//普通鉴权
@Override
public boolean authenticate(int module, int actionid, HttpRequest request, HttpResponse response) throws IOException {
public void authenticate(int module, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
UserInfo info = currentUser(request);
if (info == null) {
response.finishJson(RET_UNLOGIN);
return false;
return;
} else if (!info.checkAuth(module, actionid)) {
response.finishJson(RET_AUTHILLEGAL);
return false;
return;
}
return true;
next.execute(request, response);
}
}

View File

@@ -39,10 +39,16 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
String url = "http://127.0.0.1:" + port + "/pipes/hello/update?entity={}&bean2={}";
System.out.println(Utility.postHttpContent(url, headers, null));
url = "http://127.0.0.1:" + port + "/pipes/hello/asyncfind/1234";
System.out.println("异步查找: " + Utility.postHttpContent(url, headers, null));
url = "http://127.0.0.1:" + port + "/pipes/hello/listmap?map={'a':5}";
System.out.println("listmap: " + Utility.postHttpContent(url, headers, null));
}
@AuthIgnore
@WebAction(url = "/hello/create")
@WebMapping(url = "/hello/create")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -54,7 +60,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/delete/")
@WebMapping(url = "/hello/delete/")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
@@ -63,7 +69,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/update")
@WebMapping(url = "/hello/update")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
String clientaddr = req.getRemoteAddr();
@@ -75,7 +81,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/partupdate")
@WebMapping(url = "/hello/partupdate")
public void partupdate(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloEntity bean = req.getJsonParameter(HelloEntity.class, "bean");
@@ -87,7 +93,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/query")
@WebMapping(url = "/hello/query")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
@@ -101,7 +107,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/list")
@WebMapping(url = "/hello/list")
public void list(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
HelloBean bean = req.getJsonParameter(HelloBean.class, "bean");
@@ -114,7 +120,7 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/find/")
@WebMapping(url = "/hello/find/")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
@@ -122,4 +128,11 @@ public class _DynHelloRestServlet1 extends SimpleRestServlet {
resp.finishJson(bean);
}
@AuthIgnore
@WebMapping(url = "/hello/asyncfind/")
public void asyncfind(HttpRequest req, HttpResponse resp) throws IOException {
HelloService service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
int id = Integer.parseInt(req.getRequstURILastPath());
service.findHello(resp.createAsyncHandler(), id);
}
}

View File

@@ -27,7 +27,7 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
private Map<String, HelloService2> _servicemap;
@AuthIgnore
@WebAction(url = "/hello/create", comment = "创建Hello对象")
@WebMapping(url = "/hello/create", comment = "创建Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void create(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
@@ -40,7 +40,7 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/delete/", comment = "根据id删除Hello对象")
@WebMapping(url = "/hello/delete/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
public void delete(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
@@ -50,7 +50,7 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/update", comment = "修改Hello对象")
@WebMapping(url = "/hello/update", comment = "修改Hello对象")
@WebParam(name = "bean", type = HelloEntity.class, comment = "Hello对象")
public void update(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
@@ -62,7 +62,7 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/query", comment = "查询Hello对象列表")
@WebMapping(url = "/hello/query", comment = "查询Hello对象列表")
@WebParam(name = "bean", type = HelloBean.class, comment = "过滤条件")
public void query(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));
@@ -77,7 +77,7 @@ public class _DynHelloRestServlet2 extends SimpleRestServlet {
}
@AuthIgnore
@WebAction(url = "/hello/find/", comment = "根据id删除Hello对象")
@WebMapping(url = "/hello/find/", comment = "根据id删除Hello对象")
@WebParam(name = "#", type = int.class, comment = "Hello对象id")
public void find(HttpRequest req, HttpResponse resp) throws IOException {
HelloService2 service = _servicemap == null ? _service : _servicemap.get(req.getHeader(Rest.REST_HEADER_RESOURCE_NAME, ""));

View File

@@ -0,0 +1,200 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.service;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.util.HashSet;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.annotation.Resource;
import org.redkale.convert.bson.BsonConvert;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.Service;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.WatchFactory;
/**
*
* @author zhangjx
*/
@RestService(name = "abmain")
public class ABMainService implements Service {
@Resource
private BCService bcService;
public static void remotemain(String[] args) throws Throwable {
System.out.println("------------------- 远程模式调用 -----------------------------------");
final int abport = 8888;
ResourceFactory factory = ResourceFactory.root();
factory.register(JsonConvert.root());
factory.register(BsonConvert.root());
//------------------------ 初始化 CService ------------------------------------
CService cservice = Sncp.createLocalService("", null, ResourceFactory.root(), CService.class, new InetSocketAddress("127.0.0.1", 5577), "", new HashSet<>(), (AnyValue) null, null, null);
SncpServer cserver = new SncpServer();
cserver.getLogger().setLevel(Level.WARNING);
cserver.addSncpServlet(cservice);
cserver.init(DefaultAnyValue.create("port", 5577));
cserver.start();
//------------------------ 初始化 BCService ------------------------------------
final Transport bctransport = new Transport("", WatchFactory.root(), "", newBufferPool(), newChannelGroup(), null, Utility.ofSet(new InetSocketAddress("127.0.0.1", 5577)));
BCService bcservice = Sncp.createLocalService("", null, ResourceFactory.root(), BCService.class, new InetSocketAddress("127.0.0.1", 5588), "", new HashSet<>(), (AnyValue) null, bctransport, null);
CService remoteCService = Sncp.createRemoteService("", null, CService.class, new InetSocketAddress("127.0.0.1", 5588), "", new HashSet<>(), (AnyValue) null, bctransport);
factory.inject(remoteCService);
factory.register("", remoteCService);
SncpServer bcserver = new SncpServer();
bcserver.getLogger().setLevel(Level.WARNING);
bcserver.addSncpServlet(bcservice);
bcserver.init(DefaultAnyValue.create("port", 5588));
bcserver.start();
//------------------------ 初始化 ABMainService ------------------------------------
final Transport abtransport = new Transport("", WatchFactory.root(), "", newBufferPool(), newChannelGroup(), null, Utility.ofSet(new InetSocketAddress("127.0.0.1", 5588)));
ABMainService service = Sncp.createLocalService("", null, ResourceFactory.root(), ABMainService.class, new InetSocketAddress("127.0.0.1", 5599), "", new HashSet<>(), (AnyValue) null, bctransport, null);
BCService remoteBCService = Sncp.createRemoteService("", null, BCService.class, new InetSocketAddress("127.0.0.1", 5599), "", new HashSet<>(), (AnyValue) null, abtransport);
factory.inject(remoteBCService);
factory.register("", remoteBCService);
HttpServer server = new HttpServer();
server.getLogger().setLevel(Level.WARNING);
server.addRestServlet("", ABMainService.class, service, DefaultRestServlet.class, "/pipes");
factory.inject(cservice);
factory.inject(bcservice);
factory.inject(service);
server.init(DefaultAnyValue.create("port", abport));
server.start();
Thread.sleep(100);
//同步方法
String url = "http://127.0.0.1:" + abport + "/pipes/abmain/syncabtime/张先生";
System.out.println(Utility.postHttpContent(url));
//异步方法
url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生";
System.out.println(Utility.postHttpContent(url));
//异步方法
url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生";
System.out.println(Utility.postHttpContent(url));
server.shutdown();
}
public static void main(String[] args) throws Throwable {
System.out.println("------------------- 本地模式调用 -----------------------------------");
final int abport = 8888;
ResourceFactory factory = ResourceFactory.root();
ABMainService service = new ABMainService();
BCService bcservice = new BCService();
factory.register("", bcservice);
factory.register("", new CService());
factory.inject(bcservice);
factory.inject(service);
HttpServer server = new HttpServer();
server.getLogger().setLevel(Level.WARNING);
server.addRestServlet("", ABMainService.class, service, DefaultRestServlet.class, "/pipes");
server.init(DefaultAnyValue.create("port", "" + abport));
server.start();
Thread.sleep(100);
//同步方法
String url = "http://127.0.0.1:" + abport + "/pipes/abmain/syncabtime/张先生";
System.out.println(Utility.postHttpContent(url));
//异步方法
url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime/张先生";
System.out.println(Utility.postHttpContent(url));
//异步方法
url = "http://127.0.0.1:" + abport + "/pipes/abmain/asyncabtime2/张先生";
System.out.println(Utility.postHttpContent(url));
server.shutdown();
//远程模式
remotemain(args);
}
public static AsynchronousChannelGroup newChannelGroup() throws IOException {
final AtomicInteger counter = new AtomicInteger();
ExecutorService transportExec = Executors.newFixedThreadPool(16, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-Thread-" + counter.incrementAndGet());
return t;
});
return AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
}
public static ObjectPool<ByteBuffer> newBufferPool() {
return new ObjectPool<>(new AtomicLong(), new AtomicLong(), 16,
(Object... params) -> ByteBuffer.allocateDirect(8192), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != 8192) return false;
e.clear();
return true;
});
}
@RestMapping(name = "syncabtime")
public String abCurrentTime(@RestParam(name = "#") final String name) {
String rs = "同步abCurrentTime: " + bcService.bcCurrentTime(name);
System.out.println("执行了 ABMainService.abCurrentTime++++同步方法");
return rs;
}
@RestMapping(name = "asyncabtime")
public void abCurrentTime(final AsyncHandler<String, Void> handler, @RestParam(name = "#") final String name) {
bcService.bcCurrentTime(AsyncHandler.create((v, a) -> {
System.out.println("执行了 ABMainService.abCurrentTime----异步方法");
String rs = "异步abCurrentTime: " + v;
if (handler != null) handler.completed(rs, a);
}, (t, a) -> {
if (handler != null) handler.failed(t, a);
}), name);
}
@RestMapping(name = "asyncabtime2")
public void abCurrentTime(final MyAsyncHandler<String, Void> handler, @RestParam(name = "#") final String name) {
bcService.bcCurrentTime(new MyAsyncHandler<String, Void>() {
@Override
public int id() {
return 1;
}
@Override
public void completed(String v, Void a) {
System.out.println("执行了 ABMainService.abCurrentTime----异步方法2");
String rs = "异步abCurrentTime: " + v;
if (handler != null) handler.completed(rs, a);
}
@Override
public void failed(Throwable exc, Void attachment) {
}
@Override
public int id2() {
return 2;
}
}, name);
}
}

View File

@@ -0,0 +1,61 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.service;
import javax.annotation.Resource;
import org.redkale.service.*;
import org.redkale.util.AsyncHandler;
/**
*
* @author zhangjx
*/
public class BCService implements Service {
@Resource
private CService cService;
public String bcCurrentTime(final String name) {
String rs = "同步bcCurrentTime: " + cService.ccCurrentTime(name).getResult();
System.out.println("执行了 BCService.bcCurrentTime++++同步方法");
return rs;
}
public void bcCurrentTime(final AsyncHandler<String, Void> handler, final String name) {
cService.ccCurrentTime(AsyncHandler.create((v, a) -> {
System.out.println("执行了 BCService.bcCurrentTime----异步方法");
String rs = "异步bcCurrentTime: " + (v == null ? null : v.getResult());
if (handler != null) handler.completed(rs, null);
}, (t, a) -> {
if (handler != null) handler.failed(t, a);
}), name);
}
public void bcCurrentTime(final MyAsyncHandler<String, Void> handler, final String name) {
cService.mcCurrentTime(new MyAsyncHandler<RetResult<String>, Void>() {
@Override
public int id() {
return 1;
}
@Override
public void completed(RetResult<String> v, Void a) {
System.out.println("执行了 BCService.bcCurrentTime----异步方法2");
String rs = "异步bcCurrentTime: " + (v == null ? null : v.getResult());
if (handler != null) handler.completed(rs, null);
}
@Override
public void failed(Throwable exc, Void attachment) {
}
@Override
public int id2() {
return 2;
}
}, name);
}
}

View File

@@ -0,0 +1,34 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.service;
import org.redkale.service.*;
import org.redkale.util.*;
/**
*
* @author zhangjx
*/
public class CService implements Service {
public RetResult<String> ccCurrentTime(final String name) {
String rs = "同步ccCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis());
System.out.println("执行了 CService.ccCurrentTime++++同步方法");
return new RetResult(rs);
}
public void ccCurrentTime(final AsyncHandler<RetResult<String>, Void> handler, final String name) {
String rs = "异步ccCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis());
System.out.println("执行了 CService.ccCurrentTime----异步方法");
if (handler != null) handler.completed(new RetResult(rs), null);
}
public void mcCurrentTime(final MyAsyncHandler<RetResult<String>, Void> handler, final String name) {
String rs = "异步mcCurrentTime: " + name + ": " + Utility.formatTime(System.currentTimeMillis());
System.out.println("执行了 CService.mcCurrentTime----异步方法2");
if (handler != null) handler.completed(new RetResult(rs), null);
}
}

View File

@@ -0,0 +1,18 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.service;
/**
*
* @author zhangjx
* @param <V> V
* @param <A> A
*/
public abstract class MyAsyncHandler<V, A> extends MyAsyncInnerHandler<V, A> {
public abstract int id();
}

View File

@@ -0,0 +1,18 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.test.service;
import org.redkale.util.AsyncHandler;
/**
*
* @author zhangjx
*/
public abstract class MyAsyncInnerHandler<V, A> implements AsyncHandler<V, A> {
protected abstract int id2();
}

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