<file_sep>package biz.pdxtech.daap.ledger.util;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by bochenlong on 16-11-3.
 */
public class MessageCodec {
    private static ConcurrentHashMap<Class<?>, Schema<?>> cschema
            = new ConcurrentHashMap();

    public static <T> byte[] toBytes(T t) {
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        Class clazz = t.getClass();
        Schema schema = cschema.computeIfAbsent(clazz, a -> RuntimeSchema.createFrom(clazz));
        return ProtostuffIOUtil.toByteArray(t, schema, buffer);
    }

    public static <T> T toObject(byte[] bytes, Class<T> clazz) {
        try {
            T obj = clazz.newInstance();
            ProtostuffIOUtil.mergeFrom(bytes, obj, (Schema<T>) cschema.getOrDefault(clazz, RuntimeSchema.createFrom(clazz)));
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
<file_sep># daap-ledger

## PDX DaaP ledger application


### 1. maven工程创建  pom.xml 配置

#### 配置 maven repo
		<repository>
			<id>pdx-release</id>
			<name>biz.pdxtech</name>
			<url>http://daap.pdx.life:8081/nexus/content/repositories/releases</url>
		</repository>

#### 配置PDX BlockChain Driver API  依赖
		<!-- bcdriver api -->
		<dependency>
			<groupId>biz.pdxtech.daap</groupId>
			<artifactId>daap-bcdriver</artifactId>
			<version>1.2.5</version>
		</dependency>

#### 配置Default Ethereum BlockChain Driver实现  依赖
		<!-- Default Ethereum BlockChain Driver -->
		<dependency>
			<groupId>biz.pdxtech.daap</groupId>
			<artifactId>daap-ethbcdriver</artifactId>
			<version>1.2.5</version>
		</dependency>

### 2. BcDriver实例

**实例化BcDriver**

调用BcDriver首先需要实例化Driver.主要是两个参数。一个是协议栈类型；另一个是用户私钥。缺省情况下，协议栈类型为ethereum, 私钥会由BcDriver自动生成。调用者也可以通
过如下两个方法之一自己进行参数设置。


#### 2.1通过环境变量实例化

	BlockChainDriver driver = BlockChainDriverFactory.get();
		PDX_DAAP_CHAIN_TYPE		// 协议栈类型，默认 ethereum (以太坊）
		PDX_DAAP_PRIVATEKEY		//【可选】ECC私钥，HEX格式


#### 2.2通过property配置实例化

	BlockChainDriver driver = BlockChainDriverFactory.get(property);
	#blockchain Type
	type=ethereum
	#privateKey
	privateKey=********************************************


###	3.BcDriver调用

	通过BcDriver以下方法调用链上或者远端合约：
			query
			apply
	参见DaapLedgerCaller 例子
			通过设置Transaction 中属性指定contract 地址和自定义逻辑等
			dst  -->合约地址
			meta -->元数据，可查询
			body -->自定义数据结构

#### 3.1 ledger-query方法详细说明
Ledger查询分为两类；两类查询都可以通过设置Transaction.meta属性进行查询或者Transaction.body属性进行查询

**设置Transaction.meta属性查询**

1 查询交易
 * 根据交易ID查询；设置meta - ("DaaP-Query-TXID","txidtext".getBytes())
 * 根据自定义信息meta查询 设置meta - ("name","nametext") 可设置多个，但认为它们是与的关系
   
2 查询合约状态
 * 根据交易ID查询；设置meta - ("DaaP-Query-STATE-TXID","txidtext".getBytes())；此处查询出来的结果为此次交易执行完的合约状态
 * 根据合约查询 设置meta - ("DaaP-Query-STATE-DST","dsttext")
   
**设置Transaction.body属性进行查询，这时候你需要传入一个exp表达式，表达式形如："${tx:body[bodytext]}".getBytes())**

1 查询交易
 * 根据交易ID查询 设置body表达式 `"${tx:txid[txidtext]}".getBytes() `
 * 根据自定义信息meta查询 设置body表达式 `"${tx:meta[metak,metav]||meta[metak,metav]}".getBytes()`
   
  *注意：metav是将原byte[] Hex序列化过的文本*
  *辅助查询条件页码 设置body表达式 "${tx:txid[txidtext]&&pageno[2]}".getBytes() 不写默认为1页，每页固定1000记录*

2 查询合约状态
* 根据交易Id查询 设置body表达式 "${state:txid[txidtext]}".getBytes()
* 根据合约查询 设置body表达式 "${state:dst[dsttext]}".getBytes()
 
 *辅助查询条件页码 设置body表达式 "${state:dst[dsttext]&&pageno[2]}".getBytes() 不写默认为1页，每页固定1000记录*
 
##### 查询请注意：
 1 如果查询条件中含有txid的条件，则默认只根据txid查询
 2 exp表达式中必须以${tx:}/${state:}的形式
<file_sep>package biz.pdxtech.daap.ledger;

import biz.pdxtech.daap.api.contract.Transaction;
import biz.pdxtech.daap.bcdriver.BlockChainDriver;
import biz.pdxtech.daap.bcdriver.BlockChainDriverFactory;
import biz.pdxtech.daap.ledger.util.ContractState;
import biz.pdxtech.daap.ledger.util.HexUtil;
import biz.pdxtech.daap.ledger.util.MessageCodec;
import org.apache.commons.lang3.StringUtils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

public class DaapLedgerCaller {
    public static void main(String[] args) {
        /*1 setting props*/
        Properties props = new Properties();
        props.setProperty("privateKey", "623aacd6be3174d096711814e27487f26ce0126279ab3c85823cd3b2e86da28d");
        
        /*2 setting testKey*/
        setTestKey("2017-01-14T15:18:50.528");
        /*3 setting contract dst*/
        setContractDst("daap://default_pdx_chain/pdxdev/pdx.dapp/example");
    
        /*4 query from pdx*/
        BlockChainDriver driver = BlockChainDriverFactory.get(props);
        queryTx(driver, testKey);
        queryState(driver, testKey);
    }
    
    private static String testKey;
    private static String contractDst;
    
    /**
     * Ledger查询分为两类；两类查询都可以通过设置Transaction.meta属性进行查询或者Transaction.body属性进行查询
     * <p>
     * ### 设置Transaction.meta属性查询
     * 1 查询交易
     * ① 根据交易ID查询；设置meta - ("DaaP-Query-TXID","txidtext".getBytes())
     * ② 根据自定义信息meta查询 设置meta - ("name","nametext") 可设置多个，但认为它们是与的关系
     * <p>
     * 2 查询合约状态
     * ① 根据交易ID查询；设置meta - ("DaaP-Query-STATE-TXID","txidtext".getBytes())；此处查询出来的结果为此次交易执行完的合约状态
     * ② 根据合约查询 设置meta - ("DaaP-Query-STATE-DST","dsttext")
     * <p>
     * 2 设置Transaction.body属性进行查询，这时候你需要传入一个exp表达式，表达式形如："${tx:body[bodytext]}".getBytes())
     * <p>
     * ### 设置Transaction.body属性查询
     * 1 查询交易
     * ① 根据交易ID查询 设置body表达式 "${tx:txid[txidtext]}".getBytes()
     * ② 根据自定义信息meta查询 设置body表达式 "${tx:meta[metak,metav]||meta[metak,metav]}".getBytes() 注意：metav是将原byte[] Hex序列化过的文本
     * 辅助查询条件页码 设置body表达式 "${tx:txid[txidtext]&&pageno[2]}".getBytes() 不写默认为1页，每页固定1000记录
     * <p>
     * 2 查询合约状态
     * ① 根据交易Id查询 设置body表达式 "${state:txid[txidtext]}".getBytes()
     * ② 根据合约查询 设置body表达式 "${state:dst[dsttext]}".getBytes()
     * 辅助查询条件页码 设置body表达式 "${state:dst[dsttext]&&pageno[2]}".getBytes() 不写默认为1页，每页固定1000记录
     * <p>
     * 查询请注意：
     * 1 如果查询条件中含有txid的条件，则默认只根据txid查询
     * 2 exp表达式中必须以${tx:}/${state:}的形式
     *
     * @param driver
     */
    private static void queryTx(BlockChainDriver driver, String testKey) {
        assert StringUtils.isNotEmpty(testKey);
        
        
        /**1 设置Transaction.meta属性查询交易*/
        /** 根据交易ID查询*/
        Transaction tx = new Transaction();
        Map<String, byte[]> map = new LinkedHashMap<>();
        map.put("DaaP-Query-TX-TXID", "e4ebcbd2f017ab188d0b828cdf1568d17d1ab4ce5a0dcf63418656d8740b813e".getBytes());
        tx.setMeta(map);
        queryTx(tx, driver);
        
        /** 根据自定义信息查询*/
        tx = new Transaction();
        map = new LinkedHashMap<>();
        map.put("name", DaapCaller.addTestKey("kangxinghao", testKey).getBytes());
        map.put("age", DaapCaller.addTestKey("22", testKey).getBytes());
        tx.setMeta(map);
        queryTx(tx, driver);
        
        /**2 设置Transaction.body属性进行查询*/
        /** 根据交易ID查询*/
        tx = new Transaction();
        tx.setBody("${tx:txid[e4ebcbd2f017ab188d0b828cdf1568d17d1ab4ce5a0dcf63418656d8740b813e]}".getBytes());
        queryTx(tx, driver);
        
        /** 根据自定义信息查询*/
        String exp = ("${tx:meta[name," + HexUtil.toHex(DaapCaller.addTestKey("kangxinghao", testKey).getBytes())
                + "]||meta[age," + HexUtil.toHex(DaapCaller.addTestKey("22", testKey).getBytes()) + "]}");
        tx.setBody(exp.getBytes());
        queryTx(tx, driver);
    }
    
    private static void queryState(BlockChainDriver driver, String testKey) {
        assert StringUtils.isNotEmpty(testKey);
        
        /**1 设置Transaction.meta属性查询合约状态*/
        Transaction tx = new Transaction();
        Map<String, byte[]> map = new LinkedHashMap<>();
        map.put("DaaP-Query-STATE-TXID", "e4ebcbd2f017ab188d0b828cdf1568d17d1ab4ce5a0dcf63418656d8740b813e".getBytes());
        tx.setMeta(map);
        queryState(tx, driver);
        /**2 设置Transaction.body属性进行查询*/
        /** 根据交易ID查询*/
        tx = new Transaction();
        tx.setBody("${state:txid[e4ebcbd2f017ab188d0b828cdf1568d17d1ab4ce5a0dcf63418656d8740b813e]}".getBytes());
        queryState(tx, driver);
        /** 根据合约地址查询*/
        tx = new Transaction();
        String exp = ("${state:dst[" + contractDst + "]");
        tx.setBody(exp.getBytes());
        queryState(tx, driver);
    }
    
    private static void queryTx(Transaction tx, BlockChainDriver driver) {
        try {
            tx.setDst(new URI("daap://tender-pdx/pdx.dapp/ledger"));
            List<Transaction> res = driver.query(tx);
            if (res != null && res.size() > 0) {
                res.stream().forEach(a -> System.out.println(new String(a.getBody())));
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
    
    private static void queryState(Transaction tx, BlockChainDriver driver) {
        try {
            tx.setDst(new URI("daap://tender-pdx/pdx.dapp/ledger"));
            List<Transaction> res = driver.query(tx);
            if (res != null && res.size() > 0) {
                res.stream().forEach(a -> {
             	    if(a.getBody() != null && a.getBody().length != 0) {
                		 ContractState state = MessageCodec.toObject(a.getBody(), ContractState.class);
                         state.getMap().entrySet().stream().forEach(b -> {
                             System.out.println("key : " + b.getKey());
                             System.out.println("value : " + new String(b.getValue()));
                         });
                	}
                });
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
    
    public static String getTestKey() {
        return testKey;
    }
    
    public static void setTestKey(String testKey) {
        DaapLedgerCaller.testKey = testKey;
    }
    
    private static void setContractDst(String dst) {
        contractDst = dst;
    }
    
    public static String getContractDst() {
        return contractDst;
    }
}
<file_sep><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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>biz.pdxtech.daap</groupId>
    <artifactId>daap-ledger</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>daap-ledger</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.8</jdk.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <driver.version>1.2.5</driver.version>
        <protostuff.version>1.5.2</protostuff.version>
    </properties>

    <dependencies>
        <!-- bcdriver api -->
        <dependency>
            <groupId>biz.pdxtech.daap</groupId>
            <artifactId>daap-bcdriver</artifactId>
            <version>${driver.version}</version>
        </dependency>

        <!-- ethbcdriver -->
        <dependency>
            <groupId>biz.pdxtech.daap</groupId>
            <artifactId>daap-ethbcdriver</artifactId>
            <version>${driver.version}</version>
        </dependency>

        <!-- protoStuff -->
        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>${protostuff.version}</version>
        </dependency>
        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>${protostuff.version}</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>pdx-release</id>
            <name>biz.pdxtech</name>
            <url>http://daap.pdx.life:8081/nexus/content/repositories/releases</url>
        </repository>
    </repositories>
</project>
