Browse Source

初始化ump代码

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
bbf938553f
78 changed files with 7333 additions and 0 deletions
  1. +60
    -0
      source/manager/ump-booter/pom.xml
  2. +138
    -0
      source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java
  3. +12
    -0
      source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java
  4. +5
    -0
      source/manager/ump-booter/src/main/resources/application.properties
  5. +27
    -0
      source/manager/ump-booter/src/main/resources/assembly.xml
  6. +13
    -0
      source/manager/ump-booter/src/main/resources/banner.txt
  7. +8
    -0
      source/manager/ump-booter/src/main/resources/config.properties
  8. +46
    -0
      source/manager/ump-booter/src/main/resources/log4j2-jump.xml
  9. +9
    -0
      source/manager/ump-booter/src/main/resources/scripts/jump-start.sh
  10. +16
    -0
      source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh
  11. +81
    -0
      source/manager/ump-model/pom.xml
  12. +16
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java
  13. +58
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java
  14. +47
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java
  15. +145
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java
  16. +4
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java
  17. +115
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java
  18. +47
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java
  19. +88
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java
  20. +217
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java
  21. +104
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java
  22. +50
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java
  23. +24
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java
  24. +46
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java
  25. +92
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java
  26. +141
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java
  27. +89
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java
  28. +160
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java
  29. +86
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java
  30. +180
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java
  31. +21
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java
  32. +54
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java
  33. +33
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java
  34. +101
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java
  35. +156
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java
  36. +42
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java
  37. +117
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java
  38. +32
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java
  39. +61
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java
  40. +40
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java
  41. +43
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java
  42. +48
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java
  43. +34
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java
  44. +68
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java
  45. +69
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java
  46. +20
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java
  47. +97
    -0
      source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java
  48. +114
    -0
      source/manager/ump-service/pom.xml
  49. +31
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java
  50. +310
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java
  51. +36
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java
  52. +925
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java
  53. +17
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java
  54. +134
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java
  55. +62
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java
  56. +880
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java
  57. +15
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java
  58. +80
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java
  59. +21
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java
  60. +10
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java
  61. +79
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java
  62. +162
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java
  63. +17
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java
  64. +41
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java
  65. +153
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java
  66. +133
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java
  67. +289
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java
  68. +61
    -0
      source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java
  69. +83
    -0
      source/manager/ump-web/pom.xml
  70. +22
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java
  71. +69
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java
  72. +68
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java
  73. +147
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java
  74. +64
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java
  75. +29
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java
  76. +38
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java
  77. +51
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java
  78. +32
    -0
      source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java

+ 60
- 0
source/manager/ump-booter/pom.xml View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>manager</artifactId>
<groupId>com.jd.blockchain</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ump-booter</artifactId>

<name>ump-booter</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 138
- 0
source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java View File

@@ -0,0 +1,138 @@
package com.jd.blockchain.ump;

import org.springframework.boot.SpringApplication;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


public class UmpBooter {

private static final String ARG_PORT = "-p";

private static final String ARG_HOST = "-h";

private static final String CONFIG = "BOOT-INF" + File.separator + "classes" + File.separator + "config.properties";

private static final String CONFIG_PROP_HOST = "server.host";

private static final String CONFIG_PROP_HOST_DEFAULT = "0.0.0.0";

private static final String CONFIG_PROP_PORT = "server.port";

private static final String CONFIG_PROP_PORT_DEFAULT = "8080";

private static final String CONFIG_PROP_DB_URL = "db.url";

private static final String CONFIG_PROP_DB_URL_DEFAULT = "rocksdb://#project#/jumpdb";

public static void main(String[] args) {
try {
startServer(server(args));
System.out.println("Server Start SUCCESS !!!");
} catch (Exception e) {
e.printStackTrace();
System.err.printf("Server Start FAIL -> %s, Exit JVM !!!", e.toString());
// 正常退出
System.exit(0);
}
}

private static void startServer(Server server) {

System.out.printf("server.address = %s, server.port = %s, db.url = %s \r\n",
server.host, server.port, server.dbUrl);

List<String> argList = new ArrayList<>();
argList.add(String.format("--server.address=%s", server.host));
argList.add(String.format("--server.port=%s", server.port));
argList.add(String.format("--db.url=%s", server.dbUrl));

String[] args = argList.toArray(new String[argList.size()]);

// 启动服务器;
SpringApplication.run(UmpConfiguration.class, args);
}

private static Server server(String[] args) {
Server defaultServer = serverFromConfig();
if (args == null || args.length == 0) {
return defaultServer;
}
String host = null;

int port = 0;

// 读取参数列表
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals(ARG_HOST)) {
host = args[i + 1];
} else if (arg.equals(ARG_PORT)) {
port = Integer.parseInt(args[i + 1]);
}
}

// 参数列表中的数据不完整,则剩余部分数据从配置文件中获取
if (host == null) {
host = defaultServer.host;
}
if (port == 0) {
port = defaultServer.port;
}

return new Server(host, port, defaultServer.dbUrl);
}

private static Server serverFromConfig() {
try {
InputStream inputStream = UmpBooter.class.getResourceAsStream(File.separator + CONFIG);
if (inputStream == null) {
System.err.println("InputStream is NULL !!!");
}
Properties props = new Properties();
props.load(inputStream);
String host = props.getProperty(CONFIG_PROP_HOST, CONFIG_PROP_HOST_DEFAULT);
int port = Integer.parseInt(
props.getProperty(CONFIG_PROP_PORT, CONFIG_PROP_PORT_DEFAULT));
String dbUrl = props.getProperty(CONFIG_PROP_DB_URL, CONFIG_PROP_DB_URL_DEFAULT);
return new Server(host, port, dbUrl);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private static class Server {

private String host;

private int port;

private String dbUrl;

public Server(String host, int port, String dbUrl) {
this.host = host;
this.port = port;
this.dbUrl = dbUrl;
}

public String getHost() {
return host;
}

public void setHost(String host) {
this.host = host;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}
}
}

+ 12
- 0
source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java View File

@@ -0,0 +1,12 @@
package com.jd.blockchain.ump;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@EnableConfigurationProperties
@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class}
)
public class UmpConfiguration {
}

+ 5
- 0
source/manager/ump-booter/src/main/resources/application.properties View File

@@ -0,0 +1,5 @@
server.tomcat.uri-encoding=utf-8

spring.mvc.favicon.enabled=false

logging.config=classpath:log4j2-jump.xml

+ 27
- 0
source/manager/ump-booter/src/main/resources/assembly.xml View File

@@ -0,0 +1,27 @@
<?xml version='1.0' encoding='UTF-8'?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0
http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>${project.version}</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/main/resources/scripts</directory>
<outputDirectory>bin</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>ext</outputDirectory>
<includes>
<include>com.jd.blockchain:ump-booter</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>

+ 13
- 0
source/manager/ump-booter/src/main/resources/banner.txt View File

@@ -0,0 +1,13 @@

▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄
▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░▌
▀▀▀▀▀█░█▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌ ▐░▌
▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌
▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
▐░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌
▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌ ▐░▐░▌
▐░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌
▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀

+ 8
- 0
source/manager/ump-booter/src/main/resources/config.properties View File

@@ -0,0 +1,8 @@
# Tomcat启动的HOST,默认为0.0.0.0
server.host=0.0.0.0

# Tomcat启动监听端口号
server.port=8080

# 本地数据库存储位置
db.url=rocksdb://#project#/jumpdb

+ 46
- 0
source/manager/ump-booter/src/main/resources/log4j2-jump.xml View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="WARN" monitorInterval="60">
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<!--输出日志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</console>
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="UmpRollingInfo" fileName="${sys:jump.log}/logs/ump.info.log"
filePattern="${sys:jump.log}/logs/$${date:yyyy-MM}/ump.info-%d{yyyy-MM-dd}-%i.log">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
<RollingFile name="UmpRollingError" fileName="${sys:jump.log}/logs/ump.error.log"
filePattern="${sys:jump.log}/logs/$${date:yyyy-MM}/ump.error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉spring的一些DEBUG信息-->
<logger name="org.springframework" level="INFO"></logger>
<root level="all">
<appender-ref ref="Console"/>
<appender-ref ref="UmpRollingInfo"/>
<appender-ref ref="UmpRollingError"/>
</root>
</loggers>
</configuration>

+ 9
- 0
source/manager/ump-booter/src/main/resources/scripts/jump-start.sh View File

@@ -0,0 +1,9 @@
#!/bin/bash

HOME=$(cd `dirname $0`;cd ../; pwd)
UMP=$(ls $HOME/ext | grep ump-booter-)
if [ ! -n "UMP" ]; then
echo "Unified Management Platform Is Null !!!"
else
nohup java -jar -server -Djump.log=$HOME $HOME/ext/$UMP $* >$HOME/bin/jump.out 2>&1 &
fi

+ 16
- 0
source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh View File

@@ -0,0 +1,16 @@
#!/bin/bash

#启动Home路径
BOOT_HOME=$(cd `dirname $0`;cd ../; pwd)

#获取进程PID
PID=`ps -ef | grep $BOOT_HOME/ext/ump-booter | grep -v grep | awk '{print $2}'`

#通过Kill命令将进程杀死
if [ -z "$PID" ]; then
echo "Unable to find UMP PID. stop aborted."
else
echo "Start to kill PID = $PID ..."
kill -9 $PID
echo "Unified Management Platform has been stopped ..."
fi

+ 81
- 0
source/manager/ump-model/pom.xml View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>manager</artifactId>
<groupId>com.jd.blockchain</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ump-model</artifactId>

<name>ump-model</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>

<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>

<dependency>
<groupId>org.rocksdb</groupId>
<artifactId>rocksdbjni</artifactId>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 16
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java View File

@@ -0,0 +1,16 @@
package com.jd.blockchain.ump.dao;

public interface DBConnection {

String dbSchema();

DBConnection initDbUrl(String dbUrl);

void put(String key, String value);

void put(String key, Object value, Class<?> type);

String get(String key);

boolean exist(String dbUrl);
}

+ 58
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java View File

@@ -0,0 +1,58 @@
package com.jd.blockchain.ump.dao;

import org.reflections.Reflections;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class DBConnectionProvider {

private static final Map<String, DBConnection> dbConnections = new ConcurrentHashMap<>();

static {
init();
}

public static DBConnection dbConnection(String dbUrl) {
String dbSchema = dbSchema(dbUrl);
if (!dbConnections.containsKey(dbSchema)) {
throw new IllegalStateException(
String.format("Can not find DBConnection by {%s} !", dbUrl));
}

DBConnection dbConnection = dbConnections.get(dbSchema);
return dbConnection.initDbUrl(dbUrl);
}


private static String dbSchema(String dbUrl) {
// rocksdb:///home/xxx -> rocksdb
return dbUrl.split("://")[0];

}

private static void init() {
// 初始化所有实现类
Reflections reflections = new Reflections("com.jd.blockchain.ump.dao");

Set<Class<? extends DBConnection>> dbConnectionSet =
reflections.getSubTypesOf(DBConnection.class);

for (Class<? extends DBConnection> clazz : dbConnectionSet) {

if (!clazz.isInterface() && !clazz.equals(UmpDaoHandler.class)) {
try {
// 根据class生成对象
DBConnection dbConnection = clazz.newInstance();
String dbSchema = dbConnection.dbSchema();
if (dbSchema != null && dbSchema.length() > 0) {
dbConnections.put(dbSchema, dbConnection);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
}
}

+ 47
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java View File

@@ -0,0 +1,47 @@
package com.jd.blockchain.ump.dao;

import com.alibaba.fastjson.JSON;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MemoryDBConnection implements DBConnection {

private static final String MEMORY_SCHEMA = "memory";

private final Map<String, String> memory = new ConcurrentHashMap<>();

@Override
public String dbSchema() {
return MEMORY_SCHEMA;
}

@Override
public DBConnection initDbUrl(String dbUrl) {
return this;
}

@Override
public void put(String key, String value) {
memory.put(key, value);
}

@Override
public void put(String key, Object value, Class<?> type) {
String json = JSON.toJSONString(value);
put(key, json);
}

@Override
public String get(String key) {
return memory.get(key);
}

@Override
public boolean exist(String dbUrl) {
if (dbUrl.startsWith(MEMORY_SCHEMA)) {
return true;
}
return false;
}
}

+ 145
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java View File

@@ -0,0 +1,145 @@
package com.jd.blockchain.ump.dao;


import com.alibaba.fastjson.JSON;
import org.apache.commons.io.FileUtils;
import org.rocksdb.*;
import org.rocksdb.util.SizeUnit;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class RocksDBConnection implements DBConnection {

public static final String SCHEMA = "rocksdb";

public static final String PROTOCOL_SPLIT = "://";

public static final String ROCKSDB_PROTOCOL = SCHEMA + PROTOCOL_SPLIT;

static {
RocksDB.loadLibrary();
}

private RocksDB rocksDB;

@Override
public String dbSchema() {
return SCHEMA;
}

@Override
public DBConnection initDbUrl(String dbUrl) {
if (!dbUrl.startsWith(dbSchema())) {
throw new IllegalStateException(String.format("Unsupport DBConnection by URL {%s} !!!", dbUrl));
}
String dbSavePath = dbUrl.split(PROTOCOL_SPLIT)[1];
initDBConnection(dbSavePath);
return this;
}

@Override
public void put(String key, String value) {
if (this.rocksDB == null) {
throw new IllegalStateException("Rocksdb is NULL, Please initDbUrl first !!!");
}
try {
this.rocksDB.put(key.getBytes(UTF_8), value.getBytes(UTF_8));
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

@Override
public void put(String key, Object value, Class<?> type) {
// 使用JSON序列化
String json = JSON.toJSONString(value);
put(key, json);
}

@Override
public String get(String key) {
try {
byte[] value = this.rocksDB.get(key.getBytes(UTF_8));
if (value != null && value.length > 0) {
return new String(value, UTF_8);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
return null;
}

@Override
public boolean exist(String dbUrl) {
// 首先该dbUrl是Rocksdb
if (dbUrl.startsWith(ROCKSDB_PROTOCOL)) {
// 判断File是否存在,并且是文件夹
File dbPath = new File(dbUrl.substring(ROCKSDB_PROTOCOL.length()));
if (dbPath.exists() && dbPath.isDirectory()) {
return true;
}
}
return false;
}

private void initDBConnection(String dbUrl) {
try {
File dbPath = new File(dbUrl);
File dbParentPath = dbPath.getParentFile();
if (!dbParentPath.exists()) {
FileUtils.forceMkdir(dbParentPath);
}
this.rocksDB = RocksDB.open(initOptions(), dbUrl);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

private Options initOptions() {
final Filter bloomFilter = new BloomFilter(32);
final BlockBasedTableConfig tableOptions = new BlockBasedTableConfig()
.setFilter(bloomFilter)
.setBlockSize(4 * SizeUnit.KB)
.setBlockSizeDeviation(10)
.setBlockCacheSize(64 * SizeUnit.GB)
.setNoBlockCache(false)
.setCacheIndexAndFilterBlocks(true)
.setBlockRestartInterval(16)
;
final List<CompressionType> compressionLevels = new ArrayList<>();
compressionLevels.add(CompressionType.NO_COMPRESSION); // 0-1
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 1-2
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 2-3
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 3-4
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 4-5
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 5-6
compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 6-7

Options options = new Options()
.setAllowConcurrentMemtableWrite(true)
.setEnableWriteThreadAdaptiveYield(true)
.setCreateIfMissing(true)
.setMaxWriteBufferNumber(3)
.setTableFormatConfig(tableOptions)
.setMaxBackgroundCompactions(10)
.setMaxBackgroundFlushes(4)
.setBloomLocality(10)
.setMinWriteBufferNumberToMerge(4)
.setCompressionPerLevel(compressionLevels)
.setNumLevels(7)
.setCompressionType(CompressionType.SNAPPY_COMPRESSION)
.setCompactionStyle(CompactionStyle.UNIVERSAL)
.setMemTableConfig(new SkipListMemTableConfig())
;
return options;
}

public static void main(String[] args) {
String path = "rocksdb:///zhangsan/lisi";
System.out.println(path.substring(ROCKSDB_PROTOCOL.length()));
}
}

+ 4
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java View File

@@ -0,0 +1,4 @@
package com.jd.blockchain.ump.dao;

public interface UmpDao {
}

+ 115
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java View File

@@ -0,0 +1,115 @@
package com.jd.blockchain.ump.dao;

import com.jd.blockchain.ump.model.UmpConstant;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Repository;

import java.io.File;

@Repository
public class UmpDaoHandler implements UmpDao, CommandLineRunner, DBConnection {

public final String PROJECT_FLAG = "#project#";

private static final String PROTOCOL_FILE = "file:";

private static final String INNER_FILE_SEPARATOR = "!";

private static final String PROTOCOL_SEPARATOR = "://";

private DBConnection dbConnection;

@Override
public void run(String... args) {

String dbUrl = RocksDBConnection.SCHEMA + PROTOCOL_SEPARATOR +
PROJECT_FLAG + File.separator + UmpConstant.DB_NAME;

if (args != null && args.length > 0) {
for (String arg : args) {
if (arg.startsWith("--db.url")) {
dbUrl = arg.split("=")[1];
}
}
}

dbConnection = DBConnectionProvider.dbConnection(realPath(dbUrl));

initProjectPath();
}

private void initProjectPath() {
UmpConstant.PROJECT_PATH = projectPath();
System.out.printf("Init Project Path = %s \r\n", UmpConstant.PROJECT_PATH);
}

@Override
public String dbSchema() {
return null;
}

@Override
public DBConnection initDbUrl(String dbUrl) {
return dbConnection;
}

@Override
public void put(String key, String value) {
dbConnection.put(key, value);
}

@Override
public void put(String key, Object value, Class<?> type) {
dbConnection.put(key, value, type);
}

@Override
public String get(String key) {
return dbConnection.get(key);
}

@Override
public boolean exist(String dbUrl) {
try {
return dbConnection.exist(dbUrl);
} catch (Exception e) {
// 不关心异常
System.err.println(e);
return false;
}
}

private String realPath(String dbUrl) {
if (dbUrl.contains(PROJECT_FLAG)) {
// 获取当前jar包路径
try {
String projectPath = projectPath();
return dbUrl.replaceAll(PROJECT_FLAG, projectPath);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return dbUrl;
}

private String projectPath() {
File jarDirectory = new File(jarRootPath());
return jarDirectory.getParentFile().getParentFile().getPath();
}

private String jarRootPath() {
// 获取Jar包所在路径
String jarRootPath = UmpDaoHandler.class.getProtectionDomain().getCodeSource().getLocation().getPath();

// 处理打包到SpringBoot后路径问题:file:
if (jarRootPath.startsWith(PROTOCOL_FILE)) {
jarRootPath = jarRootPath.substring(PROTOCOL_FILE.length());
}
// 处理打包到SpringBoot后内部分隔符问题:!
if (jarRootPath.contains(INNER_FILE_SEPARATOR)) {
jarRootPath = jarRootPath.substring(0, jarRootPath.indexOf(INNER_FILE_SEPARATOR));
}

return jarRootPath;
}
}

+ 47
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java View File

@@ -0,0 +1,47 @@
package com.jd.blockchain.ump.model;

public class MasterAddr {

private String ipAddr;

private int port;

public MasterAddr() {
}

public MasterAddr(String ipAddr, int port) {
this.ipAddr = ipAddr;
this.port = port;
}

public String getIpAddr() {
return ipAddr;
}

public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}

public int getPort() {
return port;
}

public void setPort(int port) {
this.port = port;
}

public static MasterAddr newInstance(String ipAddr, int port) {
return new MasterAddr(ipAddr, port);
}

public String toHttpUrl() {
return "http://" + ipAddr + ":" + port;
}

public boolean legal() {
if (this.ipAddr == null || this.ipAddr.length() == 0 || this.port == 0) {
return false;
}
return true;
}
}

+ 88
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java View File

@@ -0,0 +1,88 @@
package com.jd.blockchain.ump.model;

import java.util.ArrayList;
import java.util.List;

public class PartiNode {

private int id;

private String name;

private String pubKey;

private String initHost;

private int initPort;

private boolean isSecure;

public List<String> toConfigChars() {

List<String> configCharList = new ArrayList<>();

configCharList.add(formatConfig(UmpConstant.PARTINODE_NAME_FORMAT, name));

configCharList.add(formatConfig(UmpConstant.PARTINODE_PUBKEY_FORMAT, pubKey));

configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_HOST_FORMAT, initHost));

configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_PORT_FORMAT, initPort));

configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_SECURE_FORMAT, isSecure));

return configCharList;
}

private String formatConfig(String formatter, Object value) {
return String.format(formatter, id) + "=" + value;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

public String getInitHost() {
return initHost;
}

public void setInitHost(String initHost) {
this.initHost = initHost;
}

public int getInitPort() {
return initPort;
}

public void setInitPort(int initPort) {
this.initPort = initPort;
}

public boolean isSecure() {
return isSecure;
}

public void setSecure(boolean secure) {
isSecure = secure;
}
}

+ 217
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java View File

@@ -0,0 +1,217 @@
package com.jd.blockchain.ump.model;

import com.jd.blockchain.ump.model.config.LedgerInitConfig;
import com.jd.blockchain.ump.model.config.MasterConfig;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.config.PeerSharedConfig;
import com.jd.blockchain.ump.model.state.LedgerMasterInstall;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PeerSharedConfigs {

/**
* 默认的一次邀请码最长等待时间,单位分钟,默认30分钟
*/
private static final int MAX_WAIT_MINUTE = 30;

private CountDownLatch latch = null;

private Lock lock = new ReentrantLock();

private Lock waitLock = new ReentrantLock();

private Condition sizeCondition = waitLock.newCondition();

private List<PeerLocalConfig> sharedConfigs = new ArrayList<>();

private int waitNodeSize;

private String consensusProvider;

private String sharedKey;

private String ledgerName;

private LedgerInitConfig ledgerInitConfig;

public synchronized PeerSharedConfigs addConfig(PeerLocalConfig sharedConfig) {

// 判断内容是否存在重复
for (PeerSharedConfig innerSharedConfig : sharedConfigs) {
if (innerSharedConfig.getName().equals(sharedConfig.getName())
|| innerSharedConfig.getPubKey().equals(sharedConfig.getPubKey())) {
return null;
}
}

if (sharedConfig.getMasterConfig().isMaster()) {
initDataByMaster(sharedConfig);
}

sharedConfigs.add(sharedConfig);

if (latch != null) {
// 不管是Master还是普通用户都需要-1
latch.countDown();
}
return this;
}

/**
* 由Master节点传入的信息对数据进行初始化
*
* @param sharedConfig
*/
private void initDataByMaster(PeerLocalConfig sharedConfig) {

MasterConfig masterConfig = sharedConfig.getMasterConfig();

// master需要对数据进行组织
if (latch == null) {
latch = new CountDownLatch(masterConfig.getNodeSize() - sharedConfigs.size());
}
if (consensusProvider == null) {
consensusProvider = sharedConfig.getConsensusProvider();
}
if (sharedKey == null) {
sharedKey = sharedConfig.getSharedKey();
}
if (ledgerName == null) {
ledgerName = masterConfig.getLedgerName();
}
waitNodeSize = masterConfig.getNodeSize();
}

/**
* 线程等待
* 一直处于等待状态(30分钟),直到有线程调用single方法
*
*/
public void await() {
waitLock.lock();
try {
sizeCondition.await(MAX_WAIT_MINUTE, TimeUnit.MINUTES);
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
waitLock.unlock();
}
}

/**
* 通知其他线程等待状态结束
*
*/
public void single() {
waitLock.lock();
try {
sizeCondition.signalAll();
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
waitLock.unlock();
}
}

/**
* Master线程调用,等待数据满足后通知其他线程
*
*/
public void waitAndNotify() {
if (this.latch == null) {
throw new IllegalStateException("Please init MasterConfig first !!!");
}
try {
latch.await(MAX_WAIT_MINUTE, TimeUnit.MINUTES);
single(); // 通知其他线程释放
} catch (Exception e) {
if (sharedConfigs.size() >= waitNodeSize) {
// 成功
single();
}
}
}

public synchronized LedgerInitConfig ledgerInitConfig(String seed, String createTime) {
if (ledgerInitConfig != null) {
return ledgerInitConfig;
}

// 处理该ledgerInitConfig
ledgerInitConfig = new LedgerInitConfig(seed, ledgerName, createTime, consensusProvider, waitNodeSize);

// 添加参与方
for (int i = 0; i < sharedConfigs.size(); i++) {
PeerLocalConfig sharedConfig = sharedConfigs.get(i);
ledgerInitConfig.addPartiNode(sharedConfig.toPartiNode(i));
}

return ledgerInitConfig;
}

public String getConsensusProvider() {
return consensusProvider;
}

public void setConsensusProvider(String consensusProvider) {
this.consensusProvider = consensusProvider;
}

public String getSharedKey() {
return sharedKey;
}

public void setSharedKey(String sharedKey) {
this.sharedKey = sharedKey;
}

public Lock getLock() {
return lock;
}

public String getLedgerName() {
return ledgerName;
}

public void setLedgerName(String ledgerName) {
this.ledgerName = ledgerName;
}

public List<PeerLocalConfig> getSharedConfigs() {
return sharedConfigs;
}

public void setSharedConfigs(List<PeerLocalConfig> sharedConfigs) {
this.sharedConfigs = sharedConfigs;
}

public LedgerInitConfig getLedgerInitConfig() {
return ledgerInitConfig;
}

public void setLedgerInitConfig(LedgerInitConfig ledgerInitConfig) {
this.ledgerInitConfig = ledgerInitConfig;
}

public LedgerMasterInstall toLedgerMasterInstall() {

// String ledgerKey, String sharedKey, int totalNodeSize
LedgerMasterInstall masterInstall = new LedgerMasterInstall(
ledgerInitConfig.ledgerKey(), sharedConfigs.size())
.initCreateTime(ledgerInitConfig.getCreateTime());

for (PeerLocalConfig sharedConfig : sharedConfigs) {

masterInstall.add(sharedConfig.toPeerInstall());
}

return masterInstall;
}
}

+ 104
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java View File

@@ -0,0 +1,104 @@
package com.jd.blockchain.ump.model;

import java.io.File;

public class UmpConstant {

public static String PROJECT_PATH = "";

public static final String DB_NAME = "jumpdb";

public static final String URL_SEPARATOR = "/";

public static final String URL_MASTER = "/master";

public static final String URL_PEER = "/peer";

public static final String PRIVATE_KEY_SUFFIX = ".priv";

public static final String PUBLIC_KEY_SUFFIX = ".priv";

public static final String PWD_SUFFIX = ".pwd";

public static final String REQUEST_SHARED_URL = URL_MASTER + URL_SEPARATOR + "share";

public static final String REQUEST_STATE_URL = URL_MASTER + URL_SEPARATOR + "receive";

public static final String PARTINODE_COUNT = "cons_parti.count";

public static final String PARTINODE_FORMAT = "cons_parti.%s";

public static final String PARTINODE_NAME_FORMAT = PARTINODE_FORMAT + ".name";

public static final String PARTINODE_PUBKEY_FORMAT = PARTINODE_FORMAT + ".pubkey";

public static final String PARTINODE_INIT_FORMAT = PARTINODE_FORMAT + ".initializer";

public static final String PARTINODE_INIT_HOST_FORMAT = PARTINODE_INIT_FORMAT + ".host";

public static final String PARTINODE_INIT_PORT_FORMAT = PARTINODE_INIT_FORMAT + ".port";

public static final String PARTINODE_INIT_SECURE_FORMAT = PARTINODE_INIT_FORMAT + ".secure";

public static final String LEDGER_PREFIX = "ledger";

public static final String LEDGER_SEED_PREFIX = LEDGER_PREFIX + ".seed";

public static final String LEDGER_NAME_PREFIX = LEDGER_PREFIX + ".name";

public static final String CREATE_TIME_PREFIX = "created-time";

public static final String CONSENSUS_PREFIX = "consensus";

public static final String CONSENSUS_PROVIDER_PREFIX = CONSENSUS_PREFIX + ".service-provider";

public static final String CONSENSUS_CONF_PREFIX = CONSENSUS_PREFIX + ".conf";

public static final String CRYPTO_PREFIX = "crypto";

public static final String CRYPTO_PROVIDERS_PREFIX = CRYPTO_PREFIX + ".service-providers";

public static final String LOCAL_PREFIX = "local";

public static final String LOCAL_PARTI_PREFIX = LOCAL_PREFIX + ".parti";

public static final String LOCAL_PARTI_ID_PREFIX = LOCAL_PARTI_PREFIX + ".id";

public static final String LOCAL_PARTI_PUBKEY_PREFIX = LOCAL_PARTI_PREFIX + ".pubkey";

public static final String LOCAL_PARTI_PRIVKEY_PREFIX = LOCAL_PARTI_PREFIX + ".privkey";

public static final String LOCAL_PARTI_PWD_PREFIX = LOCAL_PARTI_PREFIX + ".pwd";

public static final String LEDGER_BINDING_OUT_PREFIX = LEDGER_PREFIX + ".binding.out";

public static final String LEDGER_DB_URI_PREFIX = LEDGER_PREFIX + ".db.uri";

public static final String LEDGER_DB_PWD_PREFIX = LEDGER_PREFIX + ".db.pwd";

public static final String CMD_LEDGER_INIT = "/bin/bash %s -monitor";

public static final String CMD_START_UP_FORMAT = "/bin/bash %s";

public static final String PATH_BIN = File.separator + "bin";

public static final String PATH_LEDGER_INIT_BIN = PATH_BIN + File.separator + "ledger-init.sh";

public static final String PATH_STARTUP_BIN = PATH_BIN + File.separator + "startup.sh";

public static final String PATH_LIBS = File.separator + "libs";

public static final String PATH_SYSTEM = File.separator + "system";

public static final String PATH_CONFIG = File.separator + "config";

public static final String PATH_CONFIG_KEYS = PATH_CONFIG + File.separator + "keys";

public static final String PATH_LEDGER_BINDING_CONFIG = PATH_CONFIG + File.separator + "ledger-binding.conf";

public static final String PATH_CONFIG_INIT = PATH_CONFIG + File.separator + "init";

public static final String PATH_LOCAL_CONFIG = PATH_CONFIG_INIT + File.separator + "local.conf";

public static final String PATH_LEDGER_INIT_CONFIG = PATH_CONFIG_INIT + File.separator + "ledger.init";
}

+ 50
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java View File

@@ -0,0 +1,50 @@
package com.jd.blockchain.ump.model;

import com.jd.blockchain.ump.model.state.InstallSchedule;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class UmpQueue {

private final BlockingQueue<InstallScheduleRequest> QUEUE_INSTALL_SCHEDULE = new LinkedBlockingQueue<>();

public void put(InstallSchedule installSchedule, MasterAddr masterAddr) throws InterruptedException {
QUEUE_INSTALL_SCHEDULE.put(new InstallScheduleRequest(installSchedule, masterAddr));
}

public InstallScheduleRequest take() throws InterruptedException {
return QUEUE_INSTALL_SCHEDULE.take();
}

public static class InstallScheduleRequest {

private InstallSchedule installSchedule;

private MasterAddr masterAddr;

public InstallScheduleRequest() {
}

public InstallScheduleRequest(InstallSchedule installSchedule, MasterAddr masterAddr) {
this.installSchedule = installSchedule;
this.masterAddr = masterAddr;
}

public InstallSchedule getInstallSchedule() {
return installSchedule;
}

public void setInstallSchedule(InstallSchedule installSchedule) {
this.installSchedule = installSchedule;
}

public MasterAddr getMasterAddr() {
return masterAddr;
}

public void setMasterAddr(MasterAddr masterAddr) {
this.masterAddr = masterAddr;
}
}
}

+ 24
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java View File

@@ -0,0 +1,24 @@
package com.jd.blockchain.ump.model.config;

public class ConsensusConfig {

private String confPath;

private byte[] content;

public String getConfPath() {
return confPath;
}

public void setConfPath(String confPath) {
this.confPath = confPath;
}

public byte[] getContent() {
return content;
}

public void setContent(byte[] content) {
this.content = content;
}
}

+ 46
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java View File

@@ -0,0 +1,46 @@
package com.jd.blockchain.ump.model.config;

public class LedgerConfig {

private LedgerInitConfig initConfig;

/**
* 共识文件配置信息,Base58格式
*/
private String consensusConfig;


public LedgerConfig() {
}

/**
* 包装一下,使用JSON处理过程
*
* @param ledgerConfig
*/
public LedgerConfig(LedgerConfig ledgerConfig) {
this.consensusConfig = ledgerConfig.getConsensusConfig();

}

public LedgerConfig(LedgerInitConfig initConfig, String consensusConfig) {
this.initConfig = initConfig;
this.consensusConfig = consensusConfig;
}

public LedgerInitConfig getInitConfig() {
return initConfig;
}

public void setInitConfig(LedgerInitConfig initConfig) {
this.initConfig = initConfig;
}

public String getConsensusConfig() {
return consensusConfig;
}

public void setConsensusConfig(String consensusConfig) {
this.consensusConfig = consensusConfig;
}
}

+ 92
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java View File

@@ -0,0 +1,92 @@
package com.jd.blockchain.ump.model.config;

import com.jd.blockchain.ump.model.MasterAddr;

public class LedgerIdentification {

private String ledgerKey;

private String ledgerAndNodeKey;

private MasterAddr masterAddr;

private int nodeId;

private PeerLocalConfig localConfig;

private LedgerInitConfig initConfig;

public LedgerIdentification() {
}

public LedgerIdentification(int nodeId, PeerLocalConfig localConfig, MasterAddr masterAddr, String ledgerAndNodeKey, LedgerInitConfig initConfig) {
this.nodeId = nodeId;
this.localConfig = localConfig;
this.masterAddr = masterAddr;
this.ledgerKey = initConfig.ledgerKey();
this.ledgerAndNodeKey = ledgerAndNodeKey;
this.initConfig = initConfig;
init();
}

private void init() {
// 初始化部分配置信息
MasterConfig masterConfig = localConfig.getMasterConfig();
// 设置账本名称
if (masterConfig.getLedgerName() == null || masterConfig.getLedgerName().length() == 0) {
masterConfig.setLedgerName(initConfig.getName());
}
// 设置NodeSize
if (masterConfig.getNodeSize() == 0) {
masterConfig.setNodeSize(initConfig.getNodeSize());
}
}

public String getLedgerKey() {
return ledgerKey;
}

public void setLedgerKey(String ledgerKey) {
this.ledgerKey = ledgerKey;
}

public String getLedgerAndNodeKey() {
return ledgerAndNodeKey;
}

public void setLedgerAndNodeKey(String ledgerAndNodeKey) {
this.ledgerAndNodeKey = ledgerAndNodeKey;
}

public MasterAddr getMasterAddr() {
return masterAddr;
}

public void setMasterAddr(MasterAddr masterAddr) {
this.masterAddr = masterAddr;
}

public int getNodeId() {
return nodeId;
}

public void setNodeId(int nodeId) {
this.nodeId = nodeId;
}

public PeerLocalConfig getLocalConfig() {
return localConfig;
}

public void setLocalConfig(PeerLocalConfig localConfig) {
this.localConfig = localConfig;
}

public LedgerInitConfig getInitConfig() {
return initConfig;
}

public void setInitConfig(LedgerInitConfig initConfig) {
this.initConfig = initConfig;
}
}

+ 141
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java View File

@@ -0,0 +1,141 @@
package com.jd.blockchain.ump.model.config;

import com.jd.blockchain.ump.model.PartiNode;
import com.jd.blockchain.ump.model.UmpConstant;

import java.util.ArrayList;
import java.util.List;

public class LedgerInitConfig {

private String seed;

private String name;

private String createTime;

private String consensusProvider;

private int nodeSize;

private String cryptoProviders =
"com.jd.blockchain.crypto.service.classic.ClassicCryptoService, " +
"com.jd.blockchain.crypto.service.sm.SMCryptoService";


private List<PartiNode> partiNodes = new ArrayList<>();

public LedgerInitConfig() {
}

public LedgerInitConfig(String seed, String name, String createTime, String consensusProvider, int nodeSize) {
this.seed = seed;
this.name = name;
this.createTime = createTime;
this.consensusProvider = consensusProvider;
this.nodeSize = nodeSize;
}

public List<String> toConfigChars(String consensusConf) {

List<String> configChars = new ArrayList<>();

configChars.add(toConfigChars(UmpConstant.LEDGER_SEED_PREFIX, seed));

configChars.add(toConfigChars(UmpConstant.LEDGER_NAME_PREFIX, name));

configChars.add(toConfigChars(UmpConstant.CREATE_TIME_PREFIX, createTime));

configChars.add(toConfigChars(UmpConstant.CONSENSUS_PROVIDER_PREFIX, consensusProvider));

configChars.add(toConfigChars(UmpConstant.CONSENSUS_CONF_PREFIX, consensusConf));

configChars.add(toConfigChars(UmpConstant.CRYPTO_PROVIDERS_PREFIX, cryptoProviders));

configChars.add(toConfigChars(UmpConstant.PARTINODE_COUNT, partiNodes.size()));

for (PartiNode partiNode : partiNodes) {
configChars.addAll(partiNode.toConfigChars());
}

return configChars;
}

public String ledgerKey() {
return seed + "-" + name;
}

public int nodeId(String pubKey) {
for (int i = 0; i < partiNodes.size(); i++) {
PartiNode partiNode = partiNodes.get(i);
if (partiNode.getPubKey().equals(pubKey)) {
return i;
}
}
throw new IllegalStateException(String.format("Can not find PubKey = %s !", pubKey));
}

private String toConfigChars(String prefix, Object value) {
return prefix + "=" + value;
}

public String getSeed() {
return seed;
}

public void setSeed(String seed) {
this.seed = seed;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getCreateTime() {
return createTime;
}

public void setCreateTime(String createTime) {
this.createTime = createTime;
}

public String getConsensusProvider() {
return consensusProvider;
}

public void setConsensusProvider(String consensusProvider) {
this.consensusProvider = consensusProvider;
}

public int getNodeSize() {
return nodeSize;
}

public void setNodeSize(int nodeSize) {
this.nodeSize = nodeSize;
}

public String getCryptoProviders() {
return cryptoProviders;
}

public void setCryptoProviders(String cryptoProviders) {
this.cryptoProviders = cryptoProviders;
}

public List<PartiNode> getPartiNodes() {
return partiNodes;
}

public void setPartiNodes(List<PartiNode> partiNodes) {
this.partiNodes = partiNodes;
}

public void addPartiNode(PartiNode partiNode) {
this.partiNodes.add(partiNode);
}
}

+ 89
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java View File

@@ -0,0 +1,89 @@
package com.jd.blockchain.ump.model.config;

import com.jd.blockchain.ump.model.MasterAddr;

public class MasterConfig {

private String masterAddr;

private int masterPort;

private String ledgerName;

private int nodeSize;

private boolean isMaster = false;

public MasterConfig() {
}

public String getMasterAddr() {
return masterAddr;
}

public void setMasterAddr(String masterAddr) {
this.masterAddr = masterAddr;
}

public int getMasterPort() {
return masterPort;
}

public void setMasterPort(int masterPort) {
this.masterPort = masterPort;
}

public String getLedgerName() {
return ledgerName;
}

public void setLedgerName(String ledgerName) {
this.ledgerName = ledgerName;
}

public int getNodeSize() {
return nodeSize;
}

public void setNodeSize(int nodeSize) {
this.nodeSize = nodeSize;
}

public boolean isMaster() {
return isMaster;
}

public void setMaster(boolean master) {
isMaster = master;
}

public MasterConfig buildIsMaster(boolean isMaster) {
setMaster(isMaster);
return this;
}

public MasterConfig buildNodeSize(int nodeSize) {
setNodeSize(nodeSize);
return this;
}

public MasterConfig buildLedgerName(String ledgerName) {
setLedgerName(ledgerName);
return this;
}

public MasterConfig buildMasterAddr(String masterAddr) {
setMasterAddr(masterAddr);
return this;
}

public MasterConfig buildMasterPort(int masterPort) {
setMasterPort(masterPort);
return this;
}


public MasterAddr toMasterAddr() {
return MasterAddr.newInstance(masterAddr, masterPort);
}
}

+ 160
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java View File

@@ -0,0 +1,160 @@
package com.jd.blockchain.ump.model.config;


import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.PartiNode;
import com.jd.blockchain.ump.model.UmpConstant;
import com.jd.blockchain.ump.model.state.LedgerMasterInstall;
import com.jd.blockchain.ump.model.state.LedgerPeerInstall;

import java.io.File;

/**
* Peer本地配置信息
*/
public class PeerLocalConfig extends PeerSharedConfig {

private String peerPath;

private String consensusConf = "bftsmart.config"; // 默认为bftsmart配置

private String privKey;

private String encodePwd;

private String dbName;

private MasterConfig masterConfig;

public String bindingOutPath() {
return peerPath + UmpConstant.PATH_CONFIG;
}

public String localConfPath() {
return peerPath + UmpConstant.PATH_LOCAL_CONFIG;
}

public String ledgerInitConfPath() {
return peerPath + UmpConstant.PATH_LEDGER_INIT_CONFIG;
}

public String consensusConfPath() {
return peerPath + UmpConstant.PATH_CONFIG_INIT + File.separator + consensusConf;
}

public String libsDirectory() {
return peerPath + UmpConstant.PATH_LIBS;
}

public String getPeerPath() {
return peerPath;
}

public void setPeerPath(String peerPath) {
this.peerPath = peerPath;
}

public String getConsensusConf() {
return consensusConf;
}

public void setConsensusConf(String consensusConf) {
this.consensusConf = consensusConf;
}

public String getPrivKey() {
return privKey;
}

public void setPrivKey(String privKey) {
this.privKey = privKey;
}

public String getEncodePwd() {
return encodePwd;
}

public void setEncodePwd(String encodePwd) {
this.encodePwd = encodePwd;
}

public String getDbName() {
return dbName;
}

public void setDbName(String dbName) {
this.dbName = dbName;
}

public MasterConfig getMasterConfig() {
return masterConfig;
}

public void setMasterConfig(MasterConfig masterConfig) {
this.masterConfig = masterConfig;
}

public synchronized PartiNode toPartiNode(int nodeId) {
if (this.partiNode != null) {
return partiNode;
}
partiNode = new PartiNode();
partiNode.setId(nodeId);
partiNode.setName(name);
partiNode.setInitHost(initAddr);
partiNode.setInitPort(initPort);
partiNode.setPubKey(pubKey);
partiNode.setSecure(false);
return partiNode;
}

public LedgerPeerInstall toLedgerPeerInstall(int totalNodeSize) {
return new LedgerPeerInstall(name, sharedKey, peerPath, totalNodeSize);
}

public LedgerMasterInstall.PeerInstall toPeerInstall() {
return new LedgerMasterInstall.PeerInstall(name, pubKey, initAddr, initPort, consensusNode, consensusProvider);
}

public void verify() {

// 主要校验dbName地址是否存在
String dbPath = peerPath + File.separator + dbName;
File dbDir = new File(dbPath);
if (dbDir.exists()) {
throw new IllegalStateException(String.format("DB name = %s, path = %s is exist !!!", dbName, dbPath));
}

// 其他配置信息是否正确
if (masterConfig == null) {
// Master不能为空
throw new IllegalStateException("Master Config can not be NULL !!!");
}
if (masterConfig.isMaster()) {
// 账本名字及NodeSize不能为空
if (masterConfig.getLedgerName() == null || masterConfig.getLedgerName().length() == 0) {
throw new IllegalStateException("Master 's LedgerName can not be empty !!!");
}
if (masterConfig.getNodeSize() == 0) {
throw new IllegalStateException("Master 's NodeSize can not be Zero !!!");
}
} else {
// 普通Peer需要检查Master的IP地址及端口
if (masterConfig.getMasterAddr() == null || masterConfig.getMasterAddr().length() == 0) {
throw new IllegalStateException("Master 's IP Address can not be empty !!!");
}

if (masterConfig.getMasterPort() == 0) {
throw new IllegalStateException("Master 's Port must be Set !!!");
}
}
}

public boolean master() {
return masterConfig.isMaster();
}

public MasterAddr masterAddr() {
return masterConfig.toMasterAddr();
}
}

+ 86
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java View File

@@ -0,0 +1,86 @@
package com.jd.blockchain.ump.model.config;

import com.jd.blockchain.ump.model.PartiNode;

public class PeerSharedConfig {

public static final String DB_ROCKSDB_SUFFIX = "rocksdb_";

protected String sharedKey;

protected String name;

protected String initAddr;

protected String pubKey;

protected int initPort;

protected String consensusNode;

protected String consensusProvider = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider";

protected PartiNode partiNode;

public String getSharedKey() {
return sharedKey;
}

public void setSharedKey(String sharedKey) {
this.sharedKey = sharedKey;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getInitAddr() {
return initAddr;
}

public void setInitAddr(String initAddr) {
this.initAddr = initAddr;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

public int getInitPort() {
return initPort;
}

public void setInitPort(int initPort) {
this.initPort = initPort;
}

public String addr() {
return initAddr + "-" + initPort;
}

public String getConsensusNode() {
return consensusNode;
}

public void setConsensusNode(String consensusNode) {
this.consensusNode = consensusNode;
}

public String getConsensusProvider() {
return consensusProvider;
}

public void setConsensusProvider(String consensusProvider) {
this.consensusProvider = consensusProvider;
}


}

+ 180
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java View File

@@ -0,0 +1,180 @@
package com.jd.blockchain.ump.model.config;


import com.jd.blockchain.ump.model.UmpConstant;
import com.jd.blockchain.ump.model.user.UserKeys;

/**
*
*/
public class PeerSharedConfigVv {

private String sharedKey;

private String name;

private int userId;

private String pubKey;

private String initAddr;

private int initPort;

private String consensusNode;

private String peerPath = UmpConstant.PROJECT_PATH;

private String dbName;

private int nodeSize;

private String masterAddr;

private int masterPort;

private String ledgerName;

public String getSharedKey() {
return sharedKey;
}

public void setSharedKey(String sharedKey) {
this.sharedKey = sharedKey;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getUserId() {
return userId;
}

public void setUserId(int userId) {
this.userId = userId;
}

public String getInitAddr() {
return initAddr;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

public void setInitAddr(String initAddr) {
this.initAddr = initAddr;
}

public int getInitPort() {
return initPort;
}

public void setInitPort(int initPort) {
this.initPort = initPort;
}

public String getConsensusNode() {
return consensusNode;
}

public void setConsensusNode(String consensusNode) {
this.consensusNode = consensusNode;
}

public String getPeerPath() {
return peerPath;
}

public void setPeerPath(String peerPath) {
this.peerPath = peerPath;
}

public String getDbName() {
return dbName;
}

public void setDbName(String dbName) {
this.dbName = dbName;
}

public int getNodeSize() {
return nodeSize;
}

public void setNodeSize(Integer nodeSize) {
this.nodeSize = nodeSize;
}

public String getMasterAddr() {
return masterAddr;
}

public void setMasterAddr(String masterAddr) {
this.masterAddr = masterAddr;
}

public int getMasterPort() {
return masterPort;
}

public void setMasterPort(Integer masterPort) {
this.masterPort = masterPort;
}

public String getLedgerName() {
return ledgerName;
}

public void setLedgerName(String ledgerName) {
this.ledgerName = ledgerName;
}

public PeerLocalConfig toPeerLocalConfig(UserKeys userKeys) {

PeerLocalConfig localConfig = new PeerLocalConfig();

localConfig.setSharedKey(sharedKey);
localConfig.setName(name);
localConfig.setInitAddr(initAddr);
localConfig.setInitPort(initPort);
localConfig.setConsensusNode(consensusNode);
localConfig.setPubKey(userKeys.getPubKey());
localConfig.setPrivKey(userKeys.getPrivKey());
localConfig.setEncodePwd(userKeys.getEncodePwd());
localConfig.setPeerPath(peerPath);
localConfig.setDbName(dbName);

MasterConfig masterConfig = new MasterConfig();

if (master()) {
masterConfig.buildIsMaster(true)
.buildLedgerName(ledgerName)
.buildNodeSize(nodeSize);
} else {
masterConfig.buildIsMaster(false)
.buildMasterAddr(masterAddr)
.buildMasterPort(masterPort);
}

localConfig.setMasterConfig(masterConfig);

return localConfig;
}

private boolean master() {
if (masterAddr == null || masterAddr.length() == 0) {
return true;
}
return false;
}
}

+ 21
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java View File

@@ -0,0 +1,21 @@
package com.jd.blockchain.ump.model.state;

public class InstallProcess {

private String content;

public InstallProcess() {
}

public InstallProcess(String content) {
this.content = content;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

+ 54
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java View File

@@ -0,0 +1,54 @@
package com.jd.blockchain.ump.model.state;

public class InstallSchedule {

private String ledgerKey;

private String ledgerAndNodeKey;

private InstallProcess process;

private ScheduleState state;

public InstallSchedule() {
}

public InstallSchedule(String ledgerKey, String ledgerAndNodeKey, InstallProcess process, ScheduleState state) {
this.ledgerKey = ledgerKey;
this.ledgerAndNodeKey = ledgerAndNodeKey;
this.process = process;
this.state = state;
}

public String getLedgerKey() {
return ledgerKey;
}

public void setLedgerKey(String ledgerKey) {
this.ledgerKey = ledgerKey;
}

public String getLedgerAndNodeKey() {
return ledgerAndNodeKey;
}

public void setLedgerAndNodeKey(String ledgerAndNodeKey) {
this.ledgerAndNodeKey = ledgerAndNodeKey;
}

public InstallProcess getProcess() {
return process;
}

public void setProcess(InstallProcess process) {
this.process = process;
}

public ScheduleState getState() {
return state;
}

public void setState(ScheduleState state) {
this.state = state;
}
}

+ 33
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java View File

@@ -0,0 +1,33 @@
package com.jd.blockchain.ump.model.state;

import java.util.Set;

public class LedgerBindingConf {

private Set<String> ledgerHashs;

private long lastTime;

public LedgerBindingConf() {
}

public LedgerBindingConf(long lastTime) {
this.lastTime = lastTime;
}

public Set<String> getLedgerHashs() {
return ledgerHashs;
}

public void setLedgerHashs(Set<String> ledgerHashs) {
this.ledgerHashs = ledgerHashs;
}

public long getLastTime() {
return lastTime;
}

public void setLastTime(long lastTime) {
this.lastTime = lastTime;
}
}

+ 101
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java View File

@@ -0,0 +1,101 @@
package com.jd.blockchain.ump.model.state;

public class LedgerInited {

private String ledgerHash;

private String ledgerName;

private String partiName;

private String partiAddress;

private String dbUri;

private StartupState startupState = StartupState.UNKNOWN;

public LedgerInited() {
}

public LedgerInited(String ledgerHash) {
this.ledgerHash = ledgerHash;
}

public String getLedgerHash() {
return ledgerHash;
}

public void setLedgerHash(String ledgerHash) {
this.ledgerHash = ledgerHash;
}

public String getLedgerName() {
return ledgerName;
}

public void setLedgerName(String ledgerName) {
this.ledgerName = ledgerName;
}

public String getPartiName() {
return partiName;
}

public void setPartiName(String partiName) {
this.partiName = partiName;
}

public String getPartiAddress() {
return partiAddress;
}

public void setPartiAddress(String partiAddress) {
this.partiAddress = partiAddress;
}

public String getDbUri() {
return dbUri;
}

public void setDbUri(String dbUri) {
this.dbUri = dbUri;
}

public StartupState getStartupState() {
return startupState;
}

public void setStartupState(StartupState startupState) {
this.startupState = startupState;
}

public LedgerInited buildLedgerHash(String ledgerHash) {
setLedgerHash(ledgerHash);
return this;
}

public LedgerInited buildLedgerName(String ledgerName) {
setLedgerName(ledgerName);
return this;
}

public LedgerInited buildPartiName(String partiName) {
setPartiName(partiName);
return this;
}

public LedgerInited buildPartiAddress(String partiAddress) {
setPartiAddress(partiAddress);
return this;
}

public LedgerInited buildDbUri(String dbUri) {
setDbUri(dbUri);
return this;
}

public LedgerInited buildStartupState(StartupState startupState) {
setStartupState(startupState);
return this;
}
}

+ 156
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java View File

@@ -0,0 +1,156 @@
package com.jd.blockchain.ump.model.state;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class LedgerMasterInstall {

private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

private String ledgerKey;

private int totalNodeSize;

private String createTime;

private List<PeerInstall> peerInstalls = new ArrayList<>();

public LedgerMasterInstall() {
}

public LedgerMasterInstall(String ledgerKey, int totalNodeSize) {
this.ledgerKey = ledgerKey;
this.totalNodeSize = totalNodeSize;
}

public LedgerMasterInstall initCreateTime(String createTime) {
this.createTime = createTime;
return this;
}

public LedgerMasterInstall initCreateTime(Date date) {
this.createTime = SDF.format(date);
return this;
}

public LedgerMasterInstall add(PeerInstall peerInstall) {
peerInstalls.add(peerInstall);
return this;
}

public LedgerMasterInstall add(String name, String pubKey, String ipAddr, int initPort,
String consensusNode, String consensusProvider) {
PeerInstall peerInstall = new PeerInstall(
name, pubKey, ipAddr, initPort, consensusNode, consensusProvider);
return add(peerInstall);
}

public String getLedgerKey() {
return ledgerKey;
}

public void setLedgerKey(String ledgerKey) {
this.ledgerKey = ledgerKey;
}

public int getTotalNodeSize() {
return totalNodeSize;
}

public void setTotalNodeSize(int totalNodeSize) {
this.totalNodeSize = totalNodeSize;
}

public String getCreateTime() {
return createTime;
}

public void setCreateTime(String createTime) {
this.createTime = createTime;
}

public List<PeerInstall> getPeerInstalls() {
return peerInstalls;
}

public void setPeerInstalls(List<PeerInstall> peerInstalls) {
this.peerInstalls = peerInstalls;
}

public static class PeerInstall {

private String name;

private String pubKey;

private String ipAddr;

private int initPort;

private String consensusNode;

private String consensusProvider;

public PeerInstall() {
}

public PeerInstall(String name, String pubKey, String ipAddr, int initPort, String consensusNode, String consensusProvider) {
this.name = name;
this.pubKey = pubKey;
this.ipAddr = ipAddr;
this.initPort = initPort;
this.consensusNode = consensusNode;
this.consensusProvider = consensusProvider;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

public String getIpAddr() {
return ipAddr;
}

public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}

public int getInitPort() {
return initPort;
}

public void setInitPort(int initPort) {
this.initPort = initPort;
}

public String getConsensusNode() {
return consensusNode;
}

public void setConsensusNode(String consensusNode) {
this.consensusNode = consensusNode;
}

public String getConsensusProvider() {
return consensusProvider;
}

public void setConsensusProvider(String consensusProvider) {
this.consensusProvider = consensusProvider;
}
}
}

+ 42
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java View File

@@ -0,0 +1,42 @@
package com.jd.blockchain.ump.model.state;

public class LedgerPeerInited {

private String ledgerHash;

private LedgerPeerInstall peerInstall;

private StartupState startupState;

public LedgerPeerInited() {
}

public LedgerPeerInited(String ledgerHash, LedgerPeerInstall peerInstall) {
this.ledgerHash = ledgerHash;
this.peerInstall = peerInstall;
}

public String getLedgerHash() {
return ledgerHash;
}

public void setLedgerHash(String ledgerHash) {
this.ledgerHash = ledgerHash;
}

public LedgerPeerInstall getPeerInstall() {
return peerInstall;
}

public void setPeerInstall(LedgerPeerInstall peerInstall) {
this.peerInstall = peerInstall;
}

public StartupState getStartupState() {
return startupState;
}

public void setStartupState(StartupState startupState) {
this.startupState = startupState;
}
}

+ 117
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java View File

@@ -0,0 +1,117 @@
package com.jd.blockchain.ump.model.state;

import com.jd.blockchain.ump.model.MasterAddr;

import java.text.SimpleDateFormat;
import java.util.Date;

public class LedgerPeerInstall {

private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

private String ledgerKey;

private String ledgerAndNodeKey;

private String nodeName;

private String sharedKey;

private String peerPath;

private int totalNodeSize;

private MasterAddr masterAddr;

private String createTime;

public LedgerPeerInstall() {
}

public LedgerPeerInstall(String nodeName, String sharedKey, String peerPath, int totalNodeSize) {
this.nodeName = nodeName;
this.sharedKey = sharedKey;
this.peerPath = peerPath;
this.totalNodeSize = totalNodeSize;
}

public LedgerPeerInstall initKey(String ledgerKey, String ledgerAndNodeKey) {
this.ledgerKey = ledgerKey;
this.ledgerAndNodeKey = ledgerAndNodeKey;
return this;
}

public LedgerPeerInstall initMasterAddr(MasterAddr masterAddr) {
this.masterAddr = masterAddr;
return this;
}

public LedgerPeerInstall initCreateTime(Date date) {
createTime = SDF.format(date);
return this;
}

public String getLedgerKey() {
return ledgerKey;
}

public void setLedgerKey(String ledgerKey) {
this.ledgerKey = ledgerKey;
}

public String getLedgerAndNodeKey() {
return ledgerAndNodeKey;
}

public void setLedgerAndNodeKey(String ledgerAndNodeKey) {
this.ledgerAndNodeKey = ledgerAndNodeKey;
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}

public String getSharedKey() {
return sharedKey;
}

public void setSharedKey(String sharedKey) {
this.sharedKey = sharedKey;
}

public String getPeerPath() {
return peerPath;
}

public void setPeerPath(String peerPath) {
this.peerPath = peerPath;
}

public int getTotalNodeSize() {
return totalNodeSize;
}

public void setTotalNodeSize(int totalNodeSize) {
this.totalNodeSize = totalNodeSize;
}

public String getCreateTime() {
return createTime;
}

public void setCreateTime(String createTime) {
this.createTime = createTime;
}

public MasterAddr getMasterAddr() {
return masterAddr;
}

public void setMasterAddr(MasterAddr masterAddr) {
this.masterAddr = masterAddr;
}
}

+ 32
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java View File

@@ -0,0 +1,32 @@
package com.jd.blockchain.ump.model.state;

public class PeerInstallSchedule {

private InstallProcess process;

private ScheduleState state;

public PeerInstallSchedule() {
}

public PeerInstallSchedule(InstallProcess process, ScheduleState state) {
this.process = process;
this.state = state;
}

public InstallProcess getProcess() {
return process;
}

public void setProcess(InstallProcess process) {
this.process = process;
}

public ScheduleState getState() {
return state;
}

public void setState(ScheduleState state) {
this.state = state;
}
}

+ 61
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java View File

@@ -0,0 +1,61 @@
package com.jd.blockchain.ump.model.state;

import com.jd.blockchain.ump.model.config.LedgerIdentification;

import java.util.ArrayList;
import java.util.List;

public class PeerInstallSchedules {

private String ledgerHash;

private LedgerIdentification identification;

private List<PeerInstallSchedule> installSchedules = new ArrayList<>();

public PeerInstallSchedules() {
}

public PeerInstallSchedules(LedgerIdentification identification) {
this.identification = identification;
}

public PeerInstallSchedules(LedgerIdentification identification, String ledgerHash) {
this.identification = identification;
this.ledgerHash = ledgerHash;
}

public PeerInstallSchedules addInstallSchedule(PeerInstallSchedule installSchedule) {
this.installSchedules.add(installSchedule);
return this;
}

public PeerInstallSchedules initLedgerHash(String ledgerHash) {
setLedgerHash(ledgerHash);
return this;
}

public String getLedgerHash() {
return ledgerHash;
}

public void setLedgerHash(String ledgerHash) {
this.ledgerHash = ledgerHash;
}

public LedgerIdentification getIdentification() {
return identification;
}

public void setIdentification(LedgerIdentification identification) {
this.identification = identification;
}

public List<PeerInstallSchedule> getInstallSchedules() {
return installSchedules;
}

public void setInstallSchedules(List<PeerInstallSchedule> installSchedules) {
this.installSchedules = installSchedules;
}
}

+ 40
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java View File

@@ -0,0 +1,40 @@
package com.jd.blockchain.ump.model.state;

import java.util.ArrayList;
import java.util.List;

public class PeerStartupSchedules {

private String peerPath;

private List<PeerInstallSchedule> installSchedules = new ArrayList<>();

public PeerStartupSchedules() {
}

public PeerStartupSchedules(String peerPath) {
this.peerPath = peerPath;
}


public PeerStartupSchedules addInstallSchedule(PeerInstallSchedule installSchedule) {
this.installSchedules.add(installSchedule);
return this;
}

public List<PeerInstallSchedule> getInstallSchedules() {
return installSchedules;
}

public void setInstallSchedules(List<PeerInstallSchedule> installSchedules) {
this.installSchedules = installSchedules;
}

public String getPeerPath() {
return peerPath;
}

public void setPeerPath(String peerPath) {
this.peerPath = peerPath;
}
}

+ 43
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java View File

@@ -0,0 +1,43 @@
package com.jd.blockchain.ump.model.state;

public enum ScheduleState {

/**
* 加载内容,包括获取各种数据列表
*/
LOAD,
LOAD_SUCCESS, // 加载成功
LOAD_FAIL, // 加载失败

/**
* 将获取的数据写入文件
*
*/
WRITE,
WRITE_SUCCESS, // 写入文件成功
WRITE_FAIL, // 写入文件失败

/**
* Ledger_INIT:账本初始化过程
* 主要是调用SHELL
*
*/
INIT,
INIT_SUCCESS, // 账本初始化成功
INIT_FAIL, // 账本初始化失败

/**
* 无须启动PEER,等待PEER自动更新账本信息
*/
NO_STARTUP,

/**
* 启动Peer节点
*/
STARTUP_START,
STARTUP_OVER,
STARTUP_SUCCESS, // Peer节点启动成功
STARTUP_FAIL, // Peer节点启动失败
;

}

+ 48
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java View File

@@ -0,0 +1,48 @@
package com.jd.blockchain.ump.model.state;

public enum StartupState {

/**
* UNEXIST
* 不存在,描述该账本Hash曾经创建,但目前在LedgerBinding.conf文件中不存在
* 此状态不支持任何其他操作
*/
UNEXIST,

/**
* UNLOAD
* 账本存在,但未加载
* 此状态可以启动,不能停止
*/
UNLOAD,

/**
* LOADING
* 账本加载中,说明程序已经启动,但尚未加载该程序
* 此状态不可以启动,不建议停止
*/
LOADING,

/**
* LOADED
* 账本已加载
* 此状态不可以启动,后续可以支持停止操作
*/
LOADED,

/**
* UNKNOWN
* 未知,常见于命令检测执行错误或程序启动,但账本尚未加载完成
* 此状态不支持任何其他操作
*/
UNKNOWN,

/**
* DB_UNEXIST
* 该账本对应的数据库不存在
* 此状态不支持任何其他操作
*/
DB_UNEXIST,

;
}

+ 34
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java View File

@@ -0,0 +1,34 @@
package com.jd.blockchain.ump.model.user;

public class UserKeyBuilder {

private String name;

private String seed;

private String pwd;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSeed() {
return seed;
}

public void setSeed(String seed) {
this.seed = seed;
}

public String getPwd() {
return pwd;
}

public void setPwd(String pwd) {
this.pwd = pwd;
}
}

+ 68
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java View File

@@ -0,0 +1,68 @@
package com.jd.blockchain.ump.model.user;

public class UserKeys {

private int id;

private String name;

private String privKey;

private String pubKey;

private String encodePwd;

public UserKeys() {
}

public UserKeys(String name, String privKey, String pubKey, String encodePwd) {
this.name = name;
this.privKey = privKey;
this.pubKey = pubKey;
this.encodePwd = encodePwd;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPrivKey() {
return privKey;
}

public void setPrivKey(String privKey) {
this.privKey = privKey;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

public String getEncodePwd() {
return encodePwd;
}

public void setEncodePwd(String encodePwd) {
this.encodePwd = encodePwd;
}

public UserKeysVv toUserKeysVv() {
return new UserKeysVv(id, name, privKey, pubKey);
}
}

+ 69
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java View File

@@ -0,0 +1,69 @@
package com.jd.blockchain.ump.model.user;

public class UserKeysVv {

public static final int PRIVKEY_HEADER_LENGTH = 4;

public static final int PRIVKEY_TAIL_LENGTH = 8;

public static final String PRIVKEY_HIDE_CONTENT = "******";

private int id;

private String name;

private String privKey;

private String pubKey;

public UserKeysVv() {
}

public UserKeysVv(int id, String name, String privKey, String pubKey) {
this.id = id;
this.name = name;
this.privKey = encodePrivKey(privKey);
this.pubKey = pubKey;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPrivKey() {
return privKey;
}

public void setPrivKey(String privKey) {
this.privKey = privKey;
}

public String getPubKey() {
return pubKey;
}

public void setPubKey(String pubKey) {
this.pubKey = pubKey;
}

private String encodePrivKey(final String privKey) {
if (privKey != null && privKey.length() > (PRIVKEY_HEADER_LENGTH + PRIVKEY_TAIL_LENGTH)) {
return privKey.substring(0, PRIVKEY_HEADER_LENGTH) +
PRIVKEY_HIDE_CONTENT +
privKey.substring(privKey.length() - PRIVKEY_TAIL_LENGTH);
}
return privKey;
}
}

+ 20
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java View File

@@ -0,0 +1,20 @@
package com.jd.blockchain.ump.model.web;

/**
* 错误代码;
*/
public enum ErrorCode {

UNEXPECTED(5000),
;

private int value;

ErrorCode(int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

+ 97
- 0
source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java View File

@@ -0,0 +1,97 @@
package com.jd.blockchain.ump.model.web;

public class WebResponse<T> {

private boolean success;

private T data;

private ErrorMessage error;

private WebResponse(){

}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

public ErrorMessage getError() {
return error;
}

public void setError(ErrorMessage error) {
this.error = error;
}

public static WebResponse createSuccessResult(Object data){
WebResponse responseResult = new WebResponse();
responseResult.setSuccess(true);
responseResult.setData(data);
return responseResult;
}

public static WebResponse createFailureResult(int code, String message){
ErrorMessage errorMessage = new ErrorMessage(code, message);
return createFailureResult(errorMessage);
}

public static WebResponse createFailureResult(ErrorMessage errorMessage){
WebResponse responseResult = new WebResponse();
responseResult.setSuccess(false);
responseResult.setError(errorMessage);
return responseResult;
}



/**
* 错误消息实体
*
* @author liuxrb
*
*/
public static class ErrorMessage {

private int errorCode;

private String errorMessage;

public ErrorMessage() {

}

public ErrorMessage(int errorCode, String errorMessage) {
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}

public int getErrorCode() {
return errorCode;
}

public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}

public String getErrorMessage() {
return errorMessage;
}

public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
}

+ 114
- 0
source/manager/ump-service/pom.xml View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>manager</artifactId>
<groupId>com.jd.blockchain</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ump-service</artifactId>

<name>ump-service</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>crypto-classic</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>crypto-sm</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>tools-keygen</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>ump-model</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>

<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${project.basedir}/../ump-booter/libs/tools.jar</systemPath>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 31
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java View File

@@ -0,0 +1,31 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.state.LedgerBindingConf;
import com.jd.blockchain.ump.model.state.LedgerInited;

import java.util.List;

public interface LedgerService {

String randomSeed();

String currentCreateTime();

String ledgerInitCommand(String peerPath);

String peerStartCommand(String peerPath);

LedgerBindingConf allLedgerHashs(String peerPath);

LedgerBindingConf allLedgerHashs(long lastTime, String peerPath);

List<LedgerInited> allLedgerIniteds(String peerPath);

boolean dbExist(String peerPath, String ledgerHash);

String peerVerifyKey(String peerPath);

void save(String ledgerAndNodeKey, String ledgerHash);

String readLedgerHash(String ledgerAndNodeKey);
}

+ 310
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java View File

@@ -0,0 +1,310 @@
package com.jd.blockchain.ump.service;


import com.jd.blockchain.ump.dao.DBConnection;
import com.jd.blockchain.ump.model.UmpConstant;
import com.jd.blockchain.ump.model.state.LedgerBindingConf;
import com.jd.blockchain.ump.model.state.LedgerInited;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class LedgerServiceHandler implements LedgerService {

private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");

private static final String LEDGER_HASHS_FLAG = "ledger.bindings";

private static final String LEDGER_NAME_FORMAT = "binding.%s.name";

private static final String LEDGER_PARTI_ADDRESS_FORMAT = "binding.%s.parti.address";

private static final String LEDGER_PARTI_NAME_FORMAT = "binding.%s.parti.name";

private static final String LEDGER_DB_FORMAT = "binding.%s.db.uri";

private static final String FILE_PEER_FLAG = "deployment-peer";

private static final String JAR_SUFFIX = "jar";

private static final int SEED_BYTES_LENGTH = 32;

private static final int NAME_BYTES_LENGTH = 8;

private static final int SEED_PART_LENGTH = 8;

private static final Random LEDGER_RANDOM = new Random();

@Autowired
private UmpStateService umpStateService;

@Autowired
private DBConnection dbConnection;

@Override
public String randomSeed() {
byte[] seedBytes = new byte[SEED_BYTES_LENGTH];

LEDGER_RANDOM.nextBytes(seedBytes);

char[] seedChars = Hex.encodeHex(seedBytes);

StringBuilder sBuilder = new StringBuilder();

for (int i = 0; i < seedChars.length; i++) {
if (i != 0 && i % SEED_PART_LENGTH == 0) {
sBuilder.append("-");
}
sBuilder.append(seedChars[i]);
}

return sBuilder.toString();
}

@Override
public String currentCreateTime() {
return SDF.format(new Date());
}

@Override
public String ledgerInitCommand(String peerPath) {

return String.format(UmpConstant.CMD_LEDGER_INIT,
peerPath + UmpConstant.PATH_LEDGER_INIT_BIN);
}

@Override
public String peerStartCommand(String peerPath) {
return String.format(UmpConstant.CMD_START_UP_FORMAT,
peerPath + UmpConstant.PATH_STARTUP_BIN);
}

@Override
public LedgerBindingConf allLedgerHashs(String peerPath) {

return allLedgerHashs(0L, peerPath);
}

@Override
public LedgerBindingConf allLedgerHashs(long lastTime, String peerPath) {

// 读取LedgerBingConf文件,假设该文件不存在则返回空值
Set<String> allLedgerHashs = new HashSet<>();

PropAndTime propAndTime = loadLedgerBindingConf(lastTime, peerPath);

Properties props = propAndTime.getProp();

if (props != null) {

String ledgerHashChars = props.getProperty(LEDGER_HASHS_FLAG);

if (ledgerHashChars != null && ledgerHashChars.length() > 0) {
String[] ledgerHashArray = ledgerHashChars.split(",");
if (ledgerHashArray.length > 0) {
for (String ledgerHash : ledgerHashArray) {
allLedgerHashs.add(ledgerHash.trim());
}
}
}
}

LedgerBindingConf ledgerBindingConf = new LedgerBindingConf(propAndTime.getLastTime());

ledgerBindingConf.setLedgerHashs(allLedgerHashs);

return ledgerBindingConf;
}

@Override
public List<LedgerInited> allLedgerIniteds(String peerPath) {

List<LedgerInited> ledgerIniteds = new ArrayList<>();

PropAndTime propAndTime = loadLedgerBindingConf(0L, peerPath);

Properties props = propAndTime.getProp();

if (props != null) {

String ledgerHashChars = props.getProperty(LEDGER_HASHS_FLAG);

Set<String> ledgerHashSet = new HashSet<>();

if (ledgerHashChars != null && ledgerHashChars.length() > 0) {
String[] ledgerHashArray = ledgerHashChars.split(",");
if (ledgerHashArray.length > 0) {
for (String ledgerHash : ledgerHashArray) {
ledgerHashSet.add(ledgerHash.trim());
}
}
}

// 根据Hash值,遍历Prop
for (String hash : ledgerHashSet) {

LedgerInited ledgerInited = new LedgerInited(hash);

String ledgerName = props.getProperty(String.format(LEDGER_NAME_FORMAT, hash));

String partiAddress = props.getProperty(String.format(LEDGER_PARTI_ADDRESS_FORMAT, hash));

String partiName = props.getProperty(String.format(LEDGER_PARTI_NAME_FORMAT, hash));

String dbUri = props.getProperty(String.format(LEDGER_DB_FORMAT, hash));

ledgerIniteds.add(
ledgerInited
.buildLedgerName(ledgerName)
.buildPartiAddress(partiAddress)
.buildPartiName(partiName)
.buildDbUri(dbUri));
}
}
return ledgerIniteds;
}

@Override
public synchronized boolean dbExist(String peerPath, String ledgerHash) {
// 检查该账本对应的数据库是否存在

PropAndTime propAndTime = loadLedgerBindingConf(0L, peerPath);

// binding.j5faRYSqSqSRmSVgdmPsgq7Hzd1yP7yAGPWkTihekWms94.db.uri=rocksdb:///Users/shaozhuguang/Documents/ideaProjects/jdchain-patch/source/test/test-integration/rocks.db/rocksdb4.db
Properties props = propAndTime.getProp();

if (props != null) {
String dbKey = String.format(LEDGER_DB_FORMAT, ledgerHash);

String dbUri = props.getProperty(dbKey);

if (dbUri != null && dbUri.length() > 0) {

return dbConnection.exist(dbUri);
}
}

return false;
}

@Override
public String peerVerifyKey(String peerPath) {
// 从libs中读取对应的Peer.jar的文件名称,配合全路径
File libsDirectory = new File(peerPath + UmpConstant.PATH_SYSTEM);

Collection<File> jars = FileUtils.listFiles(libsDirectory, new String[]{JAR_SUFFIX}, false);

String peerVerifyKey = null;

if (!jars.isEmpty()) {
for (File jar : jars) {
String jarName = jar.getName();
if (jarName.startsWith(FILE_PEER_FLAG)) {
peerVerifyKey = jar.getPath();
break;
}
}
}

return peerVerifyKey;
}

@Override
public void save(String ledgerAndNodeKey, String ledgerHash) {
// 保存LedgerAndNodeKey与账本关系
umpStateService.saveLedgerHash(ledgerAndNodeKey, ledgerHash);
}

@Override
public String readLedgerHash(String ledgerAndNodeKey) {

return umpStateService.readLedgerHash(ledgerAndNodeKey);
}

private PropAndTime loadLedgerBindingConf(long lastTime, String peerPath) {

File ledgerBindingConf = new File(peerPath + UmpConstant.PATH_LEDGER_BINDING_CONFIG);

PropAndTime propAndTime = new PropAndTime(lastTime);

// 说明被修改过
if (ledgerBindingConf.exists() && ledgerBindingConf.lastModified() > lastTime) {

propAndTime.lastTime = ledgerBindingConf.lastModified();

try (InputStream inputStream = new FileInputStream(ledgerBindingConf)) {

Properties props = new Properties();

props.load(inputStream);

propAndTime.prop = props;

} catch (Exception e) {
throw new IllegalStateException(e);
}
}

return propAndTime;
}

private static class PropAndTime {

private Properties prop;

private long lastTime;

public PropAndTime() {
}

public PropAndTime(long lastTime) {
this.lastTime = lastTime;
}

public Properties getProp() {
return prop;
}

public void setProp(Properties prop) {
this.prop = prop;
}

public long getLastTime() {
return lastTime;
}

public void setLastTime(long lastTime) {
this.lastTime = lastTime;
}
}

// private Properties loadLedgerBindingConf(String peerPath) {
//
// File ledgerBindingConf = new File(peerPath + UmpConstant.PATH_LEDGER_BINDING_CONFIG);
//
// if (ledgerBindingConf.exists()) {
//
// try (InputStream inputStream = new FileInputStream(ledgerBindingConf)) {
//
// Properties props = new Properties();
//
// props.load(inputStream);
//
// return props;
//
// } catch (Exception e) {
// throw new IllegalStateException(e);
// }
// }
//
// return null;
// }
}

+ 36
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java View File

@@ -0,0 +1,36 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.PeerSharedConfigs;
import com.jd.blockchain.ump.model.config.*;
import com.jd.blockchain.ump.model.state.PeerInstallSchedules;
import com.jd.blockchain.ump.model.state.PeerStartupSchedules;


public interface UmpService {

PeerSharedConfigs loadPeerSharedConfigs(PeerLocalConfig sharedConfig);

LedgerConfig response(PeerSharedConfigs peerSharedConfigs, PeerLocalConfig localConfig);

String save(MasterAddr masterAddr, LedgerConfig ledgerConfig, PeerLocalConfig localConfig);

String ledgerAndNodeKey(LedgerConfig ledgerConfig, PeerSharedConfig sharedConfig);

PeerInstallSchedules install(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey);

PeerInstallSchedules install(String ledgerAndNodeKey);

PeerInstallSchedules init(String ledgerAndNodeKey);

PeerInstallSchedules init(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey);

// PeerInstallSchedules startup(String ledgerAndNodeKey);

PeerStartupSchedules startup();

boolean stop(String ledgerAndNodeKey);

boolean stop();

}

+ 925
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java View File

@@ -0,0 +1,925 @@
package com.jd.blockchain.ump.service;


import com.jd.blockchain.ump.dao.DBConnection;
import com.jd.blockchain.ump.dao.RocksDBConnection;
import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.PeerSharedConfigs;
import com.jd.blockchain.ump.model.UmpConstant;
import com.jd.blockchain.ump.model.config.*;
import com.jd.blockchain.ump.model.state.*;
import com.jd.blockchain.ump.service.consensus.ConsensusService;
import com.jd.blockchain.ump.util.Base58Utils;
import com.jd.blockchain.ump.util.CommandUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;

@Service
public class UmpServiceHandler implements UmpService {

private final Logger LOGGER = LoggerFactory.getLogger(getClass());

private static final String SUCCESS = "SUCCESS";

private static final String ROCKSDB_PROTOCOL = RocksDBConnection.ROCKSDB_PROTOCOL;

private static final int DB_SUFFIX_LENGTH = 4;

private static final Random DB_RANDOM = new Random();

private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmmssSSS");//yyyy-MM-dd HH:mm:ss为目标的样式

private final Map<String, LedgerConfig> ledgerConfigs = new ConcurrentHashMap<>();

private final Map<String, MasterConfig> masterConfigs = new ConcurrentHashMap<>();

private final Map<String, PeerSharedConfigs> peerShareds = new ConcurrentHashMap<>();

private final Map<String, LedgerConfig> ledgerConfigMemory = new ConcurrentHashMap<>();

@Autowired
private ConsensusService consensusService;

@Autowired
private LedgerService ledgerService;

@Autowired
private DBConnection dbConnection;

@Autowired
private UmpStateService umpStateService;

@Override
public synchronized PeerSharedConfigs loadPeerSharedConfigs(PeerLocalConfig sharedConfig) {

String sharedKey = sharedConfig.getSharedKey();

PeerSharedConfigs peerSharedConfigs = peerShareds.get(sharedKey);

if (peerSharedConfigs == null) {
peerSharedConfigs = new PeerSharedConfigs();
peerShareds.put(sharedKey, peerSharedConfigs);
}

return peerSharedConfigs.addConfig(sharedConfig);
}

@Override
public LedgerConfig response(PeerSharedConfigs sharedConfigs, PeerLocalConfig localConfig) {
try {
// 对于Master和Peer处理方式不同
if (localConfig.getMasterConfig().isMaster()) {

// Master节点需要等待完成后通知其他线程
sharedConfigs.waitAndNotify();
} else {

// 等待Master节点通知
sharedConfigs.await();
}

// 此处需要防止并发
final String sharedKey = sharedConfigs.getSharedKey();

LedgerConfig savedLedgerConfig = ledgerConfigMemory.get(sharedKey);

if (savedLedgerConfig != null) {
return savedLedgerConfig;
}

// 获取当前对象锁(所有节点请求使用同一个对象)
final Lock lock = sharedConfigs.getLock();

lock.lock();

try {
// 执行到此表示获取到锁,此时需要判断是否有数据
// Double Check !!!
savedLedgerConfig = ledgerConfigMemory.get(sharedKey);

if (savedLedgerConfig != null) {
return savedLedgerConfig;
}

// 校验
verify(sharedConfigs);

// 所有数据到达之后生成返回的应答
LedgerInitConfig initConfig = sharedConfigs.ledgerInitConfig(
ledgerService.randomSeed(), ledgerService.currentCreateTime());

// 生成共识文件
String consensusConfig = consensusService.initConsensusConf(
sharedConfigs.getConsensusProvider(), sharedConfigs.getSharedConfigs());

LedgerConfig ledgerConfig = new LedgerConfig(initConfig, consensusConfig);

// 将本次LedgerKey信息写入数据库
String ledgerKey = initConfig.ledgerKey();

dbConnection.put(ledgerKey, ledgerConfig, LedgerConfig.class);

// 将节点的Key信息写入数据库
umpStateService.save(ledgerKey, sharedConfigKeys(ledgerKey, sharedConfigs));

// 将本地生成数据的信息写入数据库
LedgerMasterInstall masterInstall = sharedConfigs.toLedgerMasterInstall();

umpStateService.save(masterInstall);

// 将数据放入内存
ledgerConfigMemory.put(sharedKey, ledgerConfig);

return ledgerConfig;
} finally {
lock.unlock();
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

@Override
public String save(MasterAddr masterAddr, LedgerConfig ledgerConfig, PeerLocalConfig localConfig) {

String ledgerAndNodeKey = ledgerAndNodeKey(ledgerConfig, localConfig);

ledgerConfigs.put(ledgerAndNodeKey, ledgerConfig);

// 保存本次需要发送的Master地址
masterConfigs.put(ledgerAndNodeKey, localConfig.getMasterConfig());

// 保存所有的信息至本地
umpStateService.save(ledgerAndNodeKey, localConfig);

// 保存当前同步信息至数据库
LedgerPeerInstall peerInstall = localConfig.toLedgerPeerInstall(ledgerConfig.getInitConfig().getNodeSize());

// init相关配置信息
peerInstall
.initKey(ledgerConfig.getInitConfig().ledgerKey(), ledgerAndNodeKey)
.initCreateTime(new Date())
.initMasterAddr(masterAddr);

// 写入数据库
umpStateService.save(peerInstall);

return ledgerAndNodeKey;
}

@Override
public String ledgerAndNodeKey(LedgerConfig ledgerConfig, PeerSharedConfig sharedConfig) {

return ledgerAndNodeKey(ledgerConfig.getInitConfig().ledgerKey(), sharedConfig);
}

@Override
public PeerInstallSchedules install(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey) {

// 初始化Peer节点数据
PeerInstallSchedules installSchedules = init(identification, localConfig, ledgerAndNodeKey);

// Peer节点启动
peerStart(localConfig.getPeerPath(), installSchedules);

return installSchedules;
}

@Override
public PeerInstallSchedules install(String ledgerAndNodeKey) {

PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey);

if (localConfig != null) {

// 获取LedgerIdentification
LedgerIdentification identification = umpStateService.readIdentification(ledgerAndNodeKey);

return install(identification, localConfig, ledgerAndNodeKey);
}
throw new IllegalStateException("Can not find LocalConfig from DataBase !!!");
}

@Override
public PeerInstallSchedules init(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey) {

PeerInstallSchedules installSchedules = new PeerInstallSchedules(identification);

MasterAddr masterAddr = loadMaster(localConfig);

LedgerConfig ledgerConfig = ledgerConfigs.get(ledgerAndNodeKey);

if (ledgerConfig == null || ledgerConfig.getInitConfig() == null) {
saveInstallSchedule(installSchedules, masterAddr, "", ledgerAndNodeKey,
String.format("Ledger Key = [%s] can not find Ledger-Config !!!", ledgerAndNodeKey),
ScheduleState.LOAD_FAIL);
throw new IllegalStateException(String.format("Ledger Key = [%s] can not find Ledger-Config !!!", ledgerAndNodeKey));
}

LedgerInitConfig initConfig = ledgerConfig.getInitConfig();

String ledgerKey = initConfig.ledgerKey();

List<String> localConfContents, ledgerInitContents;

try {
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Find LedgerConfig from Memory for Key [%s] -> %s", ledgerAndNodeKey, SUCCESS),
ScheduleState.LOAD);

// 首先获取当前节点的ID
int nodeId = initConfig.nodeId(localConfig.getPubKey());

// 生成local.conf文件内容
localConfContents = localConfContents(localConfig, nodeId);

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Init Local.Conf's Content -> %s", SUCCESS),
ScheduleState.LOAD);

// 生成LedgerInit内容
ledgerInitContents = initConfig.toConfigChars(localConfig.consensusConfPath());

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Init Ledger.Init's Content -> %s", SUCCESS),
ScheduleState.LOAD);
} catch (Exception e) {
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Load Config's Content !!!",
ScheduleState.LOAD_FAIL);
throw new IllegalStateException(e);
}

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Load Config's Content !!!",
ScheduleState.LOAD_SUCCESS);

try {
// 将该文件内容写入Local.Conf
forceWrite(localConfContents, new File(localConfig.localConfPath()));

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Write And Backup File local.conf -> %s", SUCCESS),
ScheduleState.WRITE);

// 将文件内容写入Ledger-Init
forceWrite(ledgerInitContents, new File(localConfig.ledgerInitConfPath()));

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Write And Backup File ledger.init -> %s", SUCCESS),
ScheduleState.WRITE);

// 将共识内容写入文件,例如bftsmart.conf
String consensusFileName = writeConsensusContent(ledgerConfig.getConsensusConfig(),
new File(localConfig.consensusConfPath()));

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Write And Backup Consensus File %s -> %s", consensusFileName, SUCCESS),
ScheduleState.WRITE);

} catch (Exception e) {
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Write Config's Content to Config File !!!",
ScheduleState.WRITE_FAIL);
throw new IllegalStateException(e);
}

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Write Config's Content to Config File !!!",
ScheduleState.WRITE_SUCCESS);

// 账本初始化
String ledgerHash = ledgerInit(localConfig.getPeerPath(), installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey);

// 设置账本Hash
installSchedules.setLedgerHash(ledgerHash);

return installSchedules;
}

@Override
public PeerInstallSchedules init(String ledgerAndNodeKey) {

PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey);

if (localConfig != null) {

// 获取LedgerIdentification
LedgerIdentification identification = umpStateService.readIdentification(ledgerAndNodeKey);

return init(identification, localConfig, ledgerAndNodeKey);
}
throw new IllegalStateException("Can not find LocalConfig from DataBase !!!");
}


// @Override
// public PeerInstallSchedules startup(String ledgerAndNodeKey) {
//
// PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey);
//
// if (localConfig != null) {
//
// PeerInstallSchedules installSchedules = umpStateService.loadState(ledgerAndNodeKey);
//
// // Peer节点启动
// return peerStart(localConfig.getPeerPath(), installSchedules);
//
// }
// throw new IllegalStateException("Can not find LocalConfig from DataBase !!!");
// }

@Override
public PeerStartupSchedules startup() {

PeerStartupSchedules startupSchedules = new PeerStartupSchedules(UmpConstant.PROJECT_PATH);

return peerStart(startupSchedules);
}

@Override
public boolean stop(String ledgerAndNodeKey) {
PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey);

if (localConfig != null) {

// Peer节点停止
return peerStop(localConfig.getPeerPath());
}
throw new IllegalStateException("Can not find LocalConfig from DataBase !!!");
}

@Override
public boolean stop() {

return peerStop(UmpConstant.PROJECT_PATH);
}

private MasterAddr loadMaster(PeerLocalConfig localConfig) {

// 开始安装之后则可以将内存中的数据释放
String sharedKey = localConfig.getSharedKey();

if (sharedKey != null) {
ledgerConfigMemory.remove(sharedKey);
}

if (localConfig.master()) {
return null;
}

return localConfig.masterAddr();
}

private List<String> sharedConfigKeys(String ledgerKey, PeerSharedConfigs sharedConfigs) {

List<String> sharedConfigKeys = new ArrayList<>();

List<PeerLocalConfig> pscs = sharedConfigs.getSharedConfigs();

for(PeerSharedConfig psc : pscs) {
sharedConfigKeys.add(ledgerAndNodeKey(ledgerKey, psc));
}

return sharedConfigKeys;
}

private String ledgerAndNodeKey(String ledgerKey, PeerSharedConfig sharedConfig) {

return ledgerKey + "-" + sharedConfig.getName();
}

private String ledgerInit(String peerPath, PeerInstallSchedules installSchedules, MasterAddr masterAddr, String ledgerKey, String ledgerAndNodeKey) {

String newLedgerHash = "";

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Steps to start processing LedgerInit !!!",
ScheduleState.INIT);

// 获取当前已经存在的Ledger列表
LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(peerPath);

Set<String> currentLedgerHashs = ledgerBindingConf.getLedgerHashs();

long lastTime = ledgerBindingConf.getLastTime();

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Find History Ledger's Size = %s", currentLedgerHashs.size()),
ScheduleState.INIT);

String ledgerInitCommand = ledgerService.ledgerInitCommand(peerPath);

try {

LOGGER.info("Execute Ledger-Init's Shell {}", ledgerInitCommand);

Process ledgerInitProcess;

try {
// 调用ledgerInit初始化脚本
ledgerInitProcess = CommandUtils.execute(CommandUtils.toCommandList(ledgerInitCommand));

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Execute LedgerInit's Command -> %s", SUCCESS),
ScheduleState.INIT);
} catch (Exception e) {
LOGGER.error("Execute Ledger-Init's Shell !!!", e);
throw new IllegalStateException(e);
}

int maxSize = 512;

boolean isInitSuccess = false;

int checkIndex = 1;

while (maxSize > 0) {
// 时延
Thread.sleep(6000);

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("%s Check LedgerInit's Status ...... ", checkIndex++),
ScheduleState.INIT);

// 检查账本是否增加
CurrentLedger currentLedger = checkNewLedger(lastTime, peerPath, currentLedgerHashs);

lastTime = currentLedger.getLastTime();

newLedgerHash = currentLedger.getLedgerHash();

if (newLedgerHash != null && newLedgerHash.length() > 0) {
isInitSuccess = true;
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Find New Ledger = %s", newLedgerHash),
ScheduleState.INIT);
break;
}
maxSize --;
}

// 完成后,不管是否处理完,都将命令停止
// 为防止其他应用仍在访问,延时6秒停止
try {
Thread.sleep(6000);
ledgerInitProcess = ledgerInitProcess.destroyForcibly();
if (ledgerInitProcess.isAlive()) {
// 再尝试一次
ledgerInitProcess.destroyForcibly();
}
} catch (Exception e) {
// 暂时打印日志
LOGGER.error("Stop Ledger Init Command !!!", e);
}

// 再次判断是否初始化账本成功
if (newLedgerHash == null) {

CurrentLedger currentLedger = checkNewLedger(lastTime, peerPath, currentLedgerHashs);

newLedgerHash = currentLedger.getLedgerHash();

if (newLedgerHash != null && newLedgerHash.length() > 0) {
isInitSuccess = true;
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Final Find New Ledger = %s", newLedgerHash),
ScheduleState.INIT);
}
}

if (!isInitSuccess) {
// 失败则抛出异常
throw new IllegalStateException("Can Not Find New Ledger !!!");
}
} catch (Exception e) {
saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
"Execute Ledger-Init Command Fail !!!",
ScheduleState.INIT_FAIL);
LOGGER.error("Execute Ledger-Init Command Fail !!!", e);
throw new IllegalStateException(e);
}

saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
String.format("Steps to processing LedgerInit -> %s", SUCCESS),
ScheduleState.INIT_SUCCESS);

// 将账本Hash写入数据库
ledgerService.save(ledgerAndNodeKey, newLedgerHash);

return newLedgerHash;
}

private CurrentLedger checkNewLedger(long lastTime, String peerPath, Set<String> currentLedgerHashs) {
// 再次判断是否初始化账本成功
LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(lastTime, peerPath);

Set<String> newLedgerHashs = ledgerBindingConf.getLedgerHashs();

CurrentLedger currentLedger = new CurrentLedger(ledgerBindingConf.getLastTime());

if (newLedgerHashs.size() > currentLedgerHashs.size()) {
// 获取其新安装的LedgerHash
for (String ledgerHash : newLedgerHashs) {
if (!currentLedgerHashs.contains(ledgerHash)) {
// 新获取的LedgerHash为当前值
currentLedger.ledgerHash = ledgerHash;
break;
}
}
}
return currentLedger;
}


private PeerInstallSchedules peerStart(String peerPath, PeerInstallSchedules installSchedules) {

saveInstallSchedule(installSchedules,
"Steps to start processing PeerNodeStart !!!",
ScheduleState.STARTUP_START);
// 启动Peer
// 说明初始化成功
// 判断是否需要启动Peer
String peerVerify = ledgerService.peerVerifyKey(peerPath);

try {
if (!CommandUtils.isActive(peerVerify)) {
// 不存在,则需要再启动
String peerStartCmd = ledgerService.peerStartCommand(peerPath);

LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd);

if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) {
// Peer节点启动失败
throw new IllegalStateException("Peer Node Start UP Fail !!!");
}
saveInstallSchedule(installSchedules,
String.format("Peer's process %s start -> %s", peerVerify, SUCCESS),
ScheduleState.STARTUP_SUCCESS);
} else {
// 命令已经存在
saveInstallSchedule(installSchedules,
String.format("Peer's process is exist -> %s", peerVerify),
ScheduleState.NO_STARTUP);
}
} catch (Exception e) {
saveInstallSchedule(installSchedules,
e.getMessage(),
ScheduleState.STARTUP_FAIL);
throw new IllegalStateException(e);
}

saveInstallSchedule(installSchedules,
"Steps to start processing PeerNodeStart over !!!",
ScheduleState.STARTUP_OVER);

return installSchedules;
}

private PeerStartupSchedules peerStart(PeerStartupSchedules startupSchedules) {

String peerPath = startupSchedules.getPeerPath();

saveStartupSchedules(startupSchedules,
"Steps to start processing PeerNodeStart !!!",
ScheduleState.STARTUP_START);
// 启动Peer
// 说明初始化成功
// 判断是否需要启动Peer
String peerVerify = ledgerService.peerVerifyKey(peerPath);

try {
if (!CommandUtils.isActive(peerVerify)) {
// 不存在,则需要再启动
String peerStartCmd = ledgerService.peerStartCommand(peerPath);

LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd);

if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) {
// Peer节点启动失败
throw new IllegalStateException("Peer Node Start UP Fail !!!");
}
saveStartupSchedules(startupSchedules,
String.format("Peer's process %s start -> %s", peerVerify, SUCCESS),
ScheduleState.STARTUP_SUCCESS);
} else {
// 命令已经存在
saveStartupSchedules(startupSchedules,
String.format("Peer's process is exist -> %s", peerVerify),
ScheduleState.NO_STARTUP);
}
} catch (Exception e) {
saveStartupSchedules(startupSchedules,
e.getMessage(),
ScheduleState.STARTUP_FAIL);
throw new IllegalStateException(e);
}

saveStartupSchedules(startupSchedules,
"Steps to start processing PeerNodeStart over !!!",
ScheduleState.STARTUP_OVER);

return startupSchedules;
}

// private PeerInstallSchedules peerStart(String peerPath, PeerInstallSchedules installSchedules) {
//
// MasterAddr masterAddr = installSchedules.getIdentification().getMasterAddr();
//
// String ledgerKey = installSchedules.getIdentification().getLedgerKey();
//
// String ledgerAndNodeKey = installSchedules.getIdentification().getLedgerAndNodeKey();
//
// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
// "Steps to start processing PeerNodeStart !!!",
// ScheduleState.STARTUP_START);
// // 启动Peer
// // 说明初始化成功
// // 判断是否需要启动Peer
// String peerVerify = ledgerService.peerVerifyKey(peerPath);
//
// try {
// if (!CommandUtils.isActive(peerVerify)) {
// // 不存在,则需要再启动
// String peerStartCmd = ledgerService.peerStartCommand(peerPath);
//
// LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd);
//
// if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) {
// // Peer节点启动失败
// throw new IllegalStateException("Peer Node Start UP Fail !!!");
// }
// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
// String.format("Peer's process %s start -> %s", peerVerify, SUCCESS),
// ScheduleState.STARTUP_SUCCESS);
// } else {
// // 命令已经存在
// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
// String.format("Peer's process is exist -> %s", peerVerify),
// ScheduleState.NO_STARTUP);
// }
// } catch (Exception e) {
// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
// e.getMessage(),
// ScheduleState.STARTUP_FAIL);
// throw new IllegalStateException(e);
// }
//
// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey,
// "Steps to start processing PeerNodeStart over !!!",
// ScheduleState.STARTUP_OVER);
//
// return installSchedules;
// }

private boolean peerStop(String peerPath) {

// 判断是否需要停止Peer
String peerVerify = ledgerService.peerVerifyKey(peerPath);

try {
if (CommandUtils.isActive(peerVerify)) {

LOGGER.info("We need stop peer {}", peerVerify);
// 需要停止Peer节点
CommandUtils.killVm(peerVerify);

// 最多循环5次进行判断
int maxSize = 5;

while (maxSize > 0) {
try {
Thread.sleep(3000);
if (!CommandUtils.isActive(peerVerify)) {
return true;
}
} catch (Exception e) {
LOGGER.error("Check Peer Stop State !!!", e);
} finally {
maxSize--;
}
}
} else {
LOGGER.info("We do not need stop peer {}", peerVerify);
return false;
}
} catch (Exception e) {
LOGGER.error("Stop Peer Node", e);
throw new IllegalStateException(e);
}
return false;
}

private String writeConsensusContent(String consensusContent, File consensusFile) throws IOException {
// 将字符串转换为字节数组
byte[] consensusBytes = Base58Utils.decode(consensusContent);
forceWrite(consensusBytes, consensusFile);
return consensusFile.getName();
}

private void forceWrite(List<String> lines, File file) throws IOException {
if (file.exists()) {
FileUtils.moveFile(file, new File(file.getPath() + "_bak_" + currentDate()));
}

FileUtils.writeLines(file, StandardCharsets.UTF_8.toString(), lines);
}

private void forceWrite(byte[] content, File file) throws IOException {
if (file.exists()) {
FileUtils.moveFile(file, new File(file.getPath() + "_bak_" + currentDate()));
}

FileUtils.writeByteArrayToFile(file, content);
}

private void verify(PeerSharedConfigs peerSharedConfigs) {
// 校验其中内容
List<PeerLocalConfig> sharedConfigs = peerSharedConfigs.getSharedConfigs();

// 首先保证其中的数据一致性
// 1、name不能重复;
// 2、pubKey不能重复;
// 3、ipAddr + initPort不能重复;

Set<String> nameSet = new HashSet<>(),
pubKeySet = new HashSet<>(),
addrSet = new HashSet<>();

for (PeerSharedConfig sharedConfig : sharedConfigs) {
String name = sharedConfig.getName(),
pubKey = sharedConfig.getPubKey(),
addr = sharedConfig.addr();
if (nameSet.contains(name)) {
throw new IllegalStateException(String.format("Name [%s] is Conflict !!!", name));
} else {
nameSet.add(name);
}

if (pubKeySet.contains(pubKey)) {
throw new IllegalStateException(String.format("PubKey [%s] is Conflict !!!", pubKey));
} else {
pubKeySet.add(pubKey);
}

if (addrSet.contains(addr)) {
throw new IllegalStateException(String.format("Address [%s] is Conflict !!!", addr));
} else {
addrSet.add(addr);
}
}
}

private void saveInstallSchedule(PeerInstallSchedules installSchedules, MasterAddr masterAddr, String ledgerKey, String ledgerAndNodeKey, String content, ScheduleState state) {

// 日志打印相关内容
LOGGER.info(content);

// 生成InstallSchedule对象
InstallSchedule schedule = installSchedule(ledgerKey, ledgerAndNodeKey, content, state);

// 加入反馈列表
installSchedules.addInstallSchedule(
new PeerInstallSchedule(new InstallProcess(content), state));

// 将InstallSchedule写入数据库
umpStateService.save(schedule, masterAddr);
}

private void saveInstallSchedule(PeerInstallSchedules installSchedules, String content, ScheduleState state) {

// 日志打印相关内容
LOGGER.info(content);

// 加入反馈列表
installSchedules.addInstallSchedule(
new PeerInstallSchedule(new InstallProcess(content), state));
}

private void saveStartupSchedules(PeerStartupSchedules startupSchedules, String content, ScheduleState state) {

// 日志打印相关内容
LOGGER.info(content);

// 加入反馈列表
startupSchedules.addInstallSchedule(
new PeerInstallSchedule(new InstallProcess(content), state));
}

private InstallSchedule installSchedule(String ledgerKey, String ledgerAndNodeKey, String content, ScheduleState state) {

InstallProcess process = new InstallProcess(content);

return new InstallSchedule(ledgerKey, ledgerAndNodeKey, process, state);

}

private List<String> localConfContents(PeerLocalConfig localConfig, int nodeId) {
/**
* #当前参与方的 id,与ledger.init文件中cons_parti.id一致,默认从0开始
* local.parti.id=0
*
* #当前参与方的公钥
* local.parti.pubkey=
*
* #当前参与方的私钥(密文编码)
* local.parti.privkey=
*
* #当前参与方的私钥解密密钥(原始口令的一次哈希,Base58格式),如果不设置,则启动过程中需要从控制台输入
* local.parti.pwd=
*
* #账本初始化完成后生成的"账本绑定配置文件"的输出目录
* #推荐使用绝对路径,相对路径以当前文件(local.conf)所在目录为基准
* ledger.binding.out=../
*
* #账本数据库的连接字符
* #rocksdb数据库连接格式:rocksdb://{path},例如:rocksdb:///export/App08/peer/rocks.db/rocksdb0.db
* #redis数据库连接格式:redis://{ip}:{prot}/{db},例如:redis://127.0.0.1:6379/0
* ledger.db.uri=
*
* #账本数据库的连接口令
* ledger.db.pwd=
*/

List<String> localContents = new ArrayList<>();

localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_ID_PREFIX, nodeId));

localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PUBKEY_PREFIX, localConfig.getPubKey()));

localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PRIVKEY_PREFIX, localConfig.getPrivKey()));

localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PWD_PREFIX, localConfig.getEncodePwd()));

localContents.add(valueToConfig(UmpConstant.LEDGER_BINDING_OUT_PREFIX, localConfig.bindingOutPath()));

localContents.add(valueToConfig(UmpConstant.LEDGER_DB_URI_PREFIX, dbUri(localConfig.getDbName(), localConfig.getPeerPath())));

localContents.add(valueToConfig(UmpConstant.LEDGER_DB_PWD_PREFIX, ""));

return localContents;
}

private String valueToConfig(String prefix, Object value) {
return prefix + "=" + value;
}

private String currentDate() {
return SDF.format(new Date());
}

private String dbUri(final String dbName, final String peerPath) {

String dbDirectoryPath = peerPath + File.separator + dbName;

String dbUri = ROCKSDB_PROTOCOL + dbDirectoryPath;

File dbDirectory = new File(dbDirectoryPath);

if (!dbDirectory.exists()) {
return dbUri;
}
throw new IllegalStateException(String.format("DB name = %s, path = %s is Exist !!!", dbName, dbDirectoryPath));
}

private static class CurrentLedger {

private String ledgerHash;

private long lastTime;

public CurrentLedger() {
}

public CurrentLedger(long lastTime) {
this.lastTime = lastTime;
}

public String getLedgerHash() {
return ledgerHash;
}

public void setLedgerHash(String ledgerHash) {
this.ledgerHash = ledgerHash;
}

public long getLastTime() {
return lastTime;
}

public void setLastTime(long lastTime) {
this.lastTime = lastTime;
}
}
}

+ 17
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java View File

@@ -0,0 +1,17 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.config.PeerSharedConfigVv;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.model.user.UserKeysVv;

public interface UmpSimulateService {

UserKeysVv userKeysVv(int nodeId);

UserKeys userKeys(int nodeId);

PeerLocalConfig nodePeerLocalConfig(int nodeId, boolean isMaster);

PeerSharedConfigVv peerSharedConfigVv(int nodeId, boolean isMaster);
}

+ 134
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java View File

@@ -0,0 +1,134 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.config.PeerSharedConfigVv;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.model.user.UserKeysVv;
import com.jd.blockchain.ump.service.consensus.providers.BftsmartConsensusProvider;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class UmpSimulateServiceHandler implements UmpSimulateService {

private static final Random RANDOM_ROCKSDB = new Random();

private static final String SHARED_KEY = "JDChain";

private static final int TOTAL_SIZE = 4;

private static final String LOCALHOST = "127.0.0.1";

private static final String CONSENSUS_PROVIDER = BftsmartConsensusProvider.BFTSMART_PROVIDER;

private static final String CONSENSUS_CONF = BftsmartConsensusProvider.BFTSMART_CONFIG_FILE;

private static final int INIT_PORT_START = 9000;

private static final String[] PUBKEYS = new String[]{
"3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9",
"3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX",
"3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x",
"3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"};

private static final String[] PRIVKEYS = new String[]{
"177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x",
"177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT",
"177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF",
"177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"};

private static final String ENCODE_PWD = "DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY";

private static final String BINDING_OUT = "../";

private static final String[] DB_URIS = new String[]{
"rocksdb:///Users/shaozhuguang/Documents/simulate/peer0/rocksdb",
"rocksdb:///Users/shaozhuguang/Documents/simulate/peer1/rocksdb",
"rocksdb:///Users/shaozhuguang/Documents/simulate/peer2/rocksdb",
"rocksdb:///Users/shaozhuguang/Documents/simulate/peer3/rocksdb"};

private static final String DB_PWD = "";

private static final String DB_NAME = "rocksdb_";

private static final String[] PEER_PATHS = new String[]{
"/Users/shaozhuguang/Documents/simulate/peer0",
"/Users/shaozhuguang/Documents/simulate/peer1",
"/Users/shaozhuguang/Documents/simulate/peer2",
"/Users/shaozhuguang/Documents/simulate/peer3"};

private static final String[] CONSENSUS_NODES = new String[]{
"127.0.0.1:6000",
"127.0.0.1:6010",
"127.0.0.1:6020",
"127.0.0.1:6030"};


@Override
public UserKeysVv userKeysVv(int nodeId) {

UserKeys userKeys = userKeys(nodeId);

return userKeys.toUserKeysVv();
}

@Override
public UserKeys userKeys(int nodeId) {

return new UserKeys("Peer-" + nodeId, PRIVKEYS[nodeId], PUBKEYS[nodeId], ENCODE_PWD);
}

@Override
public PeerLocalConfig nodePeerLocalConfig(int nodeId, boolean isMaster) {

UserKeys userKeys = userKeys(nodeId);

return peerSharedConfigVv(nodeId, isMaster).toPeerLocalConfig(userKeys);
}

@Override
public PeerSharedConfigVv peerSharedConfigVv(int nodeId, boolean isMaster) {

PeerSharedConfigVv sharedConfigVv = new PeerSharedConfigVv();

sharedConfigVv.setSharedKey(SHARED_KEY);
sharedConfigVv.setName(SHARED_KEY + "-" + nodeId);
sharedConfigVv.setInitAddr(LOCALHOST);
sharedConfigVv.setInitPort(INIT_PORT_START + nodeId * 10);
sharedConfigVv.setConsensusNode(CONSENSUS_NODES[nodeId]);
sharedConfigVv.setPubKey(PUBKEYS[nodeId]);
sharedConfigVv.setUserId(nodeId);
sharedConfigVv.setPeerPath(PEER_PATHS[nodeId]);
sharedConfigVv.setDbName(dbName());

if (isMaster) {
sharedConfigVv.setLedgerName(ledgerName());
sharedConfigVv.setNodeSize(TOTAL_SIZE);
} else {
sharedConfigVv.setMasterAddr(LOCALHOST);
sharedConfigVv.setMasterPort(8080);
}

return sharedConfigVv;
}

private String ledgerName() {

byte[] nameBytes = new byte[4];

RANDOM_ROCKSDB.nextBytes(nameBytes);

return Hex.encodeHexString(nameBytes);
}

private String dbName() {

byte[] nameBytes = new byte[4];

RANDOM_ROCKSDB.nextBytes(nameBytes);

return DB_NAME + Hex.encodeHexString(nameBytes);
}
}

+ 62
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java View File

@@ -0,0 +1,62 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.config.LedgerIdentification;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.state.*;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.model.user.UserKeysVv;

import java.util.List;
import java.util.Map;

public interface UmpStateService {

void save(String ledgerAndNodeKey, PeerLocalConfig localConfig);

void save(String ledgerKey, List<String> sharedConfigKeys);

void save(InstallSchedule installSchedule, MasterAddr masterAddr);

void save(UserKeys userKeys);

void save(LedgerPeerInstall peerInstall);

void save(LedgerMasterInstall masterInstall);

void save(LedgerIdentification identification);

void saveLedgerHash(String ledgerAndNodeKey, String ledgerHash);

List<UserKeys> readUserKeysList();

List<UserKeysVv> readUserKeysVvList();

UserKeys readUserKeys(int id);

PeerLocalConfig readConfig(String ledgerAndNodeKey);

PeerInstallSchedules loadState(String ledgerAndNodeKey);

PeerInstallSchedules loadInitState(String ledgerAndNodeKey);

PeerInstallSchedules readState(String ledgerAndNodeKey);

PeerInstallSchedules readInitState(String ledgerAndNodeKey);

Map<String, List<InstallSchedule>> readStates(String ledgerKey);

LedgerIdentification readIdentification(String ledgerAndNodeKey);

List<LedgerPeerInstall> readLedgerPeerInstalls();

List<LedgerMasterInstall> readLedgerMasterInstalls();

List<LedgerPeerInited> readLedgerPeerIniteds();

List<LedgerPeerInited> readLedgerPeerIniteds(String search);

List<LedgerInited> readLedgerIniteds(String search);

String readLedgerHash(String ledgerAndNodeKey);
}

+ 880
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java View File

@@ -0,0 +1,880 @@
package com.jd.blockchain.ump.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jd.blockchain.ump.dao.DBConnection;
import com.jd.blockchain.ump.model.*;
import com.jd.blockchain.ump.model.config.LedgerIdentification;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.state.*;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.model.user.UserKeysVv;
import com.jd.blockchain.ump.util.CommandUtils;
import com.jd.blockchain.ump.util.HttpJsonClientUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class UmpStateServiceHandler implements UmpStateService, Closeable {

private final Logger LOGGER = LoggerFactory.getLogger(getClass());

private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMM-ddHHmmss");

private static final String PEER_IDENTIFICATION_FORMAT = "PEER_IDENTIFICATION_INDEX_%s";

private static final String PEER_INSTALL_MAX_KEY = "PEER_INSTALL_MAX_INDEX";

private static final String PEER_INSTALL_KEY_FORMAT = "PEER_INSTALL_INDEX_%s";

private static final String MASTER_INSTALL_MAX_KEY = "MASTER_INSTALL_MAX_INDEX";

private static final String MASTER_INSTALL_KEY_FORMAT = "MASTER_INSTALL_INDEX_%s";

private static final String USERS_KEY_MAX_KEY = "USERS_KEY_MAX_INDEX";

private static final String USERS_KEY_FORMAT = "USERS_%s_REGISTER";

private static final String MAX_SIZE_KEY_SUFFIX = "_MAX_SIZE_KEY";

private static final String LEDGER_HASH_KEY_SUFFIX = "_LEDGER_HASH_KEY";

private static final String LEDGER_NODE_KEY_CONFIG_SUFFIX = "_LEDGER_NODE_CONFIG_KEY";

private static final String LEDGER_NODE_KEY_SUFFIX = "_LEDGER_NODE_KEY";

private static final String CURRENT_INDEX_KEY_SUFFIX_FORMAT = "_%s_INDEX_KEY";

private static final String PORT_ARG = "-p";

private static final String LOCALHOST = "127.0.0.1";

private ExecutorService singleHttpThread = Executors.newSingleThreadExecutor();

@Autowired
private DBConnection dbConnection;

@Autowired
private LedgerService ledgerService;

@Override
public synchronized void save(String ledgerAndNodeKey, PeerLocalConfig localConfig) {

String ledgerAndNodeConfigKey = ledgerAndNodeConfigKey(ledgerAndNodeKey);

dbConnection.put(ledgerAndNodeConfigKey, JSON.toJSONString(localConfig));
}

@Override
public synchronized void save(String ledgerKey, List<String> sharedConfigKeys) {

String ledgerAllNodeKey = ledgerAllNodeKey(ledgerKey);

StringBuilder sBuilder = new StringBuilder();

for (String sharedConfigKey : sharedConfigKeys) {
if (sBuilder.length() > 0) {
sBuilder.append(";");
}
sBuilder.append(sharedConfigKey);
}

dbConnection.put(ledgerAllNodeKey, sBuilder.toString());
}

@Override
public synchronized void save(InstallSchedule installSchedule, MasterAddr masterAddr) {
try {
String ledgerAndNodeKey = installSchedule.getLedgerAndNodeKey();
// 不使用队列,直接将其写入数据库
// 需要查询目前该Key对应的最大值是多少
String maxKey = ledgerAndNodeMaxKey(ledgerAndNodeKey);
String maxIdChars = dbConnection.get(maxKey);
int maxId = 0;
if (maxIdChars != null && maxIdChars.length() > 0) {
maxId = Integer.parseInt(maxIdChars) + 1;
}

String newKey = ledgerAndNodeCurrentNewKey(ledgerAndNodeKey, maxId);

// 内容写入数据库
dbConnection.put(newKey, installSchedule, InstallSchedule.class);

// 更新最大值
dbConnection.put(maxKey, String.valueOf(maxId));

if (masterAddr != null && masterAddr.legal()) {
singleHttpThread.execute(() -> {

try {
// 发送HTTP请求
HttpJsonClientUtils.httpPost(masterAddr, UmpConstant.REQUEST_STATE_URL, installSchedule, String.class, false);
} catch (Exception e) {
// 暂不关注是否发送成功
LOGGER.error(e.toString());
}

});
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

@Override
public synchronized void save(UserKeys userKeys) {

int maxIndex = maxIndex(USERS_KEY_MAX_KEY);

String userKey = usersKey(maxIndex);

// 重置userId
userKeys.setId(maxIndex);

// 将用户信息写入数据库
dbConnection.put(userKey, JSON.toJSONString(userKeys));

// 更新最大值
dbConnection.put(USERS_KEY_MAX_KEY, String.valueOf(maxIndex));

try {
// 将其放入文件中
String keysDirPath = UmpConstant.PROJECT_PATH + UmpConstant.PATH_CONFIG_KEYS;

File keysDir = new File(keysDirPath);

if (!keysDir.exists()) {
// 创建文件夹
keysDir.mkdir();
}
saveKeys2Files(keysDirPath, userKeys);
} catch (Exception e) {
LOGGER.error("Save Keys To File !", e);
}
}

@Override
public synchronized void save(LedgerPeerInstall peerInstall) {

int maxIndex = maxIndex(PEER_INSTALL_MAX_KEY);

// 将用户信息写入数据库
dbConnection.put(peerInstallKey(maxIndex), JSON.toJSONString(peerInstall));

// 更新最大值
dbConnection.put(PEER_INSTALL_MAX_KEY, String.valueOf(maxIndex));

}

@Override
public synchronized void save(LedgerMasterInstall masterInstall) {

int maxIndex = maxIndex(MASTER_INSTALL_MAX_KEY);

// 将用户信息写入数据库
dbConnection.put(masterInstallKey(maxIndex), JSON.toJSONString(masterInstall));

// 更新最大值
dbConnection.put(MASTER_INSTALL_MAX_KEY, String.valueOf(maxIndex));
}

@Override
public synchronized void save(LedgerIdentification identification) {

String ledgerAndNodeKey = identification.getLedgerAndNodeKey();

String idKey = String.format(PEER_IDENTIFICATION_FORMAT, ledgerAndNodeKey);

dbConnection.put(idKey, JSON.toJSONString(identification));
}

@Override
public void saveLedgerHash(String ledgerAndNodeKey, String ledgerHash) {

String ledgerHashKey = ledgerAndNodeHashKey(ledgerAndNodeKey);

dbConnection.put(ledgerHashKey, ledgerHash);
}

@Override
public List<UserKeys> readUserKeysList() {

List<UserKeys> userKeysList = new ArrayList<>();

String maxIndexChars = dbConnection.get(USERS_KEY_MAX_KEY);

if (maxIndexChars != null && maxIndexChars.length() > 0) {

int maxIndex = Integer.parseInt(maxIndexChars);

for (int i = 0; i <= maxIndex; i++) {
try {

String json = dbConnection.get(usersKey(i));

if (json != null && json.length() > 0) {
userKeysList.add(JSON.parseObject(json, UserKeys.class));
}
} catch (Exception e) {
LOGGER.error(e.toString());
}
}
}

return userKeysList;
}

@Override
public List<UserKeysVv> readUserKeysVvList() {

List<UserKeysVv> userKeysVvList = new ArrayList<>();

List<UserKeys> userKeysList = readUserKeysList();

if (!userKeysList.isEmpty()) {
for (UserKeys userKeys : userKeysList) {

userKeysVvList.add(userKeys.toUserKeysVv());
}
}

return userKeysVvList;
}

@Override
public UserKeys readUserKeys(int id) {

String userKey = usersKey(id);

String userKeysJson = dbConnection.get(userKey);

if (userKeysJson != null && userKeysJson.length() > 0) {
return JSON.parseObject(userKeysJson, UserKeys.class);
}

return null;
}

@Override
public PeerLocalConfig readConfig(String ledgerAndNodeKey) {

String json = dbConnection.get(ledgerAndNodeConfigKey(ledgerAndNodeKey));

if (json != null && json.length() > 0) {

return JSON.parseObject(json, PeerLocalConfig.class);
}

return null;
}

@Override
public PeerInstallSchedules loadState(String ledgerAndNodeKey) {

PeerInstallSchedules installSchedules = loadInitState(ledgerAndNodeKey);

String ledgerHash = ledgerService.readLedgerHash(ledgerAndNodeKey);

if (ledgerHash == null || ledgerHash.length() == 0) {
throw new IllegalStateException("Can not find LedgerHash from DataBase !!!");
}

return installSchedules.initLedgerHash(ledgerHash);

}

@Override
public PeerInstallSchedules loadInitState(String ledgerAndNodeKey) {
// 获取LedgerIdentification
LedgerIdentification identification = readIdentification(ledgerAndNodeKey);

if (identification == null) {
throw new IllegalStateException("Can not find LedgerIdentification from DataBase !!!");
}

return new PeerInstallSchedules(identification);
}

@Override
public PeerInstallSchedules readState(final String ledgerAndNodeKey) {

PeerInstallSchedules installSchedules = loadState(ledgerAndNodeKey);

loadInstallSchedules(installSchedules, ledgerAndNodeKey);

return installSchedules;
}

@Override
public PeerInstallSchedules readInitState(String ledgerAndNodeKey) {

PeerInstallSchedules installSchedules = loadInitState(ledgerAndNodeKey);

loadInstallSchedules(installSchedules, ledgerAndNodeKey);

return installSchedules;
}

@Override
public Map<String, List<InstallSchedule>> readStates(String ledgerKey) {

String ledgerAllNodeKey = ledgerAllNodeKey(ledgerKey);

String ledgerAllNodeValues = dbConnection.get(ledgerAllNodeKey);

String[] ledgerAndNodeKeys = ledgerAllNodeValues.split(";");

Map<String, List<InstallSchedule>> allInstallSchedules = new HashMap<>();

// 不存在就返回空值
if (ledgerAndNodeKeys.length > 0) {

for (String ledgerAndNodeKey : ledgerAndNodeKeys) {
// 获取每个LedgerAndNodeKey数据
List<InstallSchedule> installSchedules = readInstallSchedules(ledgerAndNodeKey);

if (installSchedules != null) {

allInstallSchedules.put(ledgerAndNodeKey, installSchedules);
}
}
}

return allInstallSchedules;
}

@Override
public LedgerIdentification readIdentification(String ledgerAndNodeKey) {

String idKey = String.format(PEER_IDENTIFICATION_FORMAT, ledgerAndNodeKey);

String identificationJson = dbConnection.get(idKey);

if (identificationJson != null && identificationJson.length() > 0) {

return JSON.parseObject(identificationJson, LedgerIdentification.class);
}

return null;
}

@Override
public List<LedgerPeerInstall> readLedgerPeerInstalls() {

List<LedgerPeerInstall> peerInstallList = new ArrayList<>();

String maxIndexChars = dbConnection.get(PEER_INSTALL_MAX_KEY);

if (maxIndexChars != null && maxIndexChars.length() > 0) {

int maxIndex = Integer.parseInt(maxIndexChars);

for (int i = 1; i <= maxIndex; i++) {
try {
String json = dbConnection.get(peerInstallKey(i));

if (json != null && json.length() > 0) {
peerInstallList.add(JSON.parseObject(json, LedgerPeerInstall.class));
}
} catch (Exception e) {
LOGGER.error(e.toString());
}
}
}

return peerInstallList;
}

@Override
public List<LedgerMasterInstall> readLedgerMasterInstalls() {

List<LedgerMasterInstall> masterInstalls = new ArrayList<>();

String maxIndexChars = dbConnection.get(PEER_INSTALL_MAX_KEY);

if (maxIndexChars != null && maxIndexChars.length() > 0) {

int maxIndex = Integer.parseInt(maxIndexChars);

for (int i = 1; i <= maxIndex; i++) {
try {
String json = dbConnection.get(masterInstallKey(i));

if (json != null && json.length() > 0) {
masterInstalls.add(JSON.parseObject(json, LedgerMasterInstall.class));
}
} catch (Exception e) {
LOGGER.error(e.toString());
}
}
}

return masterInstalls;
}

@Override
public List<LedgerPeerInited> readLedgerPeerIniteds() {

List<LedgerPeerInited> peerIniteds = new ArrayList<>();

List<LedgerPeerInstall> peerInstalls = readLedgerPeerInstalls();

if (!peerInstalls.isEmpty()) {

LOGGER.info("Read LedgerPeerInstalls, Size = {}", peerInstalls.size());
for (LedgerPeerInstall peerInstall : peerInstalls) {

String ledgerAndNodeKey = peerInstall.getLedgerAndNodeKey();

// 数据库中读取存放的LedgerHash
String ledgerHash = readLedgerHash(ledgerAndNodeKey);

if (ledgerHash == null || ledgerHash.length() == 0) {
continue;
}

LedgerPeerInited peerInited = new LedgerPeerInited(ledgerHash, peerInstall);

// 检测账本中的Hash是否真正存在
StartupState startupState = StartupState.UNKNOWN;
try {
startupState = startupState(ledgerHash, peerInstall);
} catch (Exception e) {
LOGGER.error("Check Ledger Hash Exist !!!", e);
}

// 设置账本状态
peerInited.setStartupState(startupState);

// 添加到集合
peerIniteds.add(peerInited);
}
} else {
LOGGER.error("Read LedgerPeerInstalls is Empty !!!");
}
return peerIniteds;
}

@Override
public List<LedgerPeerInited> readLedgerPeerIniteds(String search) {

List<LedgerPeerInited> initedList = readLedgerPeerIniteds();

if (search != null && search.length() > 0 && !initedList.isEmpty()) {

List<LedgerPeerInited> filterInitedList = new ArrayList<>();

for (LedgerPeerInited peerInited : initedList) {
if (isMatch(peerInited, search)) {
filterInitedList.add(peerInited);
}
}

return filterInitedList;
}

return initedList;
}

@Override
public List<LedgerInited> readLedgerIniteds(String search) {

List<LedgerInited> ledgerInitedsFromConf = loadAllLedgerIniteds(UmpConstant.PROJECT_PATH);

if (!ledgerInitedsFromConf.isEmpty()) {

List<LedgerInited> ledgerIniteds = new ArrayList<>();

for (LedgerInited ledgerInited : ledgerInitedsFromConf) {

if (isMatch(ledgerInited, search)) {
ledgerIniteds.add(ledgerInited);
}
}

return ledgerIniteds;
}

return ledgerInitedsFromConf;
}

@Override
public String readLedgerHash(String ledgerAndNodeKey) {

String ledgerHashKey = ledgerAndNodeHashKey(ledgerAndNodeKey);

return dbConnection.get(ledgerHashKey);
}

@Override
public void close() throws IOException {
// writeRunner.close();
}

private boolean isMatch(LedgerInited ledgerInited, String search) {

if (search == null || search.length() == 0) {
return true;
}

String ledgerHash = ledgerInited.getLedgerHash();
String ledgerName = ledgerInited.getLedgerName();
String partiName = ledgerInited.getPartiName();
String partiAddress = ledgerInited.getPartiAddress();
String dbUri = ledgerInited.getDbUri();
StartupState startupState = ledgerInited.getStartupState();

if (
ledgerHash.contains(search) ||
startupState.toString().equals(search) ||
ledgerName.contains(search) ||
partiName.contains(search) ||
partiAddress.contains(search) ||
dbUri.contains(search)
) {
return true;
}
return false;
}

private boolean isMatch(LedgerPeerInited peerInited, String search) {

if (search == null || search.length() == 0) {
return true;
}

String ledgerHash = peerInited.getLedgerHash();
StartupState startupState = peerInited.getStartupState();
LedgerPeerInstall peerInstall = peerInited.getPeerInstall();

if (ledgerHash.contains(search) ||
startupState.toString().equals(search) ||
peerInstall.getNodeName().contains(search) ||
peerInstall.getCreateTime().contains(search)
) {
return true;
}
return false;
}

private void loadInstallSchedules(PeerInstallSchedules installSchedules, String ledgerAndNodeKey) {
List<InstallSchedule> schedules = readInstallSchedules(ledgerAndNodeKey);

for (InstallSchedule installSchedule : schedules) {
installSchedules.addInstallSchedule(
new PeerInstallSchedule(installSchedule.getProcess(), installSchedule.getState()));
}
}

private List<InstallSchedule> readInstallSchedules(String ledgerAndNodeKey) {
String maxKey = ledgerAndNodeMaxKey(ledgerAndNodeKey);
String maxIdChars = dbConnection.get(maxKey);
if (maxIdChars == null || maxIdChars.length() == 0) {
return null;
}
int maxId = Integer.parseInt(maxIdChars);

List<InstallSchedule> schedules = new ArrayList<>();

for (int i = 0; i <= maxId; i++) {

try {
String currentKey = ledgerAndNodeCurrentNewKey(ledgerAndNodeKey, i);

String jsonChars = dbConnection.get(currentKey);

if (jsonChars != null && jsonChars.length() > 0) {
schedules.add(JSON.parseObject(jsonChars, InstallSchedule.class));
}
} catch (Exception e) {
// 打印错误,暂不处理其他
LOGGER.error(e.toString());
}
}

return schedules;
}

private List<LedgerInited> loadAllLedgerIniteds(String peerPath) {

List<LedgerInited> ledgerInitedsFromConf = ledgerService.allLedgerIniteds(peerPath);

if (!ledgerInitedsFromConf.isEmpty()) {

// 逐个检查其状态
for (LedgerInited ledgerInited : ledgerInitedsFromConf) {
// 判断该账本对应的数据库是否存在
if (!dbConnection.exist(ledgerInited.getDbUri())) {
ledgerInited.setStartupState(StartupState.DB_UNEXIST);
continue;
}

String peerVerify = ledgerService.peerVerifyKey(peerPath);

try {
if (!CommandUtils.isActive(peerVerify)) {
// 进程不存在
LOGGER.info("Can not find Peer Process {} !!!", peerVerify);
ledgerInited.setStartupState(StartupState.UNLOAD);
continue;
}
} catch (Exception e) {
// 进程处理错误打印日志即可
LOGGER.error(String.format("Command Check %s !!!", peerVerify), e);
}
// 查看该进程对应的监听端口
try {
int listenPort = listenPort(peerVerify);

LOGGER.info("Find Listen Port = {} !", listenPort);

if (listenPort > 0) {

int maxSize = 5, checkIndex = 1;

boolean isRead = false;

while (maxSize > 0) {

try {
// 发送请求到对应地址
JSONArray ledgerHashs = HttpJsonClientUtils.httpGet(ledgersUrl(listenPort), JSONArray.class, true);

if (ledgerHashs != null && !ledgerHashs.isEmpty()) {
for(Object hashObj : ledgerHashs) {
if (hashObj instanceof JSONObject) {
if (ledgerInited.getLedgerHash().equals(((JSONObject) hashObj).getString("value"))) {
// 说明该账本已经被加载
ledgerInited.setStartupState(StartupState.LOADED);
isRead = true;
break;
}
}
}
if (isRead) {
break;
}
}

// 6秒休眠
Thread.sleep(6000);
} catch (Exception e) {
LOGGER.error(String.format("Request LedgerHashs from PeerNode [%s]", checkIndex++), e);
}

maxSize --;
}

if (!isRead) {
// 表明等待加载,无须再启动
ledgerInited.setStartupState(StartupState.LOADING);
}
}
} catch (Exception e) {
LOGGER.error(String.format("Command [%s] 'Listen Port Check !!!", peerVerify), e);
}
}
}

return ledgerInitedsFromConf;
}

private StartupState startupState(String ledgerHash, LedgerPeerInstall peerInstall) {

String peerPath = peerInstall.getPeerPath();

// 首先检查文件中是否存在该Hash值
LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(peerPath);

Set<String> allLedgerHashs = ledgerBindingConf.getLedgerHashs();

if (!allLedgerHashs.contains(ledgerHash)) {

// 文件中不存在
return StartupState.UNEXIST;
}

// 判断该账本对应的数据库是否存在
if (!ledgerService.dbExist(peerPath, ledgerHash)) {

// 该账本对应数据库不存在
return StartupState.DB_UNEXIST;
}

// 文件中存在则检查进程是否存在
// 进程存在标识为LOADED,否则标识为LOADING,暂时用不到LOADING
String peerVerify = ledgerService.peerVerifyKey(peerPath);

try {
if (!CommandUtils.isActive(peerVerify)) {
// 进程不存在
return StartupState.UNLOAD;
}

} catch (Exception e) {
// 进程处理错误打印日志即可
LOGGER.error(String.format("Command Check %s !!!", peerVerify), e);
}

// 查看该进程对应的监听端口
try {
int listenPort = listenPort(peerVerify);

LOGGER.info("Find Listen Port = {} !", listenPort);

if (listenPort > 0) {
// 发送请求到对应地址
JSONArray ledgerHashs = HttpJsonClientUtils.httpGet(ledgersUrl(listenPort), JSONArray.class, true);

if (ledgerHashs != null && !ledgerHashs.isEmpty()) {
for(Object hashObj : ledgerHashs) {
if (hashObj instanceof JSONObject) {
if (ledgerHash.equals(((JSONObject) hashObj).getString("value"))) {
// 说明该账本已经被加载
return StartupState.LOADED;
}
}
}
// 表明等待加载,无须再启动
return StartupState.LOADING;
}
}
} catch (Exception e) {
LOGGER.error(String.format("Command [%s] 'Listen Port Check !!!", peerVerify), e);
}

return StartupState.UNKNOWN;
}

private String ledgersUrl(int listenPort) {
return "http://" + LOCALHOST + ":" + listenPort + "/ledgers";
}

private int listenPort(String peerVerify) throws Exception {

String portArg = mainArg(peerVerify, PORT_ARG);

if (portArg != null && portArg.length() > 0) {
return Integer.parseInt(portArg);
}

return 0;
}

private String mainArg(String processName, String argKey) throws Exception {

String[] cmdLineArray = mainArgs(processName);

if (cmdLineArray != null && cmdLineArray.length > 0) {
for (int i = 0; i < cmdLineArray.length; i++) {
String currArg = cmdLineArray[i].trim();
if (currArg.equals(argKey) && (i + 1) < cmdLineArray.length) {
return cmdLineArray[i+1].trim();
}
}
}
return null;
}

private String[] mainArgs(String processName) throws Exception {

String mainArgs = CommandUtils.mainArgs(processName);

if (mainArgs != null && mainArgs.length() > 0) {
///Users/shaozhuguang/Documents/newenv/peer4/system/deployment-peer-1.1.0-SNAPSHOT.jar -home=/Users/shaozhuguang/Documents/newenv/peer4 -c /Users/shaozhuguang/Documents/newenv/peer4/config/ledger-binding.conf -p 7080
return mainArgs.split(" ");
}

return null;
}

private synchronized int maxIndex(String key) {
int maxIndex = 1;
String maxIndexChars = dbConnection.get(key);
if (maxIndexChars != null && maxIndexChars.length() > 0) {
maxIndex = Integer.parseInt(maxIndexChars) + 1;
}
return maxIndex;
}

private String usersKey(int userId) {
return String.format(USERS_KEY_FORMAT, userId);
}

private String peerInstallKey(int index) {
return String.format(PEER_INSTALL_KEY_FORMAT, index);
}

private String masterInstallKey(int index) {
return String.format(MASTER_INSTALL_KEY_FORMAT, index);
}

private String ledgerAndNodeConfigKey(String ledgerAndNodeKey) {

return ledgerAndNodeKey + LEDGER_NODE_KEY_CONFIG_SUFFIX;
}

private String ledgerAllNodeKey(String ledgerKey) {

return ledgerKey + LEDGER_NODE_KEY_SUFFIX;
}

private String ledgerAndNodeMaxKey(String ledgerAndNodeKey) {

return ledgerAndNodeKey + MAX_SIZE_KEY_SUFFIX;
}

private String ledgerAndNodeHashKey(String ledgerAndNodeKey) {

return ledgerAndNodeKey + LEDGER_HASH_KEY_SUFFIX;
}

private String ledgerAndNodeCurrentNewKey(String ledgerAndNodeKey, int currentId) {

return String.format(
ledgerAndNodeKey + CURRENT_INDEX_KEY_SUFFIX_FORMAT,
currentId);
}

private void saveKeys2Files(String keysDirPath, UserKeys userKeys) throws IOException {

// 写入私钥
write(keysDirPath, userKeys.getName(), UmpConstant.PRIVATE_KEY_SUFFIX, userKeys.getPrivKey());
// 写入公钥
write(keysDirPath, userKeys.getName(), UmpConstant.PUBLIC_KEY_SUFFIX, userKeys.getPubKey());
// 写入密钥
write(keysDirPath, userKeys.getName(), UmpConstant.PWD_SUFFIX, userKeys.getEncodePwd());
}

private void write(String keysDirPath, String name, String suffix, String writeContent) throws IOException {

String keyeFilePath = keysDirPath + File.separator + name + suffix;

File keysFile = new File(keyeFilePath);

if (keysFile.exists()) {
// 文件存在,备份文件
FileUtils.copyFile(keysFile, new File(keyeFilePath + "_bak_" + currentTime()));
}

// 将Priv文件内容写入
FileUtils.writeStringToFile(keysFile, writeContent, StandardCharsets.UTF_8);
}

private String currentTime() {
return SDF.format(new Date());
}
}

+ 15
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java View File

@@ -0,0 +1,15 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.ump.model.user.UserKeyBuilder;
import com.jd.blockchain.ump.model.user.UserKeys;

public interface UtilService {

UserKeys create(UserKeyBuilder builder);

UserKeys create(String name, String seed, String pwd);

UserKeys read(int id);

boolean verify(UserKeys userKeys, String pwd);
}

+ 80
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java View File

@@ -0,0 +1,80 @@
package com.jd.blockchain.ump.service;

import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm;
import com.jd.blockchain.crypto.utils.classic.ED25519Utils;
import com.jd.blockchain.ump.model.user.UserKeyBuilder;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.security.ShaUtils;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.prng.FixedSecureRandom;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.Charset;

import static com.jd.blockchain.tools.keygen.KeyGenCommand.encodePrivKey;
import static com.jd.blockchain.tools.keygen.KeyGenCommand.encodePubKey;

@Service
public class UtilServiceHandler implements UtilService {

private static final String UTF_8 = "UTF-8";

@Autowired
private UmpStateService umpStateService;

@Override
public UserKeys create(UserKeyBuilder builder) {

return create(builder.getName(), builder.getSeed(), builder.getPwd());
}

@Override
public UserKeys create(String name, String seed, String pwd) {

AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair(
new FixedSecureRandom(seed.getBytes(Charset.forName(UTF_8))));

PubKey pubKey = new PubKey(ClassicAlgorithm.ED25519,
((Ed25519PublicKeyParameters) keyPair.getPublic()).getEncoded());

PrivKey privKey = new PrivKey(ClassicAlgorithm.ED25519,
((Ed25519PrivateKeyParameters) keyPair.getPrivate()).getEncoded());

return create(name, pubKey, privKey, pwd);
}

@Override
public UserKeys read(int userId) {

return umpStateService.readUserKeys(userId);
}

@Override
public boolean verify(UserKeys userKeys, String pwd) {

String encodePwd = Base58Utils.encode((ShaUtils.hash_256(pwd.getBytes(Charset.forName(UTF_8)))));

if (encodePwd.equals(userKeys.getEncodePwd())) {
return true;
}
return false;
}

private UserKeys create(String name, PubKey pubKey, PrivKey privKey, String pwd) {

byte[] pwdBytes = ShaUtils.hash_256(pwd.getBytes(Charset.forName(UTF_8)));

return new UserKeys(
name,
encodePrivKey(privKey, pwdBytes),
encodePubKey(pubKey),
// pwd, // 密码不保存到数据库,防止泄露
Base58Utils.encode(pwdBytes));
}
}

+ 21
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java View File

@@ -0,0 +1,21 @@
package com.jd.blockchain.ump.service.consensus;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;

import java.util.List;
import java.util.Properties;

public interface ConsensusProvider {

String NEXT_LINE = "\r\n";

String provider();

String configFilePath();

void setConfig(Properties properties);

Properties getConfig();

byte[] handleSharedConfigs(List<PeerLocalConfig> sharedConfigs);
}

+ 10
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java View File

@@ -0,0 +1,10 @@
package com.jd.blockchain.ump.service.consensus;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;

import java.util.List;

public interface ConsensusService {

String initConsensusConf(String consensusProvider, List<PeerLocalConfig> sharedConfigs);
}

+ 79
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java View File

@@ -0,0 +1,79 @@
package com.jd.blockchain.ump.service.consensus;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.util.Base58Utils;
import org.reflections.Reflections;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ConsensusServiceHandler implements ConsensusService {

private static final Map<String, ConsensusProvider> CONSENSUS_PROVIDERS = new ConcurrentHashMap<>();

static {
try {
initProviders();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

@Override
public String initConsensusConf(String consensusProvider, List<PeerLocalConfig> sharedConfigs) {
// 首先根据provider获取对应的配置信息
ConsensusProvider provider = CONSENSUS_PROVIDERS.get(consensusProvider);

if (provider == null) {
throw new IllegalStateException(
String.format("ConsensusProvider[%s] can not find Manage-Class !!!", consensusProvider));
}

byte[] result = provider.handleSharedConfigs(sharedConfigs);

return Base58Utils.encode(result);
}

private static void initProviders() {
// 初始化所有实现类
Reflections reflections = new Reflections("com.jd.blockchain.ump.service.consensus");

Set<Class<? extends ConsensusProvider>> providerSet =
reflections.getSubTypesOf(ConsensusProvider.class);

for (Class<? extends ConsensusProvider> clazz : providerSet) {

if (!clazz.isInterface()) {
try {
// 根据class生成对象
ConsensusProvider provider = clazz.newInstance();
String providerKey = provider.provider();
if (providerKey != null && providerKey.length() > 0 &&
!CONSENSUS_PROVIDERS.containsKey(providerKey)) {

// 根据value读取配置文件中的内容
InputStream currentFileInputStream = ConsensusServiceHandler.class.getResourceAsStream(
File.separator + provider.configFilePath());

Properties currentProps = new Properties();

currentProps.load(currentFileInputStream);

provider.setConfig(currentProps);

CONSENSUS_PROVIDERS.put(providerKey, provider);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
}
}

+ 162
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java View File

@@ -0,0 +1,162 @@
package com.jd.blockchain.ump.service.consensus.providers;


import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.config.PeerSharedConfig;
import com.jd.blockchain.ump.service.consensus.ConsensusProvider;

import java.nio.charset.StandardCharsets;
import java.util.*;

public class BftsmartConsensusProvider implements ConsensusProvider {

public static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider";

public static final String BFTSMART_CONFIG_FILE = "bftsmart.config";

private static final int MIN_PARTI_SIZE = 4;

private Properties bftsmartProps;

@Override
public String provider() {
return BFTSMART_PROVIDER;
}

@Override
public String configFilePath() {
return BFTSMART_CONFIG_FILE;
}

@Override
public void setConfig(Properties properties) {
bftsmartProps = properties;
}

@Override
public Properties getConfig() {
return bftsmartProps;
}

@Override
public byte[] handleSharedConfigs(List<PeerLocalConfig> sharedConfigs) {

// 首先校验其中的ConsensusNode是否完全一致,若完全一致则不可以
verify(sharedConfigs);

StringBuilder sBuilder = new StringBuilder();

// 先加入当前节点信息
List<String> nodeConfigs = nodeConfigs(sharedConfigs);

for (String nodeConfig : nodeConfigs) {
sBuilder.append(nodeConfig).append(NEXT_LINE);
}

int nodeNum = sharedConfigs.size();

// 写入之前配置文件中的内容
for (Map.Entry<Object, Object> entry : bftsmartProps.entrySet()) {

// 获取Key-Value
String key = (String) entry.getKey(), value = (String) entry.getValue();

// 对特殊的Key和Value单独处理
/**
* system.servers.num = 4
*
* system.servers.f = 1
*
* system.initial.view = 0,1,2,3
*/
if (key.startsWith(BftsmartConstant.SERVERS_NUM_PREFIX)) {

sBuilder.append(BftsmartConstant.SERVERS_NUM_PREFIX + " = " + nodeNum).append(NEXT_LINE);
} else if (key.startsWith(BftsmartConstant.SERVERS_F_PREFIX)) {

sBuilder.append(BftsmartConstant.SERVERS_F_PREFIX + " = " + nodeFNum(nodeNum)).append(NEXT_LINE);
} else if (key.startsWith(BftsmartConstant.INIT_VIEW_PREFIX)) {

sBuilder.append(BftsmartConstant.INIT_VIEW_PREFIX + " = " + initView(nodeNum)).append(NEXT_LINE);
} else {

sBuilder.append(key + " = " + value).append(NEXT_LINE);
}
}

return sBuilder.toString().getBytes(StandardCharsets.UTF_8);
}

private String initView(int nodeNum) {

StringBuilder views = new StringBuilder();

for (int i = 0; i < nodeNum; i++) {
if (views.length() > 0) {
views.append(",");
}
views.append(i);
}
return views.toString();
}

private void verify(List<PeerLocalConfig> sharedConfigs) {

Set<String> consensusInfos = new HashSet<>();

if (sharedConfigs == null) {
throw new IllegalStateException("Shared Configs is NULL !!!");
}

if (sharedConfigs.size() < MIN_PARTI_SIZE) {
throw new IllegalStateException(
String.format("Shared Configs's size = %s, can not meet minimum %s !!!",
sharedConfigs.size(), MIN_PARTI_SIZE));
}

for (PeerLocalConfig sharedConfig : sharedConfigs) {
String consensusInfo = sharedConfig.getConsensusNode();
if (consensusInfos.contains(consensusInfo)) {
throw new IllegalStateException("Shared Configs's Consensus may be conflict !!!");
}
consensusInfos.add(consensusInfo);
}
}

private List<String> nodeConfigs(List<PeerLocalConfig> sharedConfigs) {

List<String> nodeConfigs = new ArrayList<>();

if (sharedConfigs != null && !sharedConfigs.isEmpty()) {
for (int i = 0; i < sharedConfigs.size(); i++) {

PeerSharedConfig sharedConfig = sharedConfigs.get(i);

String consensusNode = sharedConfig.getConsensusNode();

String[] hostAndPort = consensusNode.split(":");

nodeConfigs.add(String.format(BftsmartConstant.HOST_FORMAT, i, hostAndPort[0]));

nodeConfigs.add(String.format(BftsmartConstant.PORT_FORMAT, i, hostAndPort[1]));

nodeConfigs.add(String.format(BftsmartConstant.SECURE_FORMAT, i, false));

}
}

return nodeConfigs;
}

private int nodeFNum(int nodeNum) {
/**
* 3F+1
*
* 假设有4个节点,则可有一个,若有N个,则N-1/3
*/
if (nodeNum < 4) {
return 0;
}
return (nodeNum - 1) / 3;
}
}

+ 17
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java View File

@@ -0,0 +1,17 @@
package com.jd.blockchain.ump.service.consensus.providers;

public class BftsmartConstant {

public static final String HOST_FORMAT = "system.server.%s.network.host=%s";

public static final String PORT_FORMAT = "system.server.%s.network.port=%s";

public static final String SECURE_FORMAT = "system.server.%s.network.secure=%s";

public static final String SERVERS_NUM_PREFIX = "system.servers.num";

public static final String SERVERS_F_PREFIX = "system.servers.f";

public static final String INIT_VIEW_PREFIX = "system.initial.view";

}

+ 41
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java View File

@@ -0,0 +1,41 @@
package com.jd.blockchain.ump.service.consensus.providers;

import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.service.consensus.ConsensusProvider;

import java.util.List;
import java.util.Properties;

public class MsgQueueConsensusProvider implements ConsensusProvider {

private static final String MSGQUEUE_PROVIDER = "com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider";

private static final String MSGQUEUE_CONFIG_FILE = "mq.config";

private Properties msgQueueProps;

@Override
public String provider() {
return MSGQUEUE_PROVIDER;
}

@Override
public String configFilePath() {
return MSGQUEUE_CONFIG_FILE;
}

@Override
public void setConfig(Properties properties) {
this.msgQueueProps = properties;
}

@Override
public Properties getConfig() {
return msgQueueProps;
}

@Override
public byte[] handleSharedConfigs(List<PeerLocalConfig> sharedConfigs) {
return new byte[0];
}
}

+ 153
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java View File

@@ -0,0 +1,153 @@
package com.jd.blockchain.ump.util;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

public class Base58Utils {

public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();

private static final int[] INDEXES = new int[128];

static {
for (int i = 0; i < INDEXES.length; i++) {
INDEXES[i] = -1;
}
for (int i = 0; i < ALPHABET.length; i++) {
INDEXES[ALPHABET[i]] = i;
}
}

/**
* Encodes the given bytes in base58. No checksum is appended.
*/
public static String encode(byte[] input) {
if (input.length == 0) {
return "";
}
input = copyOfRange(input, 0, input.length);
// Count leading zeroes.
int zeroCount = 0;
while (zeroCount < input.length && input[zeroCount] == 0) {
++zeroCount;
}
// The actual encoding.
byte[] temp = new byte[input.length * 2];
int j = temp.length;

int startAt = zeroCount;
while (startAt < input.length) {
byte mod = divmod58(input, startAt);
if (input[startAt] == 0) {
++startAt;
}
temp[--j] = (byte) ALPHABET[mod];
}

// Strip extra '1' if there are some after decoding.
while (j < temp.length && temp[j] == ALPHABET[0]) {
++j;
}
// Add as many leading '1' as there were leading zeros.
while (--zeroCount >= 0) {
temp[--j] = (byte) ALPHABET[0];
}

byte[] output = copyOfRange(temp, j, temp.length);
try {
return new String(output, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen.
}
}

public static byte[] decode(String input) throws IllegalArgumentException {
if (input.length() == 0) {
return new byte[0];
}
byte[] input58 = new byte[input.length()];
// Transform the String to a base58 byte sequence
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);

int digit58 = -1;
if (c >= 0 && c < 128) {
digit58 = INDEXES[c];
}
if (digit58 < 0) {
throw new IllegalArgumentException("Illegal character " + c + " at " + i);
}

input58[i] = (byte) digit58;
}
// Count leading zeroes
int zeroCount = 0;
while (zeroCount < input58.length && input58[zeroCount] == 0) {
++zeroCount;
}
// The encoding
byte[] temp = new byte[input.length()];
int j = temp.length;

int startAt = zeroCount;
while (startAt < input58.length) {
byte mod = divmod256(input58, startAt);
if (input58[startAt] == 0) {
++startAt;
}

temp[--j] = mod;
}
// Do no add extra leading zeroes, move j to first non null byte.
while (j < temp.length && temp[j] == 0) {
++j;
}

return copyOfRange(temp, j - zeroCount, temp.length);
}

public static BigInteger decodeToBigInteger(String input) throws IllegalArgumentException {
return new BigInteger(1, decode(input));
}

//
// number -> number / 58, returns number % 58
//
private static byte divmod58(byte[] number, int startAt) {
int remainder = 0;
for (int i = startAt; i < number.length; i++) {
int digit256 = (int) number[i] & 0xFF;
int temp = remainder * 256 + digit256;

number[i] = (byte) (temp / 58);

remainder = temp % 58;
}

return (byte) remainder;
}

//
// number -> number / 256, returns number % 256
//
private static byte divmod256(byte[] number58, int startAt) {
int remainder = 0;
for (int i = startAt; i < number58.length; i++) {
int digit58 = (int) number58[i] & 0xFF;
int temp = remainder * 58 + digit58;

number58[i] = (byte) (temp / 256);

remainder = temp % 256;
}

return (byte) remainder;
}

private static byte[] copyOfRange(byte[] source, int from, int to) {
byte[] range = new byte[to - from];
System.arraycopy(source, from, range, 0, range.length);

return range;
}
}

+ 133
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java View File

@@ -0,0 +1,133 @@
package com.jd.blockchain.ump.util;

import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;

import java.util.*;

public class CommandUtils {

public static void killVm(String processName) throws Exception {

MonitoredVm activeVm = activeVm(processName);

if (activeVm != null) {
killVm(activeVm);
}
}

public static void killVm(MonitoredVm vm) throws Exception {
if (vm != null) {
int vmId = vm.getVmIdentifier().getLocalVmId();
List<String> killCmd = killCommand(vmId);
execute(killCmd);
}
}

public static List<String> toCommandList(String cmd) {
// 要求使用空格
String[] cmdArray = cmd.split(" ");

if (cmdArray.length > 0) {
return Arrays.asList(cmdArray);
}

return null;

}

public static Process execute(List<String> cmds) throws Exception {

if (cmds == null || cmds.isEmpty()) {
throw new IllegalStateException("Command's List is NULL !!!");
}

ProcessBuilder pBuilder = new ProcessBuilder(cmds);

Process process = pBuilder.start();

return process;

}

public static boolean executeAndVerify(List<String> cmds, String verify) throws Exception {

if (cmds == null || cmds.isEmpty()) {
throw new IllegalStateException("Command's List is NULL !!!");
}

ProcessBuilder pBuilder = new ProcessBuilder(cmds);

pBuilder.start();

// 时延5s,再进行判断
Thread.sleep(5000);

return isActive(verify);

}

public static MonitoredVm activeVm(String processName) throws Exception {

MonitoredHost localMonitored = MonitoredHost.getMonitoredHost("localhost");

Set<Integer> activeVms = new HashSet<>(localMonitored.activeVms());

for (Integer vmId : activeVms) {

try {
MonitoredVm vm = localMonitored.getMonitoredVm(new VmIdentifier("//" + vmId));

String vmProcessName = MonitoredVmUtil.mainClass(vm, true);

if (vmProcessName.contains(processName)) {
return vm;
}
} catch (Exception e) {
// 此处异常打印即可,不需要处理
System.err.println(e);
}
}

return null;
}

public static boolean isActive(String processName) throws Exception {

MonitoredVm activeVm = activeVm(processName);

return activeVm != null;
}

public static String mainArgs(MonitoredVm vm) {
if (vm != null) {
try {
return MonitoredVmUtil.mainArgs(vm);
} catch (Exception e) {
// 打印日志即可
System.err.println(e);
}
}
return null;
}

public static String mainArgs(String processName) throws Exception {

return mainArgs(activeVm(processName));
}

public static List<String> killCommand(int vmId) {
if (vmId > 1) {
List<String> killCmd = new ArrayList<>();
killCmd.add("kill");
killCmd.add("-9");
killCmd.add(String.valueOf(vmId));

return killCmd;
}

throw new IllegalStateException(String.format("Can not kill Process ID = [%s]", vmId));
}
}

+ 289
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java View File

@@ -0,0 +1,289 @@
/**
* Copyright: Copyright 2016-2020 JD.COM All Right Reserved
* FileName: com.jd.blockchain.utils.http.agent.HttpClientPool
* Author: shaozhuguang
* Department: 区块链研发部
* Date: 2019/1/14 下午3:20
* Description:
*/
package com.jd.blockchain.ump.util;

import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
*
* @author shaozhuguang
* @create 2019/1/14
* @since 1.0.0
*/

public class HttpClientPool {

private static final int TEN_MINUTE = 600 * 1000;

private static final int TIME_OUT = TEN_MINUTE;

private static final int CONNECT_TIME_OUT = TEN_MINUTE;

private static final int SOCKET_TIME_OUT = TEN_MINUTE;

private static final int MAX_TOTAL = 200;

private static final int MAX_PER_ROUTE = 40;

private static final int MAX_ROUTE = 100;

private static final int RETRY_COUNT = 5;

private static final String DEFAULT_CHARSET = "UTF-8";

private static final Map<String, CloseableHttpClient> httpClients = new ConcurrentHashMap<>();

private final static Lock lock = new ReentrantLock();

private static void config(HttpRequestBase httpRequestBase) {
// 配置请求的超时设置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(TIME_OUT)
.setConnectTimeout(CONNECT_TIME_OUT)
.setSocketTimeout(SOCKET_TIME_OUT)
.build();
httpRequestBase.setConfig(requestConfig);
}

/**
* 获取HttpClient对象
*
* @param url
* @return
*/
public static CloseableHttpClient getHttpClient(String url) {
String hostName = url.split("/")[2];
int port = 80;
if (hostName.contains(":")) {
String[] arr = hostName.split(":");
hostName = arr[0];
port = Integer.parseInt(arr[1]);
}
return getHttpClient(hostName, port);
}

/**
* 获取HttpClient对象
*
* @param hostName
* @param port
* @return
*/
public static CloseableHttpClient getHttpClient(String hostName, int port) {
String key = hostName + ":" + port;
CloseableHttpClient httpClient = httpClients.get(key);
if (httpClient == null) {
try {
lock.lock();
if (httpClient == null) {
httpClient = createHttpClient(MAX_TOTAL, MAX_PER_ROUTE, MAX_ROUTE, hostName, port);
httpClients.put(key, httpClient);
}
} finally {
lock.unlock();
}
}
return httpClient;
}

/**
* 创建HttpClient
*
* @param maxTotal
* @param maxPerRoute
* @param maxRoute
* @param hostname
* @param port
* @return
*/
public static CloseableHttpClient createHttpClient(int maxTotal,
int maxPerRoute, int maxRoute, String hostname, int port) {
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
.getSocketFactory();
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
.getSocketFactory();
Registry<ConnectionSocketFactory> registry = RegistryBuilder
.<ConnectionSocketFactory> create().register("http", plainsf)
.register("https", sslsf).build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
registry);
cm.setMaxTotal(maxTotal);
cm.setDefaultMaxPerRoute(maxPerRoute);
HttpHost httpHost = new HttpHost(hostname, port);
cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);
HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> {
if (executionCount >= RETRY_COUNT) {// 最多重试5次
return false;
}else if (exception instanceof NoHttpResponseException) {
return true;
}else if (exception instanceof SSLException) {
return false;
}else if (exception instanceof InterruptedIOException) {
return false;
}else if (exception instanceof SSLHandshakeException) {
return false;
}else if (exception instanceof UnknownHostException) {
return false;
}else if (exception instanceof ConnectTimeoutException) {
return false;
}

HttpClientContext clientContext = HttpClientContext
.adapt(context);
HttpRequest request = clientContext.getRequest();
if (!(request instanceof HttpEntityEnclosingRequest)) {
return true;
}
return false;
};

CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setRetryHandler(httpRequestRetryHandler).build();

return httpClient;
}

private static void setPostParams(HttpPost httpPost,
Map<String, Object> params) {
List<NameValuePair> nameValuePairs = new ArrayList<>();
Set<String> keySet = params.keySet();
for (String key : keySet) {
nameValuePairs.add(new BasicNameValuePair(key, params.get(key).toString()));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}

private static void setJsonPostParams(HttpPost httpPost, String json) {
httpPost.addHeader("Content-type","application/json; charset=utf-8");
httpPost.setHeader("Accept", "application/json");
httpPost.setEntity(new StringEntity(json, Charset.forName("UTF-8")));
}

/**
* POST请求
*
* @param url
* @param params
* @return String
* @throws IOException
*/
public static String post(String url, Map<String, Object> params) throws IOException {
HttpPost httpPost = new HttpPost(url);
config(httpPost);
setPostParams(httpPost, params);
try (CloseableHttpResponse response = httpPost(url, httpPost)) {
return parseResponse(response);
}
}

public static String jsonPost(String url, String json) throws IOException {
HttpPost httpPost = new HttpPost(url);
config(httpPost);
setJsonPostParams(httpPost, json);
try (CloseableHttpResponse response = httpPost(url, httpPost)) {
return parseResponse(response);
}
}

/**
* GET请求
*
* @param url
* @return String
*/
public static String get(String url) throws IOException {
HttpGet httpGet = new HttpGet(url);
config(httpGet);
try (CloseableHttpResponse response = httpGet(url, httpGet)) {
return parseResponse(response);
}
}

/**
* Get请求的真实执行
*
* @param url
* @param httpGet
* @return
* @throws IOException
*/
private static CloseableHttpResponse httpGet(String url, HttpGet httpGet) throws IOException {
return getHttpClient(url)
.execute(httpGet, HttpClientContext.create());
}

/**
* POST请求的真实执行
*
* @param url
* @param httpPost
* @return
* @throws IOException
*/
private static CloseableHttpResponse httpPost(String url, HttpPost httpPost) throws IOException {
return getHttpClient(url)
.execute(httpPost, HttpClientContext.create());
}

/**
* 解析response
*
* @param response
* @return
* @throws IOException
*/
private static String parseResponse(CloseableHttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, DEFAULT_CHARSET);
EntityUtils.consume(entity);
return result;
}
}

+ 61
- 0
source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java View File

@@ -0,0 +1,61 @@
package com.jd.blockchain.ump.util;

import com.alibaba.fastjson.JSON;
import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.web.WebResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpJsonClientUtils {

private static final Logger LOGGER = LoggerFactory.getLogger(HttpJsonClientUtils.class);

public static <T> T httpPost(MasterAddr masterAddr, String url, Object body, Class<T> returnType, boolean isWrapper) {

try {
String responseJson = HttpClientPool.jsonPost(masterAddr.toHttpUrl() + url, JSON.toJSONString(body));

LOGGER.info("Http Post Receive info =[ {} ] from {} ", responseJson, masterAddr.toHttpUrl() + url);

return response(responseJson, returnType, isWrapper);
} catch (Exception e) {

LOGGER.error("HttpPostRequestException {}", e.getMessage());

throw new IllegalStateException(e);
}
}

public static <T> T httpGet(String url, Class<T> returnType, boolean isWrapper) {
try {
String responseJson = HttpClientPool.get(url);

LOGGER.info("Http Get Receive info =[ {} ] from {} ", responseJson, url);

return response(responseJson, returnType, isWrapper);

} catch (Exception e) {

LOGGER.error("HttpGetRequestException {}", e.toString());

throw new IllegalStateException(e);
}
}

private static <T> T response(String responseJson, Class<T> returnType, boolean isWrapper) {
if (isWrapper) {
// 封装类型的情况下使用的是WebResponse
WebResponse<T> webResponse = JSON.parseObject(responseJson, WebResponse.class);
LOGGER.info("Wrapper JSON Data = {}", JSON.toJSONString(webResponse));
return webResponse.getData();
}

if (!JSON.isValid(responseJson)) {
return (T)responseJson;
}
// 对responseJson进行转换
T data = JSON.parseObject(responseJson, returnType);
LOGGER.info("UnWrapper JSON Data = {}", JSON.toJSONString(data));
return data;
}
}

+ 83
- 0
source/manager/ump-web/pom.xml View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>manager</artifactId>
<groupId>com.jd.blockchain</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>ump-web</artifactId>

<name>ump-web</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>ump-service</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>ump-model</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>utils-common</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>ump-explorer</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 22
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java View File

@@ -0,0 +1,22 @@
package com.jd.blockchain.ump.controller;

import com.jd.blockchain.ump.dao.DBConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path = "/db/")
public class UmpDBController {

@Autowired
private DBConnection dbConnection;

@RequestMapping(method = RequestMethod.GET, path = "read/{key}")
public String read(@PathVariable(name = "key") String key) {

return dbConnection.get(key);
}
}

+ 69
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java View File

@@ -0,0 +1,69 @@
package com.jd.blockchain.ump.controller;

import com.jd.blockchain.ump.model.user.UserKeyBuilder;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.model.user.UserKeysVv;
import com.jd.blockchain.ump.service.UmpStateService;
import com.jd.blockchain.ump.service.UtilService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(path = "/keys/")
public class UmpKeyController {

@Autowired
private UtilService utilService;

@Autowired
private UmpStateService umpStateService;

@RequestMapping(method = RequestMethod.POST, path = "create")
public UserKeysVv create(@RequestBody final UserKeyBuilder builder) {

// 使用种子生成公私钥
UserKeys userKeys = utilService.create(builder);

// 将userKeys保存至数据库
umpStateService.save(userKeys);

return userKeys.toUserKeysVv();
}

@RequestMapping(method = RequestMethod.GET, path = "list")
public List<UserKeysVv> list() {

// 从数据库中读取,返回
return umpStateService.readUserKeysVvList();
}

@RequestMapping(method = RequestMethod.GET, path = "read/{user}/{pubKey}")
public UserKeysVv read(@PathVariable(name = "user") int userId,
@PathVariable(name = "pubKey") String pubKey) {

UserKeys userKeys = utilService.read(userId);

if (userKeys != null) {
if (userKeys.getPubKey().equals(pubKey)) {

return userKeys.toUserKeysVv();
}
}
throw new IllegalStateException(String.format("Can not find UserKeys by %s", pubKey));
}

@RequestMapping(method = RequestMethod.GET, path = "resolve/{user}/{pwd}")
public UserKeys resolve(@PathVariable(name = "user") int userId,
@PathVariable(name = "pwd") String pwd) {

UserKeys userKeys = utilService.read(userId);

if (utilService.verify(userKeys, pwd)) {

return userKeys;
}
throw new IllegalStateException(String.format("Can not resolve UserKeys by %s", pwd));
}
}

+ 68
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java View File

@@ -0,0 +1,68 @@
package com.jd.blockchain.ump.controller;

import com.jd.blockchain.ump.model.PeerSharedConfigs;
import com.jd.blockchain.ump.model.config.LedgerConfig;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.state.InstallSchedule;
import com.jd.blockchain.ump.model.state.LedgerMasterInstall;
import com.jd.blockchain.ump.service.UmpService;
import com.jd.blockchain.ump.service.UmpStateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping(path = "/master/")
public class UmpMasterController {

@Autowired
private UmpService umpService;

@Autowired
private UmpStateService umpStateService;

/**
* 需要支持的接口
* 1、接收节点Share的信息
* 2、接收节点发送来的状态信息
* 3、接收前端查看某些节点状态的请求
*/
@RequestMapping(method = RequestMethod.POST, path = "share")
public LedgerConfig share(@RequestBody final PeerLocalConfig sharedConfig) {

PeerSharedConfigs sharedConfigs = umpService.loadPeerSharedConfigs(sharedConfig);

if (sharedConfigs == null) {
throw new IllegalStateException("PeerSharedConfig may be exits Conflict !!!");
}

return umpService.response(sharedConfigs, sharedConfig);
}

@RequestMapping(method = RequestMethod.POST, path = "receive")
public String receive(@RequestBody final InstallSchedule installSchedule) {

try {
umpStateService.save(installSchedule, null);
} catch (Exception e) {
return "FAIL";
}

return "SUCCESS";
}

@RequestMapping(method = RequestMethod.GET, path = "read/{ledgerKey}")
public Map<String, List<InstallSchedule>> readState(@PathVariable(name = "ledgerKey") String ledgerKey) {

return umpStateService.readStates(ledgerKey);
}

@RequestMapping(method = RequestMethod.GET, path = "list")
public List<LedgerMasterInstall> ledgerInstallList() {

// 返回当前Master收到的所有节点所有的安装信息
return umpStateService.readLedgerMasterInstalls();
}
}

+ 147
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java View File

@@ -0,0 +1,147 @@
package com.jd.blockchain.ump.controller;

import com.jd.blockchain.ump.model.MasterAddr;
import com.jd.blockchain.ump.model.UmpConstant;
import com.jd.blockchain.ump.model.config.LedgerConfig;
import com.jd.blockchain.ump.model.config.LedgerIdentification;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.config.PeerSharedConfigVv;
import com.jd.blockchain.ump.model.state.*;
import com.jd.blockchain.ump.model.user.UserKeys;
import com.jd.blockchain.ump.service.UmpService;
import com.jd.blockchain.ump.service.UmpStateService;
import com.jd.blockchain.ump.service.UtilService;
import com.jd.blockchain.ump.util.HttpJsonClientUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(path = "/peer/")
public class UmpPeerController {

@Autowired
private UmpService umpService;

@Autowired
private UmpStateService umpStateService;

@Autowired
private UmpMasterController masterController;

@Autowired
private UtilService utilService;

// @RequestMapping(method = RequestMethod.POST, path = "share")
public LedgerIdentification share(@RequestBody PeerLocalConfig localConfig) {

//首先校验配置信息
localConfig.verify();

MasterAddr masterAddr = localConfig.masterAddr();

LedgerConfig ledgerConfig;

if (localConfig.master()) {
// 当前节点本身是master,直接调用Controller方法
ledgerConfig = masterController.share(localConfig);
} else {
ledgerConfig = HttpJsonClientUtils.httpPost(masterAddr, UmpConstant.REQUEST_SHARED_URL, localConfig, LedgerConfig.class, false);
}

if (ledgerConfig == null) {
// 未加载成功
throw new IllegalStateException("Can not load Ledger-Config's Data from Master Node !!!");
}

String ledgerAndNodeKey = umpService.save(masterAddr, ledgerConfig, localConfig);

int nodeId = ledgerConfig.getInitConfig().nodeId(localConfig.getPubKey());

LedgerIdentification identification = new LedgerIdentification(nodeId, localConfig,
masterAddr, ledgerAndNodeKey, ledgerConfig.getInitConfig());

// 将数据写入数据库
umpStateService.save(identification);

return identification;
}

@RequestMapping(method = RequestMethod.POST, path = "share")
public LedgerIdentification share(@RequestBody PeerSharedConfigVv sharedConfigVv) {

String pubKey = sharedConfigVv.getPubKey();

if (pubKey == null || pubKey.length() == 0) {
throw new IllegalStateException("Public Key can not be empty !!!");
}

// 获取对应的UsersKey,转换为LocalConfig
UserKeys userKeys = utilService.read(sharedConfigVv.getUserId());

if (userKeys == null || !pubKey.equals(userKeys.getPubKey())) {
throw new IllegalStateException(String.format("Can not find UserKeys by %s", pubKey));
}

PeerLocalConfig localConfig = sharedConfigVv.toPeerLocalConfig(userKeys);

return share(localConfig);
}

@RequestMapping(method = RequestMethod.POST, path = "install/{ledgerAndNodeKey}")
public PeerInstallSchedules install(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) {

return umpService.install(ledgerAndNodeKey);
}

@RequestMapping(method = RequestMethod.POST, path = "init/{ledgerAndNodeKey}")
public PeerInstallSchedules init(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) {

return umpService.init(ledgerAndNodeKey);
}

@RequestMapping(method = RequestMethod.POST, path = "startup")
public PeerStartupSchedules startup() {

return umpService.startup();
}

// @RequestMapping(method = RequestMethod.POST, path = "stop/{ledgerAndNodeKey}")
public boolean stop(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) {

return umpService.stop(ledgerAndNodeKey);
}

@RequestMapping(method = RequestMethod.POST, path = "stop")
public boolean stop() {

return umpService.stop();
}

@RequestMapping(method = RequestMethod.GET, path = "init/read/{ledgerAndNodeKey}")
public PeerInstallSchedules readInitState(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) {

return umpStateService.readInitState(ledgerAndNodeKey);
}

@RequestMapping(method = RequestMethod.GET, path = "list")
public List<LedgerPeerInstall> ledgerInstallList() {

// 返回当前Peer节点所有的安装信息
return umpStateService.readLedgerPeerInstalls();
}

public List<LedgerPeerInited> ledgerInitedList(@RequestParam(name = "search", required = false) String search) {

// 返回当前Peer节点所有的初始化后信息
return umpStateService.readLedgerPeerIniteds(search);
}

@RequestMapping(method = RequestMethod.GET, path = "initeds")
public List<LedgerInited> ledgerIniteds(@RequestParam(name = "search", required = false) String search) {

// 返回当前Peer节点所有的初始化后信息
return umpStateService.readLedgerIniteds(search);
}
}

+ 64
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java View File

@@ -0,0 +1,64 @@
package com.jd.blockchain.ump.controller;

import com.jd.blockchain.ump.model.config.LedgerIdentification;
import com.jd.blockchain.ump.model.config.PeerLocalConfig;
import com.jd.blockchain.ump.model.state.PeerInstallSchedules;
import com.jd.blockchain.ump.service.UmpService;
import com.jd.blockchain.ump.service.UmpSimulateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping(path = "/peer/")
public class UmpPeerSimulateController {

private final Map<Integer, String> ledgerAndNodeKeys = new ConcurrentHashMap<>();

@Autowired
private UmpService umpService;

@Autowired
private UmpSimulateService simulateService;

@Autowired
private UmpPeerController peerController;

@RequestMapping(method = RequestMethod.GET, path = "share/simulate/{node}")
public LedgerIdentification share(@PathVariable(name = "node") int nodeId) {

boolean isMaster = false;
if (nodeId == 0) {
isMaster = true;
}

PeerLocalConfig localConfig = simulateService.nodePeerLocalConfig(nodeId, isMaster);

LedgerIdentification identification = peerController.share(localConfig);

// 作为缓存使用
ledgerAndNodeKeys.put(nodeId, identification.getLedgerAndNodeKey());

return identification;
}


@RequestMapping(method = RequestMethod.GET, path = "install/simulate/{node}")
public PeerInstallSchedules install(@PathVariable(name = "node") int nodeId) {

String ledgerAndNodeKey = ledgerAndNodeKeys.get(nodeId);

return umpService.install(ledgerAndNodeKey);
}

@RequestMapping(method = RequestMethod.GET, path = "init/simulate/{node}")
public PeerInstallSchedules init(@PathVariable(name = "node") int nodeId) {

return umpService.init(ledgerAndNodeKeys.get(nodeId));
}
}

+ 29
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java View File

@@ -0,0 +1,29 @@
package com.jd.blockchain.ump.web;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ControllerConfigurer implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {

// 添加打印日志的拦截器
registry.addInterceptor(new LogPrintInterceptor()).addPathPatterns("/**");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources");
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("web/index.html");
}
}

+ 38
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java View File

@@ -0,0 +1,38 @@
package com.jd.blockchain.ump.web;

import com.jd.blockchain.ump.model.web.ErrorCode;
import com.jd.blockchain.ump.model.web.WebResponse;
import com.jd.blockchain.utils.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

@RestControllerAdvice
public class ExceptionResponseAdvice {

private final Logger logger = LoggerFactory.getLogger(getClass());

@ExceptionHandler(value = Exception.class)
@ResponseBody
public WebResponse json(HttpServletRequest req, Exception ex) {

WebResponse.ErrorMessage message;

String reqURL = "[" + req.getMethod() + "] " + req.getRequestURL().toString();

if (ex instanceof BusinessException) {
BusinessException businessException = (BusinessException) ex;
message = new WebResponse.ErrorMessage(businessException.getErrorCode(), businessException.getMessage());
} else {
logger.error("Exception occurred! --[RequestURL=" + reqURL + "][" + ex.getClass().toString()
+ "]" + ex.getMessage(), ex);

message = new WebResponse.ErrorMessage(ErrorCode.UNEXPECTED.getValue(), ex.toString());
}
return WebResponse.createFailureResult(message);
}
}

+ 51
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java View File

@@ -0,0 +1,51 @@
package com.jd.blockchain.ump.web;

import com.jd.blockchain.ump.model.config.LedgerConfig;
import com.jd.blockchain.ump.model.web.WebResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class JsonResponseAdvice implements ResponseBodyAdvice<Object> {

@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
if (MappingJackson2HttpMessageConverter.class == converterType
&& (returnType.getContainingClass().getName().startsWith("com.jd.blockchain.ump")
|| returnType.getDeclaringClass().getName().startsWith("com.jd.blockchain.ump"))) {
return true;
}
return false;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if (body == null) {
return WebResponse.createSuccessResult(null);
}

if (body instanceof ResponseEntity) {
return body;
}

// LedgerConfig单独处理
if (body instanceof LedgerConfig) {
return body;
}

// 把返回结果自动转换为 WebResponse;
if (body instanceof WebResponse) {
return body;
}
return WebResponse.createSuccessResult(body);
}
}

+ 32
- 0
source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java View File

@@ -0,0 +1,32 @@
package com.jd.blockchain.ump.web;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public class LogPrintInterceptor implements HandlerInterceptor {

private final Logger LOGGER = LoggerFactory.getLogger(getClass());

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 记录日志
// 请求的参数:
String parameters = "";
Map<String, String[]> requestParameters = request.getParameterMap();
if (requestParameters != null && !requestParameters.isEmpty()) {
parameters = JSON.toJSONString(requestParameters);
}
LOGGER.info("Request[{}][{}], parameters=[{}]",
request.getRequestURL().toString(), // 请求URL
request.getMethod(), // 请求的方法
parameters); // 请求的参数

return true;
}
}

Loading…
Cancel
Save