@@ -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> |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 { | |||
} |
@@ -0,0 +1,5 @@ | |||
server.tomcat.uri-encoding=utf-8 | |||
spring.mvc.favicon.enabled=false | |||
logging.config=classpath:log4j2-jump.xml |
@@ -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> |
@@ -0,0 +1,13 @@ | |||
▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ | |||
▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░▌ | |||
▀▀▀▀▀█░█▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌ ▐░▌ | |||
▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ | |||
▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ | |||
▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ | |||
▐░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ | |||
▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ | |||
▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌ ▐░▐░▌ | |||
▐░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌ | |||
▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ | |||
@@ -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 |
@@ -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> |
@@ -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 |
@@ -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 |
@@ -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> |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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())); | |||
} | |||
} |
@@ -0,0 +1,4 @@ | |||
package com.jd.blockchain.ump.dao; | |||
public interface UmpDao { | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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节点启动失败 | |||
; | |||
} |
@@ -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, | |||
; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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); | |||
} |
@@ -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; | |||
// } | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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]; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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> |
@@ -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); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |