@@ -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; | |||||
} | |||||
} |