1. 概述

数字对象体系(Digital Object Architecture,下面简称为DOA)是图灵奖得主、互联网发明人Robert E. Kahn提出的一种实现异构信息系统互操作的新型计算架构。

在DOA架构中,将信息资源抽象表示为数字对象(Digital Object,下面简称DO),所有的DO都存储在DO Repository中,并且支持通过数字对象接口协议(Digital Object Interface Protocol,下面简称DOIP)来对外提供服务。每一种DO具有全球可解析的唯一标识,可以通过标识与解析协议(Identifier/Resolution Protocol,下面简称IRP)向Handle System进行注册与解析。同时每一个DO也具有对该DO进行描述的元信息,元信息存储在DO Registry(一种特殊的DO Repository)中,也支持通过DOIP来对外提供服务。

根据上面的描述,在DOA架构中,有三种构件和两种协议。三种构件分别是:Handle System,DO Repository和DO Registry。两种协议分别是:DOIP和IRP。北京大学提供了DOIP和IRP的代码实现,并提供了用于开发DO Repository,DO Registry以及Client的软件开发工具包(Software Development Kit,简称SDK)。服务提供者,可以基于该SDK实现DO Repository和DO Registry功能。同时,我们提供用于对接国内主流Handle System提供者的支持代码,比如中数、中科院网络中心等。服务提供者可以基于该代码开发用于提供标识与解析的服务。最终使用者,可以基于Client的SDK开发基于DOA的应用程序。

2. 快速上手

2.1 环境准备

相关的代码均采用Java编写,在使用相关代码前,请确保本地已经安装了JDK(>= Java 1.8)。

2.2 下载示例代码

  • LHSMock v1.0 提供一个模拟的标识/解析环境。
  • example-Repository v1.0 提供一个包含概念验证功能的数字对象仓库。
  • example-Registry v1.0 提供一个包含概念验证功能的数字对象注册表。
  • example-Client v1.0 提供一个与数字对象仓库、数字对象注册表进行交互的客户端工具。

2.3 运行代码

下载回来的示例代码是一个压缩包,解压后包含一个jar包和一些支持文件(里面包含示例代码运行需要使用的配置文件)。

2.3.1 使用Client与Repository进行交互

  1. 启动mockLHS 下载的压缩包解压后,得到如下目录和文件。
libs LHSMock-1.0.jar

执行如下命令,开启模拟的标识解析服务。

java -jar LHSMock-1.0.jar
[The actual rocksdb path:] D:\test\tmp\lhsmock\.\handleRecords
  1. 启动Respository 将Repository示例代码解压后,打开命令窗口,进入包含jar包的目录,此时目录内容如下:
keys libs default_repo.json account.json SimpleRepository-1.0.jar

执行如下命令,开启Repository:

java -jar SimpleRepository-1.0.jar

此时,命令行出现如下日志信息,表示Repository启动成功。

java -jar .\SimpleRepository-1.0.jar
[INFO ]00:27:36.533 load config from: default_repo.json (DoipServiceConfig.java:22)
[INFO ]00:27:38.514 [HandleService] response from LHS: 86.5000.470/Repository.Test.00 (SimpleRepositoryMain.java:123)
[INFO ]00:27:38.728 DOIPServiceInfo: {"id":"86.5000.470/Repository.Test.00","serviceDescription":"local repository for test","publicKey":"{\"kty\":\"RSA\",\"n\":\"AIaJrbLDedKLMIFVaO9hHFhsJgZDCVQH2-QFvrArazIa4yGsR3rYSxqmYQFMTBfw-IP9Alx5LUKVeCbuo2rVlj26-DV4HAaCUnR6SfCZrasDQYiRqo2Hinv47-mWUImhH6lMzhi9jxggWLlfSrfDze3d9ijT_LGBYd0rfV84OIPjHjb5u9t0_Wxnegunvz9sDDsUJT2BZAmkN6lKdGWF9owm06b9BRnCCUetvsDAFjyH0clhPiBdwdoYJC1zQOe0qdeRzErp9A_OlUSKaojgKjjSpw52CPLMw7iJx_0v7i9qJrQhvt-2woZvaSWI9Y157hWLFW_dUX2ywuUveqCWa-s\",\"e\":\"AQAB\",\"use\":\"sig\"}","serviceName":"TestTLSRepository0","port":1718,"ipAddress":"127.0.0.1","protocol":"tls","protocolVersion":"2.0","listenerInfos":[{"url":"tls://127.0.0.1:1718","protocolVersion":"2.0","messageFormat":"delimiter"}],"owner":"86.5000.470/dou.SUPER0"} (DoipServerImpl.java:34)
[INFO ]00:27:40.939 start at:1718 (NettyTLSDoipListener.java:63)
  1. 修改客户端配置文件 将Client示例代码解压后,打开命令窗口,进入包含jar包的目录,此时目录内容如下:
libs Client-1.0.jar default_client.json default_client_regi.json default_client_repo.json

Client默认情况下使用default_client.json作为配置文件,配置文件的内容需要根据具体需要进行修改。如果要连接示例里面的Repository和Registry,请使用命令行参数-cf指定配置文件。(default_client_repo.json用于连接示例里面的Repository,default_client_regi.json用于连接示例里面的Registry)。

  1. 使用Client发送操作请求 Client是一个DOIP客户端命令行工具,支持DOIP的7种基本操作。不加参数直接执行,会显示工具的帮助信息,如下:
java -jar .\Client-1.0.jar
usage: DOIPCMDClient [-c <arg>] [-cf <arg>] [-d <arg>] [-h] [-i] [-l] [-r <arg>] [-s <arg>] [-u <arg>]
basic doip operations to illustrate usage of the protocol

 -c,--create <arg>     create do in doip repository/registry, e.g. create do: -c 86.5000.470/do.test DO message, create
                       meta: -c 86.5000.470/do.test Meta description
 -cf,--config <arg>    path to config file
 -d,--delete <arg>     delete do in doip repository/registry, e.g. -d 86.5000.470/do.test
 -h                    display this help message
 -i,--hello            get doip service information, e.g. -i
 -l,--list             get repository/registry supported operations, e.g. -l
 -r,--retrieve <arg>   retrieve do in doip repository/registry, e.g. -r 86.5000.470/do.test
 -s,--search <arg>     search meta info in registry, e.g. -s key_word
 -u,--update <arg>     update do in doip repository/registry, e.g. -u 86.5000.470/do.test DO new_message

Please report issues at https://gitee.com/BDWare/doip-sdk.git

(1)发送hello操作请求

java -jar .\Client-1.0.jar -i -cf .\default_client_repo.json
[INFO ]16:56:32.280 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:56:34.777 client sending message: {"requestId":"1701103136","targetId":"86.5000.470/doip.localTcpRepo","operationId":"0.DOIP/Op.Hello","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:56:35.353 client received message: {"requestId":"1701103136","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/doip.localTcpRepo","type":"0.TYPE/DO.DOIPServiceInfo","attributes":{"serviceName":"TestMultiTransProtocol","serviceDescription":"test local Repository","owner":"86.5000.470/dou.SUPER","publicKey":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUjtYUciJbdU5BYYFYykS33+1Wnm8KHf9+0/9EolcIWYro7xX8x9OHwF3nYu8xfhjjKo6Ma4WzI/ON5UO447eynCSKbvzJZV01rzuk03ED9rWfYQQyZrI6WyDtLAnwkG4ZJ+9ik75F+JF5YRHNb7bU0VU7FEtPS16uzF9twHi9JzZcfI8fwFKPO9Xzp6UagHzibIuRTLmU+Jl4jnzvU4MJsQlfcmyMM7VWM8oHCkd9NzC+XIr7GH/a3zcI8WEY9D1mLrwYR8UERd6rqSJ3W03O21s4+lLOGgGoRmtJERVqwK2TF789Fa7N9+9bZJJ3dAaP16iynHfOl5tb7Jmr4tLwIDAQAB","protocol":"tls","protocolVersion":"2.0","port":1718,"ipAddress":"127.0.0.1","listenerInfos":"[{\"url\":\"tls://127.0.0.1:1718\",\"protocolVersion\":\"2.0\",\"messageFormat\":\"delimiter\"}]","isSigned":"true"}}
#
{"bytesAlg":{"hashAlg":"SHA-256"},"signatures":{"payload":"eyJpZCI6Ijg2LjUwMDAuNDcwL2RvaXAubG9jYWxUY3BSZXBvIiwidHlwZSI6IjAuVFlQRS9ETy5ET0lQU2VydmljZUluZm8iLCJhdHRyaWJ1dGVzIjp7InNlcnZpY2VOYW1lIjoiVGVzdE11bHRpVHJhbnNQcm90b2NvbCIsInNlcnZpY2VEZXNjcmlwdGlvbiI6InRlc3QgbG9jYWwgUmVwb3NpdG9yeSIsIm93bmVyIjoiODYuNTAwMC40NzAvZG91LlNVUEVSIiwicHVibGljS2V5IjoiTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3VWp0WVVjaUpiZFU1QllZRll5a1MzMysxV25tOEtIZjkrMC85RW9sY0lXWXJvN3hYOHg5T0h3RjNuWXU4eGZoampLbzZNYTRXekkvT041VU80NDdleW5DU0tidnpKWlYwMXJ6dWswM0VEOXJXZllRUXlackk2V3lEdExBbndrRzRaSis5aWs3NUYrSkY1WVJITmI3YlUwVlU3RkV0UFMxNnV6Rjl0d0hpOUp6WmNmSThmd0ZLUE85WHpwNlVhZ0h6aWJJdVJUTG1VK0psNGpuenZVNE1Kc1FsZmNteU1NN1ZXTThvSENrZDlOekMrWElyN0dIL2EzemNJOFdFWTlEMW1McndZUjhVRVJkNnJxU0ozVzAzTzIxczQrbExPR2dHb1JtdEpFUlZxd0syVEY3ODlGYTdOOSs5YlpKSjNkQWFQMTZpeW5IZk9sNXRiN0ptcjR0THdJREFRQUIiLCJwcm90b2NvbCI6InRscyIsInByb3RvY29sVmVyc2lvbiI6IjIuMCIsInBvcnQiOjE3MTgsImlwQWRkcmVzcyI6IjEyNy4wLjAuMSIsImxpc3RlbmVySW5mb3MiOiJbe1widXJsXCI6XCJ0bHM6Ly8xMjcuMC4wLjE6MTcxOFwiLFwicHJvdG9jb2xWZXJzaW9uXCI6XCIyLjBcIixcIm1lc3NhZ2VGb3JtYXRcIjpcImRlbGltaXRlclwifV0iLCJpc1NpZ25lZCI6InRydWUifX0","signatures":[{"protected":"eyJhbGciOiJSUzI1NiJ9","header":{"kid":"86.5000.470/dou.SUPER"},"signature":"fuoDyqZMElZ-8i5ptQ09TBz5AIp0wcVzoDVqECkmWPnjPMSVRCjpwaw6wqsRSqCMhKJbGPZn3GMmuFaybqa1S2daPq7WNw2-UpsdjqYE_uMNLrbtQNe-dz5PmBOK4gtmrNURLlofJqSWhw2vv6h0CnsIgqqN7r3IuuGglHU2QAdchywBf_FcgxGqJv3JuoGu_QGQpVufi0k1yD4ziVEs4_NN62_uZgkQXY7eSB-mzNKGv6c5WvF9-5Nm9Mej7KBHlFkNv30zx1SToYHCSc0xeXuTXfmyOzyO1W7piB1s6nZX47g5S5YysTytmdHm0OIlpcX6pqSVpSxx2oULl8oe8w"}]}} (DelimiterMessageClientCodec.java:85)

(2)发送listOperation操作请求

java -jar .\Client-1.0.jar -l -cf .\default_client_repo.json
[INFO ]16:56:54.083 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:56:56.385 client sending message: {"requestId":"-1340345561","targetId":"86.5000.470/doip.localTcpRepo","operationId":"0.DOIP/Op.ListOperations","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:56:56.581 client received message: {"requestId":"-1340345561","status":"0.DOIP/Status.001","output":["0.DOIP/Op.Hello","0.DOIP/Op.ListOperations","0.DOIP/Op.Retrieve","0.DOIP/Op.Create","0.DOIP/Op.Update","0.DOIP/Op.Delete","0.DOIP/Op.Search","0.DOIP/Op.Extension","0.DOIP/Op.Unknown"]} (DelimiterMessageClientCodec.java:85)

(3)发送create操作请求

java -jar .\Client-1.0.jar -c 86.5000.470/do.test01 DO hello -cf .\default_client_repo.json
[INFO ]16:58:59.062 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:59:01.354 client sending message: {"requestId":"1646813081","targetId":"86.5000.470/doip.localTcpRepo","operationId":"0.DOIP/Op.Create","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/do.test01","type":"0.TYPE/DO","attributes":{"content":{"create":"hello","name":"create","description":"this is an example for create"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:59:01.548 client received message: {"requestId":"1646813081","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/do.test01","type":"0.TYPE/DO","attributes":{"content":{"create":"hello","name":"create","description":"this is an example for create"}}} (DelimiterMessageClientCodec.java:85)

(4)发送update操作请求

java -jar .\Client-1.0.jar -u 86.5000.470/do.test01 DO hello_update -cf .\default_client_repo.json
[INFO ]16:59:36.850 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:59:39.151 client sending message: {"requestId":"-1386601504","targetId":"86.5000.470/do.test01","operationId":"0.DOIP/Op.Update","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/do.test01","type":"0.TYPE/DO","attributes":{"content":{"update":"hello_update","name":"update","description":"this is an example for update"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:59:39.338 client received message: {"requestId":"-1386601504","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/do.test01","type":"0.TYPE/DO","attributes":{"content":{"update":"hello_update","name":"update","description":"this is an example for update"}}} (DelimiterMessageClientCodec.java:85)

(5)发送retrieve操作请求

java -jar .\Client-1.0.jar -r 86.5000.470/do.test01 -cf .\default_client_repo.json
[INFO ]17:00:05.143 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:00:07.485 client sending message: {"requestId":"1775903427","targetId":"86.5000.470/do.test01","operationId":"0.DOIP/Op.Retrieve","attributes":{"includeElementData":"true"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:00:07.686 client received message: {"requestId":"1775903427","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/do.test01","type":"0.TYPE/DO","attributes":{"content":{"update":"hello_update","name":"update","description":"this is an example for update"}}} (DelimiterMessageClientCodec.java:85)

(6)发送delete操作请求

java -jar .\Client-1.0.jar -d 86.5000.470/do.test01 -cf .\default_client_repo.json
[INFO ]17:00:22.094 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:00:24.340 client sending message: {"requestId":"-762527615","targetId":"86.5000.470/do.test01","operationId":"0.DOIP/Op.Delete","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:00:24.491 client received message: {"requestId":"-762527615","status":"0.DOIP/Status.001"} (DelimiterMessageClientCodec.java:85)

(7)发送search操作请求

java -jar .\Client-1.0.jar -s "hello" -cf .\default_client_repo.json
[INFO ]17:01:09.654 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:01:11.913 client sending message: {"requestId":"1513536436","targetId":"86.5000.470/doip.localTcpRepo","operationId":"0.DOIP/Op.Search","attributes":{"query":"hello","pageNum":0,"pageSize":10,"type":"full","sortFields":"id:ASC"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:01:12.078 client received message: {"requestId":"1513536436","status":"0.DOIP/Status.200","output":{"message":"Unsupported Operation!"}} (DelimiterMessageClientCodec.java:85)

注意:根据DOIP标准,Repository不支持search操作。

2.3.2 使用Client与Registry进行交互

  1. 启动mockLHS
libs LHSMock-1.0.jar

执行如下命令,开启模拟的标识解析服务。

java -jar LHSMock-1.0.jar
[The actual rocksdb path:] D:\test\tmp\lhsmock\.\handleRecords
  1. 启动Registry 将Registry示例代码解压后,打开命令窗口,进入包含jar包的目录,此时目录内容如下:
keys libs default_regi.json account.json SimpleRegistry-1.0.jar

执行如下命令,开启Registry:

java -jar SimpleRegistry-1.0.jar

此时,命令行出现如下日志信息,表示Registry启动成功。

java -jar .\SimpleRegistry-1.0.jar
[INFO ]00:29:27.019 load config from: default_regi.json (DoipServiceConfig.java:22)
[INFO ]00:29:27.105 index path: index (DoIndexerLuceneImpl.java:39)
[INFO ]00:29:29.626 [HandleService] response from LHS: 86.5000.470/Registry.Test (SimpleRegistryMain.java:135)
[INFO ]00:29:29.649 DOIPServiceInfo: {"id":"86.5000.470/Registry.Test","serviceDescription":"local registry for test","publicKey":"{\"kty\":\"RSA\",\"n\":\"AJcJWZYZcmilUFcOMf-1d5qaSyAbchfmRL8Cu8QFsBOvG0xKK32yuLavb84AvB3mz7oy5lrKu8rooD2rs2hhMo8Mnj3qhUWYTpbuatm6pZy9YOKgzJo3DRZyUgUQuLlmSyh34rjM_HR_d9nYxImzbVhiAi4mQp9dErWJHF0lQfU30qMjxFzuIzoK8CHWgtf57TCzEaTP0gNO7mD3QKjC49kMy7RBoOu6EQBCag9YKfXcTysHRhFrCWBDyUTN49YNMS1-RU4a8YPgNXL7du2n2LpnFFnFk9c6fz_Zv2zyvts1WkLFhS6ZBjtfMJwavc1w2MaTtv_-8doOeeSreWNJiik\",\"e\":\"AQAB\",\"use\":\"sig\"}","serviceName":"TestTLSRegistry","port":1720,"ipAddress":"127.0.0.1","protocol":"tls","protocolVersion":"2.0","listenerInfos":[{"url":"tls://127.0.0.1:1720","protocolVersion":"2.0","messageFormat":"delimiter"}],"owner":"86.5000.470/dou.SUPER"} (DoipServerImpl.java:34)
[INFO ]00:29:31.834 start at:1720 (NettyTLSDoipListener.java:63)
  1. 修改客户端配置文件 将Client示例代码解压后,打开命令窗口,进入包含jar包的目录,此时目录内容如下:
libs Client-1.0.jar default_client.json default_client_regi.json default_client_repo.json

Client默认情况下使用default_client.json作为配置文件,配置文件的内容需要根据具体需要进行修改。如果要连接示例里面的Repository和Registry,请使用命令行参数-cf指定配置文件。(default_client_repo.json用于连接示例里面的Repository,default_client_regi.json用于连接示例里面的Registry)。

  1. 使用Client发送操作请求 Client的基本用法,请参考2.3.1中的步骤3。与Registry交互过程中,需要注意的事项事:1. 创建DO时制定的类型需要为“Meta”;2. Registry支持search操作。 (1)发送hello操作
java -jar .\Client-1.0.jar -i -cf .\default_client_regi.json
[INFO ]17:10:54.658 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:10:56.929 client sending message: {"requestId":"1632407099","targetId":"86.5000.470/dou.TEST","operationId":"0.DOIP/Op.Hello","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:10:57.529 client received message: {"requestId":"1632407099","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/dou.TEST","type":"0.TYPE/DO.DOIPServiceInfo","attributes":{"serviceName":"TestTLSRegistry","serviceDescription":"test local TLS Registry","owner":"86.5000.470/dou.SUPER","publicKey":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgHes68FmNYTgj2UKMu0cAc6+1izOoAkOkcYu+wS3/utvtA98CutdjogZjPVnYP4lumA1TrKo9zY0xGyo/8hkMY3C7Bn9kK3+o1uT0Jv5qPmxcr8E1vZg6joe2k38pHKBkjIctqHDXVrzcoQG1EiUSNQwbhlT/EjNmdzt2+ykmkHf+jiocjwc6TAL0EmifHk4o6kmn4LHvChmTfaMeRUnT2Ol6Aral+dd5RfVhQ1lNsoRfTk7QVR9GETmgLOLDQTbWAkMGg/p6LgQml0eulTTg5SCuoFKY81wruPVeoQ6yfmfX11aKHS88XOEg5qUARGlwncaxMUFqTPpiJwKzzlJrwIDAQAB","protocol":"tls","protocolVersion":"2.0","port":1720,"ipAddress":"127.0.0.1","listenerInfos":"[{\"url\":\"tls://127.0.0.1:1720\",\"protocolVersion\":\"2.0\",\"messageFormat\":\"delimiter\"}]","isSigned":"true"}}
#
{"bytesAlg":{"hashAlg":"SHA-256"},"signatures":{"payload":"eyJpZCI6Ijg2LjUwMDAuNDcwL2RvdS5URVNUIiwidHlwZSI6IjAuVFlQRS9ETy5ET0lQU2VydmljZUluZm8iLCJhdHRyaWJ1dGVzIjp7InNlcnZpY2VOYW1lIjoiVGVzdFRMU1JlZ2lzdHJ5Iiwic2VydmljZURlc2NyaXB0aW9uIjoidGVzdCBsb2NhbCBUTFMgUmVnaXN0cnkiLCJvd25lciI6Ijg2LjUwMDAuNDcwL2RvdS5TVVBFUiIsInB1YmxpY0tleSI6Ik1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBZ0hlczY4Rm1OWVRnajJVS011MGNBYzYrMWl6T29Ba09rY1l1K3dTMy91dHZ0QTk4Q3V0ZGpvZ1pqUFZuWVA0bHVtQTFUcktvOXpZMHhHeW8vOGhrTVkzQzdCbjlrSzMrbzF1VDBKdjVxUG14Y3I4RTF2Wmc2am9lMmszOHBIS0JrakljdHFIRFhWcnpjb1FHMUVpVVNOUXdiaGxUL0VqTm1kenQyK3lrbWtIZitqaW9jandjNlRBTDBFbWlmSGs0bzZrbW40TEh2Q2htVGZhTWVSVW5UMk9sNkFyYWwrZGQ1UmZWaFExbE5zb1JmVGs3UVZSOUdFVG1nTE9MRFFUYldBa01HZy9wNkxnUW1sMGV1bFRUZzVTQ3VvRktZODF3cnVQVmVvUTZ5Zm1mWDExYUtIUzg4WE9FZzVxVUFSR2x3bmNheE1VRnFUUHBpSndLenpsSnJ3SURBUUFCIiwicHJvdG9jb2wiOiJ0bHMiLCJwcm90b2NvbFZlcnNpb24iOiIyLjAiLCJwb3J0IjoxNzIwLCJpcEFkZHJlc3MiOiIxMjcuMC4wLjEiLCJsaXN0ZW5lckluZm9zIjoiW3tcInVybFwiOlwidGxzOi8vMTI3LjAuMC4xOjE3MjBcIixcInByb3RvY29sVmVyc2lvblwiOlwiMi4wXCIsXCJtZXNzYWdlRm9ybWF0XCI6XCJkZWxpbWl0ZXJcIn1dIiwiaXNTaWduZWQiOiJ0cnVlIn19","signatures":[{"protected":"eyJhbGciOiJSUzI1NiJ9","header":{"kid":"86.5000.470/dou.SUPER"},"signature":"XYJanYr50DDMRwwy9h8Ayy5JOAgvLnI6T__UgAxCjvxSBVPItMYpID5Yok4t6x9Jslna4o9P6ddf0O8fa2R3qv9XVzM-_6FehOeS-fKwb0J_HkncKk2NMVk1W7OSq8NvhsTn6jvREGWCSCnQH1Z3Lr6XyH0t68FkrGj186UNBagIk_Q3Vc_doYQfwlo3gJ3p_rjN26WcrllhjIWLGjxlWoN_XWoy3kn5Vr3_5pQu8Tn64qUFKdDFKvtomu-Tr-noYDf13AOlTaAAg8VsIgc-pbM4hEd2KdoBvGn9xANGFKE7ruoTSbOV79zM_cxFVZnQRPSAHKVHapBFWCCYdJmsKQ"}]}} (DelimiterMessageClientCodec.java:85)

(2)发送listOperation操作

java -jar .\Client-1.0.jar -l -cf .\default_client_regi.json
[INFO ]17:11:38.824 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:11:41.068 client sending message: {"requestId":"453969307","targetId":"86.5000.470/dou.TEST","operationId":"0.DOIP/Op.ListOperations","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:11:41.258 client received message: {"requestId":"453969307","status":"0.DOIP/Status.001","output":["0.DOIP/Op.Hello","0.DOIP/Op.ListOperations","0.DOIP/Op.Retrieve","0.DOIP/Op.Create","0.DOIP/Op.Update","0.DOIP/Op.Delete","0.DOIP/Op.Search","0.DOIP/Op.Extension","0.DOIP/Op.Unknown"]} (DelimiterMessageClientCodec.java:85)

(3)发送create操作

java -jar .\Client-1.0.jar -c 86.5000.470/meta.test01 Meta metainfo -cf .\default_client_regi.json
[INFO ]17:14:39.364 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:14:41.588 client sending message: {"requestId":"495617923","targetId":"86.5000.470/dou.TEST","operationId":"0.DOIP/Op.Create","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"create":"metainfo","name":"create","description":"this is an example for create"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:14:41.832 client received message: {"requestId":"495617923","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"create":"metainfo","name":"create","description":"this is an example for create"}}} (DelimiterMessageClientCodec.java:85)

(4)发送update操作

java -jar .\Client-1.0.jar -u 86.5000.470/meta.test01 Meta metainfo_update -cf .\default_client_regi.json
[INFO ]17:15:04.887 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:15:07.150 client sending message: {"requestId":"1654592549","targetId":"86.5000.470/meta.test01","operationId":"0.DOIP/Op.Update","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"update":"metainfo_update","name":"update","description":"this is an example for update"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:15:07.454 client received message: {"requestId":"1654592549","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"update":"metainfo_update","name":"update","description":"this is an example for update"}}} (DelimiterMessageClientCodec.java:85)

(5)发送retrieve操作

java -jar .\Client-1.0.jar -r 86.5000.470/meta.test01 -cf .\default_client_regi.json
[INFO ]17:15:23.620 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:15:25.938 client sending message: {"requestId":"-1789595138","targetId":"86.5000.470/meta.test01","operationId":"0.DOIP/Op.Retrieve","attributes":{"includeElementData":"true"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:15:26.108 client received message: {"requestId":"-1789595138","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"update":"metainfo_update","name":"update","description":"this is an example for update"}}} (DelimiterMessageClientCodec.java:85)

(6)发送search操作

java -jar .\Client-1.0.jar -s "metainfo_update" -cf .\default_client_regi.json
[INFO ]17:16:00.188 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:16:02.441 client sending message: {"requestId":"2052262241","targetId":"86.5000.470/dou.TEST","operationId":"0.DOIP/Op.Search","attributes":{"query":"metainfo_update","pageNum":0,"pageSize":10,"type":"full","sortFields":"id:ASC"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:16:02.726 client received message: {"requestId":"2052262241","status":"0.DOIP/Status.001","output":{"size":1,"results":[{"id":"86.5000.470/meta.test01","type":"0.TYPE/DO.Metadata","attributes":{"content":{"update":"metainfo_update","name":"update","description":"this is an example for update"}}}]}} (DelimiterMessageClientCodec.java:85)

(7)发送delete操作

java -jar .\Client-1.0.jar -d 86.5000.470/meta.test01 -cf .\default_client_regi.json
[INFO ]17:16:38.767 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]17:16:40.975 client sending message: {"requestId":"779456898","targetId":"86.5000.470/meta.test01","operationId":"0.DOIP/Op.Delete","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]17:16:41.160 client received message: {"requestId":"779456898","status":"0.DOIP/Status.001"} (DelimiterMessageClientCodec.java:85)

3. 与其他DOIP实现进行互操作

3.1 cordra

3.1.1 使用PKU实现的DOIP客户端访问cordra实现的DOIP服务

参考cordra提供的文档搭建cordra的DOIP服务,注册用户,并记录账户。使用PKU实现的DOIP客户端工具访问cordra的DOIP服务,使用已经注册的用户凭据来通过认证。这里以cordra2.1版本为例来进行说明。

  1. 启动cordra的DOIP服务 将下载的cordra2.1代码进行解压,目录结构如下:
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2020/5/8     23:28                bin
d-----         2020/5/8     23:28                cordra-client-handle-storage
d-----        2021/1/17     14:00                data
d-----         2020/5/8     23:28                docker
d-----         2020/5/8     23:28                extensions
d-----         2020/8/6     23:26                src
d-----         2020/5/8     23:28                sw
-a----         2020/5/8     23:28          14152 cordra-client-LICENSE.txt
-a----        2020/7/27     10:49         948067 cordra-technical-manual-2.1.0.pdf
-a----         2020/5/8     23:28          66548 LICENSE.txt
-a----         2020/5/8     23:28           1503 README.txt
-a----         2020/5/8     23:28             45 shutdown
-a----         2020/5/8     23:28             61 shutdown.bat
-a----         2020/5/8     23:28             44 startup
-a----         2020/5/8     23:28             60 startup.bat

根据README.txt中的提示,修改admin的初始密码。然后通过启动脚本(Linux和MacOS中使用startup,Windows中使用startup.bat)开启DOIP服务。看到如下信息,表示启动完成。

data dir: D:\App\cordra-2.1.0\data
Initializing HTTP interface on port 8080
Initializing HTTPS interface on port 8443
Using existing keypair for HTTPS.
Storage: bdbje
Index: lucene
Initializing Handle TCP interface on port 2641
Initializing DOIP interface on port 9000
Startup complete.
  1. 配置PKU DOIP客户端 当完成cordra服务端启动后,修改PKU DOIP客户端的配置文件。该配置文件与客户端的jar包放在一个目录,文件名为:default_client.json。修改内容如下,其中userPass为第一步配置的admin初始密码,这里假设为"password":
{
  "repoID": "20.5000.123/service",
  "repoURL": "tls://127.0.0.1:9000",
  "userName": "admin",
  "userPass": "password",
  "enableIRP": false
}
  1. 使用DOIP客户端与cordra服务端进行交互 (1) 查看服务端信息:
java -jar .\DoipSDK-1.0.jar -i
[INFO ]16:37:25.727 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:37:27.743 client sending message: {"requestId":"-886484722","targetId":"20.5000.123/service","operationId":"0.DOIP/Op.Hello","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:37:27.979 client received message: {"requestId":"-886484722","status":"0.DOIP/Status.001","output":{"id":"20.5000.123/service","type":"0.TYPE/DOIPService","attributes":{"ipAddress":"127.0.0.1","port":9000,"protocol":"TCP","protocolVersion":"2.0","publicKey":{"kty":"RSA","n":"i8MxV1gugMrs_GdSNDRzxzoj87vJZ9tlUyDHFYJ6oHJDtmD2F2VK_hwqTLQgadmmKTs2RfHfzIIrkz1vWqvGLMMaTvvmYpqjZml64FDXEXP1yynAhV34ylJ7ChYENmbc1gEkv44wqG8lvQdyeysxM9tz6VSlYwT1AjfAute9QjtscU5Hpzr7kBTOpRRE7za3dCErPmBbNZKDy9ZUREIsOik0jwnlEs7uGJgh4AoQR--qczbTO-VLafDE1pmIfaeQU9WAPD2euXZ34vaLyV2MsZQ4BGJq4xYYbBoKdSXikdRQ3NMsGjPalajdYdxwWCt0yVWbP9MGObTiv3OlOToyuQ","e":"AQAB"}}}} (DelimiterMessageClientCodec.java:85)

(2) 查看服务端支持的操作:

java -jar .\DoipSDK-1.0.jar -l
[INFO ]16:40:23.876 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:40:25.922 client sending message: {"requestId":"-1201986326","targetId":"20.5000.123/service","operationId":"0.DOIP/Op.ListOperations","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:40:26.100 client received message: {"requestId":"-1201986326","status":"0.DOIP/Status.001","output":["0.DOIP/Op.Hello","0.DOIP/Op.ListOperations","0.DOIP/Op.Create","0.DOIP/Op.Search"]} (DelimiterMessageClientCodec.java:85)

(3) 创建数字对象:

java -jar .\DoipSDK-1.0.jar -c 86.5000.470/do.cordra.test0 DO hello
[INFO ]16:39:09.847 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:39:11.800 client sending message: {"requestId":"-1058388874","targetId":"20.5000.123/service","operationId":"0.DOIP/Op.Create","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/do.cordra.test0","type":"0.TYPE/DO","attributes":{"content":{"create":"hello","name":"create","description":"this is an example for create"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:39:12.019 client received message: {"requestId":"-1058388874","status":"0.DOIP/Status.001","output":{"id":"86.5000.470/do.cordra.test0","type":"0.TYPE/DO","attributes":{"content":{"name":"create","description":"this is an example for create","create":"hello"},"metadata":{"createdOn":1610872751960,"createdBy":"admin","modifiedOn":1610872751960,"modifiedBy":"admin","txnId":1610872751963003}},"elements":[]}} (DelimiterMessageClientCodec.java:85)

(4) 更新数字对象:

java -jar .\DoipSDK-1.0.jar -u 86.5000.470/do.cordra.test0 DO hello_update
[INFO ]16:42:05.815 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:42:07.871 client sending message: {"requestId":"-702244521","targetId":"86.5000.470/do.cordra.test0","operationId":"0.DOIP/Op.Update","authentication":{"username":"admin","password":"password"}}
#
{"id":"86.5000.470/do.cordra.test0","type":"0.TYPE/DO","attributes":{"content":{"update":"hello_update","name":"update","description":"this is an example for update"}}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:42:08.083 client received message: {"requestId":"-702244521","status":"0.DOIP/Status.001","output":{"id":"86.5000.470/do.cordra.test0","type":"0.TYPE/DO","attributes":{"content":{"name":"update","description":"this is an example for update","update":"hello_update"},"metadata":{"createdOn":1610872751960,"createdBy":"admin","modifiedOn":1610872928052,"modifiedBy":"admin","txnId":1610872928045004}},"elements":[]}} (DelimiterMessageClientCodec.java:85)

(5) 获取数字对象

java -jar .\DoipSDK-1.0.jar -r 86.5000.470/do.cordra.test0
[INFO ]16:45:24.997 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:45:27.069 client sending message: {"requestId":"1215397185","targetId":"86.5000.470/do.cordra.test0","operationId":"0.DOIP/Op.Retrieve","attributes":{"includeElementData":"true"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:45:27.241 client received message: {"requestId":"1215397185","status":"0.DOIP/Status.001"}
#
{"id":"86.5000.470/do.cordra.test0","type":"0.TYPE/DO","attributes":{"content":{"name":"update","description":"this is an example for update","update":"hello_update"},"metadata":{"createdOn":1610872751960,"createdBy":"admin","modifiedOn":1610872928052,"modifiedBy":"admin","txnId":1610872928045004}},"elements":[]} (DelimiterMessageClientCodec.java:85)

(6) 检索数字对象:

java -jar .\DoipSDK-1.0.jar -s "+type:0.TYPE/DO +/name:update"
[INFO ]16:43:18.653 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:43:20.683 client sending message: {"requestId":"-328328880","targetId":"20.5000.123/service","operationId":"0.DOIP/Op.Search","attributes":{"query":"+type:0.TYPE/DO +/name:update","pageNum":0,"pageSize":10,"type":"full","sortFields":"id:ASC"},"authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:43:20.892 client received message: {"requestId":"-328328880","status":"0.DOIP/Status.001"}
#
{
  "size": 1,
  "results": [
    {
      "id": "86.5000.470/do.cordra.test0",
      "type": "0.TYPE/DO",
      "attributes": {
        "content": {
          "name": "update",
          "description": "this is an example for update",
          "update": "hello_update"
        },
        "metadata": {
          "createdOn": 1610872751960,
          "createdBy": "admin",
          "modifiedOn": 1610872928052,
          "modifiedBy": "admin",
          "txnId": 1610872928045004
        }
      },
      "elements": []
    }
  ]
} (DelimiterMessageClientCodec.java:85)

(7) 删除数字对象:

java -jar .\DoipSDK-1.0.jar -d 86.5000.470/do.cordra.test0
[INFO ]16:46:55.354 load config from: default_client.json (DOIPCMDClient.java:192)
[INFO ]16:46:57.436 client sending message: {"requestId":"-1326115326","targetId":"86.5000.470/do.cordra.test0","operationId":"0.DOIP/Op.Delete","authentication":{"username":"admin","password":"password"}}
#
#
 (DelimiterMessageClientCodec.java:35)
[INFO ]16:46:57.627 client received message: {"requestId":"-1326115326","status":"0.DOIP/Status.001"} (DelimiterMessageClientCodec.java:85)

3.1.2 使用cordra客户端访问PKU实现的DOIP服务

参考cordra提供的客户端开发代码,编写客户端程序,详细请参考cordra相关文档

注意:由于实现的差异,cordra客户端不能识别PKU DOIP服务针对hello操作返回的信息(包含签名),会报Unexpected input segments的错误。

4. 使用SDK编写自己的应用

下载doip-java-sdk v1.0,注意:由于SDK代码采用Java编写,请准备好JDK环境(版本>=java1.8)。

4.1 分析要管理的数据

参考DOIP2.0标准,数字对象是一个比特序列或者比特序列的集合,可以是任何可以分离并唯一标识的东西。

4.1.1 定义数字对象

以下通过一些具体的例子来说明如何通过SDK定义数字对象。

  • 字符串
DigitalObject digitalObject = new DigitalObject(doId, doType);
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", "hello");
jsonObject.addProperty("date", "2021/01/20");
jsonObject.addProperty("description", "this is an example for create");
  • 文件(文本、图片、文档)
DigitalObject digitalObject = new DigitalObject(doId, doType);
JsonObject jsonObject = new JsonObject();
Element element = new Element("file", "txt");
InputStream is = new FileInputStream(strFile);
int iAvail = is.available();
byte[] bytes = new byte[iAvail];
is.read(bytes);
is.close();
element.setData(bytes);

4.1.2 定义元数据格式

您可以根据自己的需求设计自己的元数据格式,比如如果您处理的数据是图书类数据,可以使用都柏林元数据标准。下面通过一个简单的示例来说明如何使用SDK定义元数据格式。

DigitalObject digitalObject = new DigitalObject(doId, DoType.Metadata);
JsonObject metadata = new JsonObject();
metadata.addProperty("doGroupName","DOIP");
metadata.addProperty("doGroupDesc","DOIP接口创建");
metadata.addProperty("doName","helloDO");
metadata.addProperty("doDesc","hello world");
digitalObject.addAttribute("metadata",new Gson().toJson(metadata));
digitalObject.addAttribute("owner","86.5000.470/dou.TEST");

4.2 使用SDK开发应用

在源码目录下创建libs目录,将下载的SDK文件解压出来的jar包拷贝到libs目录中,如果您使用gradle,请在build.gradle中添加如下代码:

repositories {
    maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
    flatDir { dirs 'libs' }
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.8.1'

    //netty
    implementation 'io.netty:netty-all:4.1.29.Final'

    //Http utils
    implementation 'org.apache.httpcomponents:httpclient:4.5.11'

    //Gson
    implementation 'com.google.code.gson:gson:2.8.6'

    // Log4j
    implementation 'log4j:log4j:1.2.17'

    // Junit
    testImplementation 'junit:junit:4.12'

    //bouncyCastle
    implementation 'org.bouncycastle:bcprov-jdk15on:1.65'

    //doip
    implementation files('libs/DoipSDK-1.0.jar')
}

4.2.1 实现自定义的Repository

参考源代码:org.bdware.doip.application.SimpleRepositoryMain

4.2.2 实现自定义的Registry

参考源代码:org.bdware.doip.application.SimpleRegistryMain

4.2.3 实现自定义的Client

参考源代码:org.bdware.doip.application.client.DOIPCMDClient

4.3 准备配置信息

4.3.1 生成证书

由于客户端与服务端采用了TLS通信协议,需要配置服务端密钥/证书。请确保环境中安装有keytools工具,然后使用如下命令,生成服务端使用的私钥和证书。

  • 为Repository生成证书
keytool -genkey -keyalg RSA -keysize 2048 -validity 365 -keypass 123456 -keystore doip_service_repository.keystore -storepass 123456 -dname "UID=86.5000.470/doip.RepositoryTLSService"
  • 为Registry生成证书
keytool -genkey -keyalg RSA -keysize 2048 -validity 365 -keypass 123456 -keystore doip_service_registry.keystore -storepass 123456 -dname "UID=86.5000.470/doip.RegistryTLSService"

4.3.2 编写配置文件

  1. Repository 创建名称为default_repository.conf的文件,写入如下内容。
{
  "LHSProxyAddress": "http://localhost:10001/",
  "ownerHandle": "86.5000.470/dou.SUPER0",
  "certPath": "keys/default_repo_0.keystore",
  "certPassword": "123456",
  "repoID": "86.5000.470/Repository.Test.00",
  "listeners": "[{\"url\":\"tls://127.0.0.1:1718\",\"protocolVersion\":\"2.0\",\"messageFormat\":\"delimiter\"}]",
  "serviceDescription": "local repository for test",
  "serviceName": "TestTLSRepository0"
}

创建名称为account.json的文件,写入如下内容(下述仅为示例),这将作为Repository管理员的初始账户/密码:

{
  "userName": "admin",
  "userPass": "password"
}
  1. Registry 创建名称为default_registry.conf的文件,写入如下内容。
{
  "LHSProxyAddress": "http://localhost:10001/",
  "ownerHandle": "86.5000.470/dou.SUPER",
  "certPath": "keys/default_regi.keystore",
  "certPassword": "123456",
  "repoID": "86.5000.470/Registry.Test",
  "listeners": "[{\"url\":\"tls://127.0.0.1:1720\",\"protocolVersion\":\"2.0\",\"messageFormat\":\"delimiter\"}]",
  "serviceDescription": "local registry for test",
  "serviceName": "TestTLSRegistry"
}

创建名称为account.json的文件,写入如下内容(下述仅为示例),这将作为Registry管理员的初始账户/密码:

{
  "userName": "admin",
  "userPass": "password"
}
  1. Client 创建名称为default_client.conf的文件,写入如下内容。
{
  "repoID": "86.5000.470/Repository.Test.00",
  "repoURL": "tls://127.0.0.1:1718",
  "userID": "86.5000.470/Repository.Test.00",
  "userName": "admin",
  "userPass": "password",
  "enableIRP": true
}

4.4 部署程序

  • 将编译好的Repository代码与default_server_repository.keystore,default_repository.conf放在同一目录,然后执行Repository。
  • 将编译好的Registry代码与default_server_registry.keystore,default_registry.conf放在同一目录,然后执行Registry。
  • 将编译好的Client代码与default_client_repository.keystore,default_client_registry.keystore,default_client.conf放在同一目录,然后执行Client。

5. 接口说明

详细的SDK接口说明文档

6. 查看源代码

  • doip-java-sdk-src v1.0