| @@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.AccountHeader; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class ContractAccount implements AccountHeader { | |||
| @@ -43,7 +43,7 @@ public class ContractAccount implements AccountHeader { | |||
| } | |||
| public long setChaincode(byte[] chaincode, long version) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(chaincode); | |||
| BytesValue bytesValue = BytesData.fromBytes(chaincode); | |||
| return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version); | |||
| } | |||
| @@ -60,18 +60,18 @@ public class ContractAccount implements AccountHeader { | |||
| } | |||
| public long setProperty(Bytes key, String value, long version) { | |||
| BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
| BytesValue bytesValue = BytesData.fromText(value); | |||
| return accBase.setBytes(encodePropertyKey(key), bytesValue, version); | |||
| } | |||
| public String getProperty(Bytes key) { | |||
| BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key)); | |||
| return BytesValueEntry.toText(bytesValue); | |||
| return BytesData.toText(bytesValue); | |||
| } | |||
| public String getProperty(Bytes key, long version) { | |||
| BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version); | |||
| return BytesValueEntry.toText(bytesValue); | |||
| return BytesData.toText(bytesValue); | |||
| } | |||
| private Bytes encodePropertyKey(Bytes key) { | |||
| @@ -6,7 +6,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.AccountHeader; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.KVDataEntry; | |||
| import com.jd.blockchain.ledger.KVDataObject; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| @@ -49,12 +49,12 @@ public class DataAccount implements AccountHeader, MerkleProvable { | |||
| public long setBytes(Bytes key, String value, long version) { | |||
| BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
| BytesValue bytesValue = BytesData.fromText(value); | |||
| return baseAccount.setBytes(key, bytesValue, version); | |||
| } | |||
| public long setBytes(Bytes key, byte[] value, long version) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
| BytesValue bytesValue = BytesData.fromBytes(value); | |||
| return baseAccount.setBytes(key, bytesValue, version); | |||
| } | |||
| @@ -3,7 +3,7 @@ package com.jd.blockchain.ledger.core; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.UserInfo; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| @@ -50,12 +50,12 @@ public class UserAccount implements UserInfo { | |||
| public long setDataPubKey(PubKey pubKey) { | |||
| byte[] pkBytes = pubKey.toBytes(); | |||
| return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), -1); | |||
| return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1); | |||
| } | |||
| public long setDataPubKey(PubKey pubKey, long version) { | |||
| byte[] pkBytes = pubKey.toBytes(); | |||
| return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), version); | |||
| return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version); | |||
| } | |||
| public long setProperty(String key, String value, long version) { | |||
| @@ -63,7 +63,7 @@ public class UserAccount implements UserInfo { | |||
| } | |||
| public long setProperty(Bytes key, String value, long version) { | |||
| return baseAccount.setBytes(encodePropertyKey(key), BytesValueEntry.fromText(value), version); | |||
| return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version); | |||
| } | |||
| public String getProperty(Bytes key) { | |||
| @@ -8,7 +8,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.AccountHeader; | |||
| import com.jd.blockchain.ledger.BlockchainIdentity; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
| import com.jd.blockchain.ledger.KVDataEntry; | |||
| @@ -279,7 +279,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
| BytesValue bytesValue = BytesData.fromText(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -287,7 +287,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
| BytesValue bytesValue = BytesData.fromBytes(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -295,7 +295,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromInt64(value); | |||
| BytesValue bytesValue = BytesData.fromInt64(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -312,7 +312,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromJSON(value); | |||
| BytesValue bytesValue = BytesData.fromJSON(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -320,7 +320,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromXML(value); | |||
| BytesValue bytesValue = BytesData.fromXML(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -328,7 +328,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
| BytesValue bytesValue = BytesData.fromBytes(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -336,7 +336,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromImage(value); | |||
| BytesValue bytesValue = BytesData.fromImage(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -344,7 +344,7 @@ public class ContractLedgerContext implements LedgerContext { | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); | |||
| BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
| this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); | |||
| handle(op); | |||
| return this; | |||
| @@ -12,7 +12,7 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; | |||
| import com.jd.blockchain.crypto.service.sm.SMCryptoService; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.core.BaseAccount; | |||
| import com.jd.blockchain.ledger.core.CryptoConfig; | |||
| import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | |||
| @@ -53,33 +53,33 @@ public class BaseAccountTest { | |||
| assertFalse(baseAccount.isReadonly()); | |||
| // 在空白状态下写入数据; | |||
| long v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 0); | |||
| long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0); | |||
| // 预期失败; | |||
| assertEquals(-1, v); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 1); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1); | |||
| // 预期失败; | |||
| assertEquals(-1, v); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), -1); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1); | |||
| // 预期成功; | |||
| assertEquals(0, v); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A-1"), -1); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1); | |||
| // 已经存在版本,指定版本号-1,预期导致失败; | |||
| assertEquals(-1, v); | |||
| baseAccount.commit(); | |||
| v = 0; | |||
| for (int i = 0; i < 10; i++) { | |||
| long s = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + i), v); | |||
| long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v); | |||
| baseAccount.commit(); | |||
| // 预期成功; | |||
| assertEquals(v + 1, s); | |||
| v++; | |||
| } | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + v), v + 1); | |||
| v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1); | |||
| // 预期成功; | |||
| assertEquals(-1, v); | |||
| @@ -21,7 +21,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.EndpointRequest; | |||
| import com.jd.blockchain.ledger.LedgerBlock; | |||
| import com.jd.blockchain.ledger.LedgerInitSetting; | |||
| @@ -103,6 +103,7 @@ public class ContractInvokingTest { | |||
| Random rand = new Random(); | |||
| TxBuilder txBuilder = new TxBuilder(ledgerHash); | |||
| TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class); | |||
| TestContract contractProxy1 = txBuilder.contract(contractAddress, TestContract.class); | |||
| String asset = "AK"; | |||
| long issueAmount = rand.nextLong(); | |||
| @@ -120,7 +121,7 @@ public class ContractInvokingTest { | |||
| assertEquals(1, opResults.length); | |||
| assertEquals(0, opResults[0].getIndex()); | |||
| byte[] expectedRetnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class); | |||
| byte[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class); | |||
| byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); | |||
| assertArrayEquals(expectedRetnBytes, reallyRetnBytes); | |||
| @@ -1,5 +1,6 @@ | |||
| package test.com.jd.blockchain.ledger; | |||
| import static org.junit.Assert.assertArrayEquals; | |||
| import static org.junit.Assert.assertEquals; | |||
| import static org.junit.Assert.assertFalse; | |||
| import static org.junit.Assert.assertNotNull; | |||
| @@ -10,10 +11,13 @@ import java.util.Random; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.BytesDataList; | |||
| import com.jd.blockchain.ledger.BytesValueList; | |||
| import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| @@ -67,8 +71,8 @@ public class TransactionSetTest { | |||
| BlockchainKeypair dataKey = BlockchainKeyGenerator.getInstance().generate(); | |||
| DataAccountRegisterOperation dataAccRegOp = txBuilder.dataAccounts().register(dataKey.getIdentity()); | |||
| DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress()) | |||
| .setText("A", "Value_A_0", -1).setText("B", "Value_B_0", -1).getOperation(); | |||
| DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress()).setText("A", "Value_A_0", -1) | |||
| .setText("B", "Value_B_0", -1).getOperation(); | |||
| byte[] chainCode = new byte[128]; | |||
| rand.nextBytes(chainCode); | |||
| @@ -76,7 +80,7 @@ public class TransactionSetTest { | |||
| ContractCodeDeployOperation contractDplOP = txBuilder.contracts().deploy(contractKey.getIdentity(), chainCode); | |||
| ContractEventSendOperation contractEvtSendOP = txBuilder.contractEvents().send(contractKey.getAddress(), "test", | |||
| "TestContractArgs".getBytes()); | |||
| BytesDataList.singleText("TestContractArgs")); | |||
| TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
| @@ -98,7 +102,8 @@ public class TransactionSetTest { | |||
| txSnapshot.setContractAccountSetHash(contractAccountSetHash); | |||
| long blockHeight = 8922L; | |||
| LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot, null); | |||
| LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot, | |||
| null); | |||
| txset.add(tx); | |||
| assertTrue(txset.isUpdated()); | |||
| @@ -172,7 +177,8 @@ public class TransactionSetTest { | |||
| for (int i = 0; i < acutualKVWriteSet.length; i++) { | |||
| assertEquals(expKVWriteSet[i].getKey(), acutualKVWriteSet[i].getKey()); | |||
| assertEquals(expKVWriteSet[i].getExpectedVersion(), acutualKVWriteSet[i].getExpectedVersion()); | |||
| assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), acutualKVWriteSet[i].getValue().getValue().toBytes())); | |||
| assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), | |||
| acutualKVWriteSet[i].getValue().getValue().toBytes())); | |||
| } | |||
| ContractCodeDeployOperation actualContractDplOp = (ContractCodeDeployOperation) actualOperations[3]; | |||
| @@ -184,8 +190,14 @@ public class TransactionSetTest { | |||
| assertEquals(contractEvtSendOP.getContractAddress(), actualContractEvtSendOp.getContractAddress()); | |||
| assertEquals(contractEvtSendOP.getEvent(), actualContractEvtSendOp.getEvent()); | |||
| assertEquals("test", actualContractEvtSendOp.getEvent()); | |||
| assertTrue(BytesUtils.equals(contractEvtSendOP.getArgs(), actualContractEvtSendOp.getArgs())); | |||
| assertTrue(BytesUtils.equals("TestContractArgs".getBytes(), actualContractEvtSendOp.getArgs())); | |||
| byte[] expectedBytes = BinaryProtocol.encode(contractEvtSendOP.getArgs(), BytesValueList.class); | |||
| byte[] actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class); | |||
| assertArrayEquals(expectedBytes, actualBytes); | |||
| expectedBytes = BinaryProtocol.encode(BytesDataList.singleText("TestContractArgs"), BytesValueList.class); | |||
| actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class); | |||
| assertArrayEquals(expectedBytes, actualBytes); | |||
| } | |||
| } | |||
| @@ -8,38 +8,38 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public class BytesValueEntry implements BytesValue { | |||
| public class BytesData implements BytesValue { | |||
| DataType type; | |||
| Bytes value; | |||
| private BytesValueEntry(DataType type, byte[] bytes) { | |||
| private BytesData(DataType type, byte[] bytes) { | |||
| this.type = type; | |||
| this.value = new Bytes(bytes); | |||
| } | |||
| private BytesValueEntry(DataType type, Bytes bytes) { | |||
| private BytesData(DataType type, Bytes bytes) { | |||
| this.type = type; | |||
| this.value = bytes; | |||
| } | |||
| public static BytesValue fromType(DataType type, byte[] value) { | |||
| return new BytesValueEntry(type, value); | |||
| return new BytesData(type, value); | |||
| } | |||
| public static BytesValue fromBytes(byte[] value) { | |||
| return new BytesValueEntry(DataType.BYTES, value); | |||
| return new BytesData(DataType.BYTES, value); | |||
| } | |||
| public static BytesValue fromBytes(Bytes value) { | |||
| return new BytesValueEntry(DataType.BYTES, value); | |||
| return new BytesData(DataType.BYTES, value); | |||
| } | |||
| public static BytesValue fromImage(byte[] value) { | |||
| return new BytesValueEntry(DataType.IMG, value); | |||
| return new BytesData(DataType.IMG, value); | |||
| } | |||
| public static BytesValue fromImage(Bytes value) { | |||
| return new BytesValueEntry(DataType.IMG, value); | |||
| return new BytesData(DataType.IMG, value); | |||
| } | |||
| /** | |||
| @@ -49,7 +49,7 @@ public class BytesValueEntry implements BytesValue { | |||
| * @return | |||
| */ | |||
| public static BytesValue fromText(String value) { | |||
| return new BytesValueEntry(DataType.TEXT, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); | |||
| } | |||
| /** | |||
| @@ -70,35 +70,35 @@ public class BytesValueEntry implements BytesValue { | |||
| } | |||
| public static BytesValue fromJSON(String value) { | |||
| return new BytesValueEntry(DataType.JSON, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromXML(String value) { | |||
| return new BytesValueEntry(DataType.XML, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.XML, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromInt32(int value) { | |||
| return new BytesValueEntry(DataType.INT32, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromInt64(long value) { | |||
| return new BytesValueEntry(DataType.INT64, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromInt16(short value) { | |||
| return new BytesValueEntry(DataType.INT16, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromInt8(byte value) { | |||
| return new BytesValueEntry(DataType.INT8, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromTimestamp(long value) { | |||
| return new BytesValueEntry(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); | |||
| } | |||
| public static BytesValue fromBoolean(boolean value) { | |||
| return new BytesValueEntry(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
| return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); | |||
| } | |||
| @Override | |||
| @@ -0,0 +1,31 @@ | |||
| package com.jd.blockchain.ledger; | |||
| public class BytesDataList implements BytesValueList { | |||
| private BytesValue[] bytesValues; | |||
| public BytesDataList(BytesValue... bytesValues) { | |||
| this.bytesValues = bytesValues; | |||
| } | |||
| @Override | |||
| public BytesValue[] getValues() { | |||
| return bytesValues; | |||
| } | |||
| public static BytesValueList singleText(String value) { | |||
| return new BytesDataList(BytesData.fromText(value)); | |||
| } | |||
| public static BytesValueList singleLong(long value) { | |||
| return new BytesDataList(BytesData.fromInt64(value)); | |||
| } | |||
| public static BytesValueList singleInt(int value) { | |||
| return new BytesDataList(BytesData.fromInt32(value)); | |||
| } | |||
| public static BytesValueList singleBoolean(boolean value) { | |||
| return new BytesDataList(BytesData.fromBoolean(value)); | |||
| } | |||
| } | |||
| @@ -1,5 +1,7 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import java.io.Closeable; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| @@ -9,7 +11,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public interface PreparedTransaction extends HashObject { | |||
| public interface PreparedTransaction extends HashObject, Closeable { | |||
| /** | |||
| * 交易内容的 Hash; | |||
| @@ -55,8 +57,4 @@ public interface PreparedTransaction extends HashObject { | |||
| */ | |||
| TransactionResponse commit(); | |||
| /** | |||
| * 取消交易;<br> | |||
| */ | |||
| void cancel(); | |||
| } | |||
| @@ -1,5 +1,7 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import java.io.Closeable; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.transaction.ClientOperator; | |||
| @@ -9,7 +11,7 @@ import com.jd.blockchain.transaction.ClientOperator; | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public interface TransactionTemplate extends ClientOperator { | |||
| public interface TransactionTemplate extends ClientOperator, Closeable { | |||
| HashDigest getLedgerHash(); | |||
| @@ -106,15 +106,15 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
| * | |||
| * @return | |||
| */ | |||
| public Collection<OperationReturnValueHandler> getReturnValuetHandlers() { | |||
| List<OperationReturnValueHandler> resultHandlers = new ArrayList<OperationReturnValueHandler>(); | |||
| public Collection<OperationResultHandle> getReturnValuetHandlers() { | |||
| List<OperationResultHandle> resultHandlers = new ArrayList<OperationResultHandle>(); | |||
| int index = 0; | |||
| for (Operation op : operationList) { | |||
| if (op instanceof ContractEventSendOperation) { | |||
| // 操作具有返回值,创建对应的结果处理器; | |||
| ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; | |||
| ContractInvocation invocation = opTemp.getInvocation(); | |||
| OperationReturnValueHandler retnHandler; | |||
| OperationResultHandle retnHandler; | |||
| if (invocation == null) { | |||
| retnHandler = new NullOperationReturnValueHandler(index); | |||
| } else { | |||
| @@ -278,7 +278,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| private static class NullOperationReturnValueHandler implements OperationReturnValueHandler { | |||
| private static class NullOperationReturnValueHandler implements OperationResultHandle { | |||
| private int operationIndex; | |||
| @@ -292,10 +292,14 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||
| } | |||
| @Override | |||
| public Object setReturnValue(BytesValue bytesValue) { | |||
| public Object complete(BytesValue bytesValue) { | |||
| return null; | |||
| } | |||
| @Override | |||
| public void complete(Throwable error) { | |||
| } | |||
| } | |||
| } | |||
| @@ -1,43 +1,22 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class BooleanValueHolder extends ValueHolderWrapper { | |||
| public class BooleanValueHolder extends ValueHolderBase { | |||
| BooleanValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| BooleanValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 获取值;<br> | |||
| * | |||
| * @return | |||
| */ | |||
| public boolean get() { | |||
| return (boolean) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public boolean get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 false; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public boolean get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (boolean) super.getValue(timeout, unit); | |||
| public boolean get() { | |||
| return super.isCompleted() ? (boolean) super.getValue() : false; | |||
| } | |||
| } | |||
| @@ -1,43 +1,22 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class ByteValueHolder extends ValueHolderWrapper { | |||
| public class ByteValueHolder extends ValueHolderBase { | |||
| ByteValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| ByteValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 获取值;<br> | |||
| * | |||
| * @return | |||
| */ | |||
| public byte get() { | |||
| return (byte) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public byte get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public byte get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (byte) super.getValue(timeout, unit); | |||
| public byte get() { | |||
| return super.isCompleted() ? (byte) super.getValue() : 0; | |||
| } | |||
| } | |||
| @@ -1,8 +1,6 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.lang.reflect.Method; | |||
| import java.util.concurrent.CompletableFuture; | |||
| import java.util.concurrent.Future; | |||
| import com.jd.blockchain.contract.ContractType; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| @@ -14,7 +12,7 @@ import com.jd.blockchain.ledger.BytesValueEncoding; | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| class ContractInvocation implements OperationReturnValueHandler { | |||
| class ContractInvocation extends OperationResultHolder { | |||
| private Method method; | |||
| @@ -22,12 +20,9 @@ class ContractInvocation implements OperationReturnValueHandler { | |||
| private int operationIndex = -1; | |||
| private CompletableFuture<Object> returnValueFuture; | |||
| public ContractInvocation(ContractType contractType, Method method) { | |||
| this.contractType = contractType; | |||
| this.method = method; | |||
| this.returnValueFuture = new CompletableFuture<Object>(); | |||
| } | |||
| public ContractType getContractType() { | |||
| @@ -47,16 +42,9 @@ class ContractInvocation implements OperationReturnValueHandler { | |||
| return method.getReturnType(); | |||
| } | |||
| public Future<Object> getReturnValue() { | |||
| return returnValueFuture; | |||
| } | |||
| @Override | |||
| public Object setReturnValue(BytesValue bytesValue) { | |||
| // Resolve BytesValue to an value object with the return type; | |||
| Object returnValue = BytesValueEncoding.decode(bytesValue, method.getReturnType()); | |||
| returnValueFuture.complete(returnValue); | |||
| return returnValue; | |||
| protected Object decodeResult(BytesValue bytesValue) { | |||
| return BytesValueEncoding.decode(bytesValue, method.getReturnType()); | |||
| } | |||
| } | |||
| @@ -4,10 +4,8 @@ import java.lang.reflect.Proxy; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| import com.jd.blockchain.contract.EventResult; | |||
| import com.jd.blockchain.contract.ContractType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.IllegalDataException; | |||
| /** | |||
| * 合约调用代理的构建器; | |||
| @@ -19,8 +17,6 @@ public class ContractInvocationProxyBuilder { | |||
| private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | |||
| // private Map<Object, Integer> contractOperations = new ConcurrentHashMap<>(); | |||
| public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
| return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | |||
| } | |||
| @@ -33,31 +29,9 @@ public class ContractInvocationProxyBuilder { | |||
| T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | |||
| new Class<?>[] { contractIntf }, proxyHandler); | |||
| // // 创建关联关系 | |||
| // contractOperations.put(proxy, proxyHandler.opIndex()); | |||
| return proxy; | |||
| } | |||
| // public <T> EventResult<T> execute(ContractEventExecutor execute) { | |||
| // Object contractProxy = execute.execute(); | |||
| // if (contractProxy == null) { | |||
| // // 该方法执行必须要有返回值 | |||
| // throw new IllegalStateException( | |||
| // String.format("ContractEventExecutor [%s] 's return must be not empty !!!", execute.toString())); | |||
| // } | |||
| // if (!(contractProxy instanceof Proxy)) { | |||
| // throw new IllegalDataException( | |||
| // String.format("ContractEventExecutor [%s] 's return must from TxTemplate.contract()'s result !!!", | |||
| // execute.toString())); | |||
| // } | |||
| // | |||
| // Integer opIndex = contractOperations.get(contractProxy); | |||
| // if (opIndex != null && opIndex > -1) { | |||
| // return new EventResult<>(opIndex); | |||
| // } | |||
| // return null; | |||
| // } | |||
| private ContractType resolveContractType(Class<?> contractIntf) { | |||
| ContractType contractType = contractTypes.get(contractIntf); | |||
| if (contractType != null) { | |||
| @@ -26,9 +26,9 @@ public class ContractReturnValue { | |||
| * @param call | |||
| * @return | |||
| */ | |||
| public static <T> ValueHolder<T> decode(T call) { | |||
| public static <T> GenericValueHolder<T> decode(T call) { | |||
| ContractInvocation invocation = ContractInvocationStub.take(); | |||
| return new ValueHolder<T>(invocation); | |||
| return new GenericValueHolder<T>(invocation); | |||
| } | |||
| /** | |||
| @@ -1,7 +1,7 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| @@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
| BytesValue bytesValue = BytesData.fromBytes(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromImage(value); | |||
| BytesValue bytesValue = BytesData.fromImage(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromText(value); | |||
| BytesValue bytesValue = BytesData.fromText(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromBytes(value); | |||
| BytesValue bytesValue = BytesData.fromBytes(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromInt64(value); | |||
| BytesValue bytesValue = BytesData.fromInt64(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromJSON(value); | |||
| BytesValue bytesValue = BytesData.fromJSON(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromXML(value); | |||
| BytesValue bytesValue = BytesData.fromXML(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
| BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); | |||
| BytesValue bytesValue = BytesData.fromTimestamp(value); | |||
| operation.set(key, bytesValue, expVersion); | |||
| return this; | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| package com.jd.blockchain.transaction; | |||
| public class GenericValueHolder<T> extends ValueHolderWrapper { | |||
| GenericValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 获取值;<br> | |||
| * | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; | |||
| * | |||
| * @return | |||
| */ | |||
| @SuppressWarnings("unchecked") | |||
| public T get() { | |||
| return (T) super.getValue(); | |||
| } | |||
| } | |||
| @@ -1,43 +1,22 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class IntValueHolder extends ValueHolderWrapper { | |||
| public class IntValueHolder extends ValueHolderBase { | |||
| IntValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| IntValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 获取值;<br> | |||
| * | |||
| * @return | |||
| */ | |||
| public int get() { | |||
| return (int) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public int get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public int get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (int) super.getValue(timeout, unit); | |||
| public int get() { | |||
| return super.isCompleted() ? (int) super.getValue() : 0; | |||
| } | |||
| } | |||
| @@ -1,43 +1,22 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class LongValueHolder extends ValueHolderWrapper { | |||
| public class LongValueHolder extends ValueHolderBase { | |||
| LongValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| LongValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 获取值;<br> | |||
| * | |||
| * @return | |||
| */ | |||
| public long get() { | |||
| return (long) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public long get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public long get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (long) super.getValue(timeout, unit); | |||
| public long get() { | |||
| return super.isCompleted() ? (long) super.getValue() : 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| public class OperationCompletedContext { | |||
| private int operationIndex; | |||
| private BytesValue returnBytesValue; | |||
| public OperationCompletedContext(int operationIndex, BytesValue returnBytesValue) { | |||
| this.operationIndex = operationIndex; | |||
| this.returnBytesValue = returnBytesValue; | |||
| } | |||
| public int getOperationIndex() { | |||
| return operationIndex; | |||
| } | |||
| public BytesValue getReturnBytesValue() { | |||
| return returnBytesValue; | |||
| } | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| package com.jd.blockchain.transaction; | |||
| /** | |||
| * 操作完成监听器; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public interface OperationCompletedListener { | |||
| /** | |||
| * 当操作完成时发生; | |||
| * | |||
| * @param retnValue 返回值; | |||
| * @param error 异常;如果值为非空,则表示由异常导致结束; | |||
| * @param context 上下文对象; | |||
| */ | |||
| void onCompleted(Object retnValue, Throwable error, OperationCompletedContext context); | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| /** | |||
| * 操作返回值处理器; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| interface OperationResultHandle { | |||
| /** | |||
| * 操作的索引位置; | |||
| * | |||
| * @return | |||
| */ | |||
| int getOperationIndex(); | |||
| /** | |||
| * 正常地完成; | |||
| * | |||
| * @param returnBytesValue | |||
| * @return | |||
| */ | |||
| Object complete(BytesValue returnBytesValue); | |||
| /** | |||
| * 以异常方式完成; | |||
| * | |||
| * @param error | |||
| */ | |||
| void complete(Throwable error); | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.utils.event.EventMulticaster; | |||
| abstract class OperationResultHolder implements OperationResultHandle { | |||
| private Object value; | |||
| private Throwable error; | |||
| private volatile boolean completed; | |||
| private EventMulticaster<OperationCompletedListener> listenerMulticaster; | |||
| /** | |||
| * 导致结束的错误; | |||
| * | |||
| * @return | |||
| */ | |||
| public Throwable getError() { | |||
| return error; | |||
| } | |||
| /** | |||
| * 是否已经处理完成; | |||
| * | |||
| * @return | |||
| */ | |||
| public boolean isCompleted() { | |||
| return completed; | |||
| } | |||
| /** | |||
| * 获取操作的返回值; <br> | |||
| * 在操作未完成之前,总是返回 null;<br> | |||
| * 可以通过 {@link #isCompleted()} 方法判断操作是否已经完成;<br> | |||
| * 可以通过 {@link #addCompletedListener(OperationCompletedListener)} | |||
| * 方法添加监听器来监听操作完成的事件; | |||
| * | |||
| * @return | |||
| */ | |||
| public Object getResult() { | |||
| return value; | |||
| } | |||
| /** | |||
| * 添加操作完成监听器; | |||
| * | |||
| * @param listener | |||
| */ | |||
| public void addCompletedListener(OperationCompletedListener listener) { | |||
| listenerMulticaster.addListener(listener); | |||
| } | |||
| protected abstract Object decodeResult(BytesValue bytesValue); | |||
| @Override | |||
| public Object complete(BytesValue bytesValue) { | |||
| if (this.completed) { | |||
| throw new IllegalStateException( | |||
| "Contract invocation has been completed, and is not allowed to be completed again!"); | |||
| } | |||
| this.completed = true; | |||
| this.value = decodeResult(bytesValue); | |||
| OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); | |||
| listenerMulticaster.getBroadcaster().onCompleted(value, null, context); | |||
| return null; | |||
| } | |||
| @Override | |||
| public void complete(Throwable error) { | |||
| if (completed) { | |||
| return; | |||
| } | |||
| this.completed = true; | |||
| this.error = error; | |||
| OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); | |||
| listenerMulticaster.getBroadcaster().onCompleted(null, error, context); | |||
| } | |||
| } | |||
| @@ -1,11 +0,0 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| interface OperationReturnValueHandler { | |||
| int getOperationIndex(); | |||
| Object setReturnValue(BytesValue bytesValue); | |||
| } | |||
| @@ -1,9 +1,12 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.io.IOException; | |||
| import java.util.Arrays; | |||
| import java.util.Collection; | |||
| import java.util.Comparator; | |||
| import org.springframework.cglib.proxy.UndeclaredThrowableException; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| @@ -25,7 +28,9 @@ public class PreparedTx implements PreparedTransaction { | |||
| private TransactionService txProcessor; | |||
| private OperationReturnValueHandler[] opReturnValueHandlers; | |||
| private OperationResultHandle[] opReturnValueHandlers; | |||
| private TxStateManager stateManager; | |||
| /** | |||
| * 创建一个“就绪交易”对象; | |||
| @@ -34,17 +39,18 @@ public class PreparedTx implements PreparedTransaction { | |||
| * @param txProcessor 交易处理服务; | |||
| * @param opReturnValueHandlerList 操作返回值处理器列表; | |||
| */ | |||
| public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, | |||
| Collection<OperationReturnValueHandler> opReturnValueHandlerList) { | |||
| public PreparedTx(TxStateManager stateManager, TransactionRequestBuilder txReqBuilder, | |||
| TransactionService txProcessor, Collection<OperationResultHandle> opReturnValueHandlerList) { | |||
| this.stateManager = stateManager; | |||
| this.txReqBuilder = txReqBuilder; | |||
| this.txProcessor = txProcessor; | |||
| this.opReturnValueHandlers = opReturnValueHandlerList | |||
| .toArray(new OperationReturnValueHandler[opReturnValueHandlerList.size()]); | |||
| .toArray(new OperationResultHandle[opReturnValueHandlerList.size()]); | |||
| // 按照操作索引升序排列; | |||
| Arrays.sort(opReturnValueHandlers, new Comparator<OperationReturnValueHandler>() { | |||
| Arrays.sort(opReturnValueHandlers, new Comparator<OperationResultHandle>() { | |||
| @Override | |||
| public int compare(OperationReturnValueHandler o1, OperationReturnValueHandler o2) { | |||
| public int compare(OperationResultHandle o1, OperationResultHandle o2) { | |||
| return o1.getOperationIndex() - o2.getOperationIndex(); | |||
| } | |||
| }); | |||
| @@ -78,31 +84,59 @@ public class PreparedTx implements PreparedTransaction { | |||
| @Override | |||
| public TransactionResponse commit() { | |||
| stateManager.commit(); | |||
| TransactionResponse txResponse = null; | |||
| try { | |||
| TransactionRequest txReq = txReqBuilder.buildRequest(); | |||
| // 发起交易请求; | |||
| TransactionResponse txResponse = txProcessor.process(txReq); | |||
| // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; | |||
| OperationResult[] opResults = txResponse.getOperationResults(); | |||
| if (opResults != null && opResults.length > 0) { | |||
| if (opResults.length != opReturnValueHandlers.length) { | |||
| throw new IllegalStateException(String.format( | |||
| "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", | |||
| txReq.getTransactionContent().getHash(), opResults.length, opReturnValueHandlers.length)); | |||
| } | |||
| for (int i = 0; i < opResults.length; i++) { | |||
| if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { | |||
| throw new IllegalStateException( | |||
| "The operation indexes of the items in the result list and in the handler list don't match!"); | |||
| } | |||
| opReturnValueHandlers[i].setReturnValue(opResults[i].getResult()); | |||
| txResponse = txProcessor.process(txReq); | |||
| stateManager.complete(); | |||
| } catch (Exception ex) { | |||
| stateManager.close(); | |||
| handleError(ex); | |||
| throw new UndeclaredThrowableException(ex); | |||
| } | |||
| if (txResponse != null) { | |||
| handleResults(txResponse); | |||
| } | |||
| return txResponse; | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| if (!stateManager.close()) { | |||
| TransactionCancelledExeption error = new TransactionCancelledExeption( | |||
| "Prepared transaction has been cancelled!"); | |||
| handleError(error); | |||
| } | |||
| } | |||
| private void handleError(Throwable error) { | |||
| for (OperationResultHandle handle : opReturnValueHandlers) { | |||
| handle.complete(error); | |||
| } | |||
| } | |||
| private void handleResults(TransactionResponse txResponse) { | |||
| // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; | |||
| OperationResult[] opResults = txResponse.getOperationResults(); | |||
| if (opResults != null && opResults.length > 0) { | |||
| if (opResults.length != opReturnValueHandlers.length) { | |||
| throw new IllegalStateException(String.format( | |||
| "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", | |||
| txResponse.getContentHash(), opResults.length, opReturnValueHandlers.length)); | |||
| } | |||
| for (int i = 0; i < opResults.length; i++) { | |||
| if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { | |||
| throw new IllegalStateException( | |||
| "The operation indexes of the items in the result list and in the handler list don't match!"); | |||
| } | |||
| opReturnValueHandlers[i].complete(opResults[i].getResult()); | |||
| } | |||
| return txResponse; | |||
| } catch (Exception e) { | |||
| //TODO: 出错时清理交易上下文,释放与交易关联对异步等待资源,避免当前线程死锁; | |||
| } | |||
| } | |||
| @@ -1,43 +1,22 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class ShortValueHolder extends ValueHolderWrapper { | |||
| public class ShortValueHolder extends ValueHolderBase { | |||
| ShortValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| ShortValueHolder(OperationResultHolder resultHolder) { | |||
| super(resultHolder); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 获取值;<br> | |||
| * | |||
| * @return | |||
| */ | |||
| public short get() { | |||
| return (short) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public short get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public short get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (short) super.getValue(timeout, unit); | |||
| public short get() { | |||
| return super.isCompleted() ? (short) super.getValue() : 0; | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| package com.jd.blockchain.transaction; | |||
| public class TransactionCancelledExeption extends RuntimeException { | |||
| private static final long serialVersionUID = -2577951411093171806L; | |||
| public TransactionCancelledExeption(String message) { | |||
| super(message); | |||
| } | |||
| public TransactionCancelledExeption(String message, Throwable cause) { | |||
| super(message, cause); | |||
| } | |||
| } | |||
| @@ -51,7 +51,7 @@ public class TxBuilder implements TransactionBuilder { | |||
| return txContent; | |||
| } | |||
| public Collection<OperationReturnValueHandler> getReturnValuehandlers() { | |||
| public Collection<OperationResultHandle> getReturnValuehandlers() { | |||
| return opFactory.getReturnValuetHandlers(); | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| package com.jd.blockchain.transaction; | |||
| class TxStateManager { | |||
| private State state = State.OPERABLE; | |||
| public void operate() { | |||
| if (state != State.OPERABLE) { | |||
| throw new IllegalStateException(String.format("Cannot define operations in %s state!", state)); | |||
| } | |||
| } | |||
| public void prepare() { | |||
| if (state != State.OPERABLE) { | |||
| throw new IllegalStateException( | |||
| String.format("Cannot switch to %s state in %s state!", State.PREPARED, state)); | |||
| } | |||
| state = State.PREPARED; | |||
| } | |||
| public void commit() { | |||
| if (state != State.PREPARED) { | |||
| throw new IllegalStateException( | |||
| String.format("Cannot switch to %s state in %s state!", State.COMMITTED, state)); | |||
| } | |||
| state = State.COMMITTED; | |||
| } | |||
| public void complete() { | |||
| if (state != State.COMMITTED) { | |||
| throw new IllegalStateException(String.format("Cannot complete normally in %s state!", state)); | |||
| } | |||
| state = State.CLOSED; | |||
| } | |||
| /** | |||
| * 关闭交易; | |||
| * | |||
| * @param error | |||
| * @return 此次操作前是否已经处于关闭状态; <br> | |||
| * 如果返回 true ,则表示之前已经处于关闭状态,此次操作将被忽略;<br> | |||
| * 如果返回 fasle,则表示之前处于非关闭状态,此次操作将切换为关闭状态; | |||
| */ | |||
| public boolean close() { | |||
| if (state == State.CLOSED) { | |||
| return true; | |||
| } | |||
| state = State.CLOSED; | |||
| return false; | |||
| } | |||
| private static enum State { | |||
| /** | |||
| * 可操作; | |||
| */ | |||
| OPERABLE, | |||
| /** | |||
| * 就绪; | |||
| */ | |||
| PREPARED, | |||
| /** | |||
| * 已提交; | |||
| */ | |||
| COMMITTED, | |||
| /** | |||
| * 已关闭; | |||
| */ | |||
| CLOSED | |||
| } | |||
| } | |||
| @@ -1,5 +1,8 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.io.IOException; | |||
| import java.util.Collection; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.PreparedTransaction; | |||
| import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
| @@ -12,8 +15,10 @@ public class TxTemplate implements TransactionTemplate { | |||
| private TransactionService txService; | |||
| private TxStateManager stateManager; | |||
| public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | |||
| this.stateManager = new TxStateManager(); | |||
| this.txBuilder = new TxBuilder(ledgerHash); | |||
| this.txService = txService; | |||
| } | |||
| @@ -25,43 +30,63 @@ public class TxTemplate implements TransactionTemplate { | |||
| @Override | |||
| public PreparedTransaction prepare() { | |||
| stateManager.prepare(); | |||
| TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
| return new PreparedTx(txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
| return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
| } | |||
| @Override | |||
| public UserRegisterOperationBuilder users() { | |||
| stateManager.operate(); | |||
| return txBuilder.users(); | |||
| } | |||
| @Override | |||
| public DataAccountRegisterOperationBuilder dataAccounts() { | |||
| stateManager.operate(); | |||
| return txBuilder.dataAccounts(); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
| stateManager.operate(); | |||
| return txBuilder.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
| stateManager.operate(); | |||
| return txBuilder.dataAccount(accountAddress); | |||
| } | |||
| @Override | |||
| public ContractCodeDeployOperationBuilder contracts() { | |||
| stateManager.operate(); | |||
| return txBuilder.contracts(); | |||
| } | |||
| @Override | |||
| public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
| stateManager.operate(); | |||
| return txBuilder.contract(address, contractIntf); | |||
| } | |||
| @Override | |||
| public <T> T contract(String address, Class<T> contractIntf) { | |||
| stateManager.operate(); | |||
| return txBuilder.contract(address, contractIntf); | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| if (!stateManager.close()) { | |||
| Collection<OperationResultHandle> handlers = txBuilder.getReturnValuehandlers(); | |||
| if (handlers.size() > 0) { | |||
| TransactionCancelledExeption error = new TransactionCancelledExeption("Transaction template has been cancelled!"); | |||
| for (OperationResultHandle handle : handlers) { | |||
| handle.complete(error); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| public class ValueHolder<T> extends ValueHolderBase { | |||
| ValueHolder(ContractInvocation invocation) { | |||
| super(invocation); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * | |||
| * @return | |||
| */ | |||
| @SuppressWarnings("unchecked") | |||
| public T get() { | |||
| return (T) super.getValue(); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * | |||
| * @param timeout | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| public T get(long timeout) throws TimeoutException { | |||
| return get(timeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| @SuppressWarnings("unchecked") | |||
| public T get(long timeout, TimeUnit unit) throws TimeoutException { | |||
| return (T) super.getValue(timeout, unit); | |||
| } | |||
| } | |||
| @@ -1,42 +0,0 @@ | |||
| package com.jd.blockchain.transaction; | |||
| import java.util.concurrent.ExecutionException; | |||
| import java.util.concurrent.TimeUnit; | |||
| import java.util.concurrent.TimeoutException; | |||
| class ValueHolderBase { | |||
| private ContractInvocation invocation; | |||
| protected ValueHolderBase(ContractInvocation invocation) { | |||
| this.invocation = invocation; | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * | |||
| * @return | |||
| */ | |||
| protected Object getValue() { | |||
| try { | |||
| return invocation.getReturnValue().get(); | |||
| } catch (InterruptedException | ExecutionException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| /** | |||
| * 等待结果合约调用的结果返回; | |||
| * | |||
| * @param timeout | |||
| * @param unit | |||
| * @return | |||
| * @throws TimeoutException | |||
| */ | |||
| protected Object getValue(long timeout, TimeUnit unit) throws TimeoutException { | |||
| try { | |||
| return invocation.getReturnValue().get(timeout, unit); | |||
| } catch (InterruptedException | ExecutionException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| package com.jd.blockchain.transaction; | |||
| class ValueHolderWrapper { | |||
| private OperationResultHolder valueHolder; | |||
| protected ValueHolderWrapper(OperationResultHolder valueHolder) { | |||
| this.valueHolder = valueHolder; | |||
| } | |||
| public boolean isCompleted() { | |||
| return valueHolder.isCompleted(); | |||
| } | |||
| public Throwable getError() { | |||
| return valueHolder.getError(); | |||
| } | |||
| /** | |||
| * 获取值;<br> | |||
| * | |||
| * 此方法不堵塞,调用立即返回;<br> | |||
| * | |||
| * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; | |||
| * | |||
| * @return | |||
| */ | |||
| protected Object getValue() { | |||
| return valueHolder.getResult(); | |||
| } | |||
| public void addCompletedListener(OperationCompletedListener listener) { | |||
| valueHolder.addCompletedListener(listener); | |||
| } | |||
| } | |||
| @@ -8,21 +8,22 @@ | |||
| */ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import static org.junit.Assert.assertArrayEquals; | |||
| import static org.junit.Assert.assertEquals; | |||
| import org.junit.Before; | |||
| import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesDataList; | |||
| import com.jd.blockchain.ledger.BytesValueList; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||
| import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import org.junit.Before; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertArrayEquals; | |||
| import static org.junit.Assert.assertEquals; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| @@ -32,34 +33,36 @@ import static org.junit.Assert.assertEquals; | |||
| public class ContractEventSendOpTemplateTest { | |||
| private ContractEventSendOpTemplate data; | |||
| private ContractEventSendOpTemplate data; | |||
| @Before | |||
| public void initContractEventSendOpTemplate() { | |||
| DataContractRegistry.register(ContractEventSendOperation.class); | |||
| DataContractRegistry.register(Operation.class); | |||
| String contractAddress = "zhangsan-address", event = "zhangsan-event"; | |||
| byte[] args = "zhangsan-args".getBytes(); | |||
| data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); | |||
| } | |||
| @Before | |||
| public void initContractEventSendOpTemplate() { | |||
| DataContractRegistry.register(ContractEventSendOperation.class); | |||
| DataContractRegistry.register(Operation.class); | |||
| String contractAddress = "zhangsan-address", event = "zhangsan-event"; | |||
| BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args")); | |||
| data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); | |||
| } | |||
| @Test | |||
| public void testSerialize_ContractEventSendOperation() throws Exception { | |||
| byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); | |||
| ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); | |||
| System.out.println("------Assert start ------"); | |||
| assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); | |||
| assertEquals(resolvedData.getEvent(), data.getEvent()); | |||
| assertArrayEquals(resolvedData.getArgs(), data.getArgs()); | |||
| System.out.println("------Assert OK ------"); | |||
| } | |||
| @Test | |||
| public void testSerialize_ContractEventSendOperation() throws Exception { | |||
| byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); | |||
| ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); | |||
| System.out.println("------Assert start ------"); | |||
| assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); | |||
| assertEquals(resolvedData.getEvent(), data.getEvent()); | |||
| byte[] expectedBytes = BinaryProtocol.encode(resolvedData.getArgs(), BytesValueList.class); | |||
| byte[] actualBytes = BinaryProtocol.encode(data.getArgs(), BytesValueList.class); | |||
| assertArrayEquals(expectedBytes, actualBytes); | |||
| System.out.println("------Assert OK ------"); | |||
| } | |||
| @Test | |||
| public void testSerialize_Operation() throws Exception { | |||
| byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); | |||
| Operation resolvedData = BinaryProtocol.decode(serialBytes); | |||
| System.out.println("------Assert start ------"); | |||
| System.out.println(resolvedData); | |||
| System.out.println("------Assert OK ------"); | |||
| } | |||
| @Test | |||
| public void testSerialize_Operation() throws Exception { | |||
| byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); | |||
| Operation resolvedData = BinaryProtocol.decode(serialBytes); | |||
| System.out.println("------Assert start ------"); | |||
| System.out.println(resolvedData); | |||
| System.out.println("------Assert OK ------"); | |||
| } | |||
| } | |||
| @@ -16,7 +16,7 @@ import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
| @@ -42,11 +42,11 @@ public class DataAccountKVSetOpTemplateTest { | |||
| String accountAddress = "zhangsandhakhdkah"; | |||
| data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); | |||
| KVData kvData1 = | |||
| new KVData("test1", BytesValueEntry.fromText("zhangsan"), 9999L); | |||
| new KVData("test1", BytesData.fromText("zhangsan"), 9999L); | |||
| KVData kvData2 = | |||
| new KVData("test2", BytesValueEntry.fromText("lisi"), 9990L); | |||
| new KVData("test2", BytesData.fromText("lisi"), 9990L); | |||
| KVData kvData3 = | |||
| new KVData("test3", BytesValueEntry.fromText("wangwu"), 1990L); | |||
| new KVData("test3", BytesData.fromText("wangwu"), 1990L); | |||
| data.set(kvData1); | |||
| data.set(kvData2); | |||
| data.set(kvData3); | |||
| @@ -16,7 +16,7 @@ import org.junit.Test; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.ledger.BytesValueEntry; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||
| import com.jd.blockchain.transaction.KVData; | |||
| @@ -38,7 +38,7 @@ public class KVDataTest { | |||
| byte[] value = "test-value".getBytes(); | |||
| long expectedVersion = 9999L; | |||
| kvData = new KVData(key, BytesValueEntry.fromBytes(value), expectedVersion); | |||
| kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); | |||
| } | |||
| @Test | |||
| @@ -31,346 +31,348 @@ import java.lang.reflect.Field; | |||
| public class ClientResolveUtil { | |||
| public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||
| if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
| return kvDataEntries; | |||
| } | |||
| KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||
| // kvDataEntries是代理对象,需要处理 | |||
| for (int i = 0; i < kvDataEntries.length; i++) { | |||
| KVDataEntry kvDataEntry = kvDataEntries[i]; | |||
| String key = kvDataEntry.getKey(); | |||
| long version = kvDataEntry.getVersion(); | |||
| DataType dataType = kvDataEntry.getType(); | |||
| KvData innerKvData = new KvData(key, version, dataType); | |||
| Object valueObj = kvDataEntry.getValue(); | |||
| switch (dataType) { | |||
| case NIL: | |||
| break; | |||
| case BYTES: | |||
| case TEXT: | |||
| case JSON: | |||
| innerKvData.setValue(valueObj.toString()); | |||
| break; | |||
| case INT32: | |||
| innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||
| break; | |||
| case INT64: | |||
| innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||
| break; | |||
| default: | |||
| throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||
| } | |||
| resolveKvDataEntries[i] = innerKvData; | |||
| } | |||
| return resolveKvDataEntries; | |||
| } | |||
| public static Operation read(Operation operation) { | |||
| try { | |||
| // Class | |||
| Class<?> clazz = operation.getClass(); | |||
| Field field = clazz.getSuperclass().getDeclaredField("h"); | |||
| field.setAccessible(true); | |||
| Object object = field.get(operation); | |||
| if (object instanceof JSONObject) { | |||
| JSONObject jsonObject = (JSONObject) object; | |||
| if (jsonObject.containsKey("accountID")) { | |||
| return convertDataAccountRegisterOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("userID")) { | |||
| return convertUserRegisterOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("contractID")) { | |||
| return convertContractCodeDeployOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("writeSet")) { | |||
| return convertDataAccountKVSetOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("initSetting")) { | |||
| return convertLedgerInitOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("contractAddress")) { | |||
| return convertContractEventSendOperation(jsonObject); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return null; | |||
| } | |||
| public static Object readValueByBytesValue(BytesValue bytesValue) { | |||
| DataType dataType = bytesValue.getType(); | |||
| Bytes saveVal = bytesValue.getValue(); | |||
| Object showVal; | |||
| switch (dataType) { | |||
| case BYTES: | |||
| // return hex | |||
| showVal = HexUtils.encode(saveVal.toBytes()); | |||
| break; | |||
| case TEXT: | |||
| case JSON: | |||
| showVal = saveVal.toUTF8String(); | |||
| break; | |||
| case INT64: | |||
| showVal = BytesUtils.toLong(saveVal.toBytes()); | |||
| break; | |||
| default: | |||
| showVal = HexUtils.encode(saveVal.toBytes()); | |||
| break; | |||
| } | |||
| return showVal; | |||
| } | |||
| public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { | |||
| JSONObject account = jsonObject.getJSONObject("accountID"); | |||
| return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); | |||
| } | |||
| public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { | |||
| // 写入集合处理 | |||
| JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); | |||
| JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); | |||
| String addressBase58 = accountAddrObj.getString("value"); | |||
| Bytes address = Bytes.fromBase58(addressBase58); | |||
| DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); | |||
| for (int i = 0; i <writeSetObj.size(); i++) { | |||
| JSONObject currWriteSetObj = writeSetObj.getJSONObject(i); | |||
| long expectedVersion = currWriteSetObj.getLong("expectedVersion"); | |||
| JSONObject valueObj = currWriteSetObj.getJSONObject("value"); | |||
| String typeStr = valueObj.getString("type"); | |||
| String realValBase58 = valueObj.getString("value"); | |||
| String key = currWriteSetObj.getString("key"); | |||
| DataType dataType = DataType.valueOf(typeStr); | |||
| BytesValue bytesValue =BytesValueEntry.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
| KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||
| kvOperation.set(kvData); | |||
| } | |||
| return kvOperation; | |||
| } | |||
| public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) { | |||
| JSONObject legerInitObj = jsonObject.getJSONObject("initSetting"); | |||
| LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
| String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); | |||
| // 种子需要做Base64转换 | |||
| ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); | |||
| String consensusProvider = legerInitObj.getString("consensusProvider"); | |||
| ledgerInitSettingData.setConsensusProvider(consensusProvider); | |||
| JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting"); | |||
| boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash"); | |||
| short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm"); | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setAutoVerifyHash(autoVerifyHash); | |||
| cryptoConfig.setHashAlgorithm(hashAlgorithm); | |||
| ledgerInitSettingData.setCryptoSetting(cryptoConfig); | |||
| JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings"); | |||
| Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value")); | |||
| ledgerInitSettingData.setConsensusSettings(consensusSettings); | |||
| JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants"); | |||
| if (!consensusParticipantsArray.isEmpty()) { | |||
| ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()]; | |||
| for (int i = 0; i < consensusParticipantsArray.size(); i++) { | |||
| JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i); | |||
| String addressBase58 = currConsensusParticipant.getString("address"); | |||
| String name = currConsensusParticipant.getString("name"); | |||
| int id = currConsensusParticipant.getInteger("id"); | |||
| JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||
| String pubKeyBase58 = pubKeyObj.getString("value"); | |||
| // 生成ParticipantNode对象 | |||
| ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||
| participantNodes[i] = participantCertData; | |||
| } | |||
| ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||
| } | |||
| return new LedgerInitOpTemplate(ledgerInitSettingData); | |||
| } | |||
| public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) { | |||
| JSONObject user = jsonObject.getJSONObject("userID"); | |||
| return new UserRegisterOpTemplate(blockchainIdentity(user)); | |||
| } | |||
| public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) { | |||
| JSONObject contract = jsonObject.getJSONObject("contractID"); | |||
| BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); | |||
| String chainCodeStr = jsonObject.getString("chainCode"); | |||
| ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, BytesUtils.toBytes(chainCodeStr)); | |||
| return contractCodeDeployOpTemplate; | |||
| } | |||
| public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) { | |||
| JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress"); | |||
| String contractAddress = contractAddressObj.getString("value"); | |||
| String argsStr = jsonObject.getString("args"); | |||
| String event = jsonObject.getString("event"); | |||
| return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr)); | |||
| } | |||
| private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { | |||
| JSONObject addressObj = jsonObject.getJSONObject("address"); | |||
| // base58值 | |||
| String addressBase58 = addressObj.getString("value"); | |||
| Bytes address = Bytes.fromBase58(addressBase58); | |||
| JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey"); | |||
| // base58值 | |||
| String pubKeyBase58 = pubKeyObj.getString("value"); | |||
| PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()); | |||
| // 生成对应的对象 | |||
| return new BlockchainIdentityData(address, pubKey); | |||
| } | |||
| public static class CryptoConfig implements CryptoSetting { | |||
| private short hashAlgorithm; | |||
| private boolean autoVerifyHash; | |||
| @Override | |||
| public CryptoProvider[] getSupportedProviders() { | |||
| return new CryptoProvider[0]; | |||
| } | |||
| @Override | |||
| public short getHashAlgorithm() { | |||
| return hashAlgorithm; | |||
| } | |||
| @Override | |||
| public boolean getAutoVerifyHash() { | |||
| return autoVerifyHash; | |||
| } | |||
| public void setHashAlgorithm(short hashAlgorithm) { | |||
| this.hashAlgorithm = hashAlgorithm; | |||
| } | |||
| public void setAutoVerifyHash(boolean autoVerifyHash) { | |||
| this.autoVerifyHash = autoVerifyHash; | |||
| } | |||
| } | |||
| public static class ParticipantCertData implements ParticipantNode{ | |||
| private int id; | |||
| private String address; | |||
| private String name; | |||
| private PubKey pubKey; | |||
| public ParticipantCertData() { | |||
| } | |||
| public ParticipantCertData(ParticipantNode participantNode) { | |||
| this.address = participantNode.getAddress(); | |||
| this.name = participantNode.getName(); | |||
| this.pubKey = participantNode.getPubKey(); | |||
| } | |||
| public ParticipantCertData(int id, String address, String name, PubKey pubKey) { | |||
| this.id = id; | |||
| this.address = address; | |||
| this.name = name; | |||
| this.pubKey = pubKey; | |||
| } | |||
| @Override | |||
| public String getAddress() { | |||
| return address; | |||
| } | |||
| @Override | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public int getId() { | |||
| return id; | |||
| } | |||
| public void setId(int id) { | |||
| this.id = id; | |||
| } | |||
| } | |||
| public static class KvData implements KVDataEntry { | |||
| private String key; | |||
| private long version; | |||
| private DataType dataType; | |||
| private Object value; | |||
| public KvData() { | |||
| } | |||
| public KvData(String key, long version, DataType dataType) { | |||
| this(key, version, dataType, null); | |||
| } | |||
| public KvData(String key, long version, DataType dataType, Object value) { | |||
| this.key = key; | |||
| this.version = version; | |||
| this.dataType = dataType; | |||
| this.value = value; | |||
| } | |||
| public void setKey(String key) { | |||
| this.key = key; | |||
| } | |||
| public void setVersion(long version) { | |||
| this.version = version; | |||
| } | |||
| public void setDataType(DataType dataType) { | |||
| this.dataType = dataType; | |||
| } | |||
| public void setValue(Object value) { | |||
| this.value = value; | |||
| } | |||
| @Override | |||
| public String getKey() { | |||
| return key; | |||
| } | |||
| @Override | |||
| public long getVersion() { | |||
| return version; | |||
| } | |||
| @Override | |||
| public DataType getType() { | |||
| return dataType; | |||
| } | |||
| @Override | |||
| public Object getValue() { | |||
| return value; | |||
| } | |||
| } | |||
| public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||
| if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
| return kvDataEntries; | |||
| } | |||
| KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||
| // kvDataEntries是代理对象,需要处理 | |||
| for (int i = 0; i < kvDataEntries.length; i++) { | |||
| KVDataEntry kvDataEntry = kvDataEntries[i]; | |||
| String key = kvDataEntry.getKey(); | |||
| long version = kvDataEntry.getVersion(); | |||
| DataType dataType = kvDataEntry.getType(); | |||
| KvData innerKvData = new KvData(key, version, dataType); | |||
| Object valueObj = kvDataEntry.getValue(); | |||
| switch (dataType) { | |||
| case NIL: | |||
| break; | |||
| case BYTES: | |||
| case TEXT: | |||
| case JSON: | |||
| innerKvData.setValue(valueObj.toString()); | |||
| break; | |||
| case INT32: | |||
| innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||
| break; | |||
| case INT64: | |||
| innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||
| break; | |||
| default: | |||
| throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||
| } | |||
| resolveKvDataEntries[i] = innerKvData; | |||
| } | |||
| return resolveKvDataEntries; | |||
| } | |||
| public static Operation read(Operation operation) { | |||
| try { | |||
| // Class | |||
| Class<?> clazz = operation.getClass(); | |||
| Field field = clazz.getSuperclass().getDeclaredField("h"); | |||
| field.setAccessible(true); | |||
| Object object = field.get(operation); | |||
| if (object instanceof JSONObject) { | |||
| JSONObject jsonObject = (JSONObject) object; | |||
| if (jsonObject.containsKey("accountID")) { | |||
| return convertDataAccountRegisterOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("userID")) { | |||
| return convertUserRegisterOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("contractID")) { | |||
| return convertContractCodeDeployOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("writeSet")) { | |||
| return convertDataAccountKVSetOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("initSetting")) { | |||
| return convertLedgerInitOperation(jsonObject); | |||
| } else if (jsonObject.containsKey("contractAddress")) { | |||
| return convertContractEventSendOperation(jsonObject); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return null; | |||
| } | |||
| public static Object readValueByBytesValue(BytesValue bytesValue) { | |||
| DataType dataType = bytesValue.getType(); | |||
| Bytes saveVal = bytesValue.getValue(); | |||
| Object showVal; | |||
| switch (dataType) { | |||
| case BYTES: | |||
| // return hex | |||
| showVal = HexUtils.encode(saveVal.toBytes()); | |||
| break; | |||
| case TEXT: | |||
| case JSON: | |||
| showVal = saveVal.toUTF8String(); | |||
| break; | |||
| case INT64: | |||
| showVal = BytesUtils.toLong(saveVal.toBytes()); | |||
| break; | |||
| default: | |||
| showVal = HexUtils.encode(saveVal.toBytes()); | |||
| break; | |||
| } | |||
| return showVal; | |||
| } | |||
| public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { | |||
| JSONObject account = jsonObject.getJSONObject("accountID"); | |||
| return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); | |||
| } | |||
| public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { | |||
| // 写入集合处理 | |||
| JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); | |||
| JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); | |||
| String addressBase58 = accountAddrObj.getString("value"); | |||
| Bytes address = Bytes.fromBase58(addressBase58); | |||
| DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); | |||
| for (int i = 0; i < writeSetObj.size(); i++) { | |||
| JSONObject currWriteSetObj = writeSetObj.getJSONObject(i); | |||
| long expectedVersion = currWriteSetObj.getLong("expectedVersion"); | |||
| JSONObject valueObj = currWriteSetObj.getJSONObject("value"); | |||
| String typeStr = valueObj.getString("type"); | |||
| String realValBase58 = valueObj.getString("value"); | |||
| String key = currWriteSetObj.getString("key"); | |||
| DataType dataType = DataType.valueOf(typeStr); | |||
| BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58)); | |||
| KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||
| kvOperation.set(kvData); | |||
| } | |||
| return kvOperation; | |||
| } | |||
| public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) { | |||
| JSONObject legerInitObj = jsonObject.getJSONObject("initSetting"); | |||
| LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||
| String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); | |||
| // 种子需要做Base64转换 | |||
| ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); | |||
| String consensusProvider = legerInitObj.getString("consensusProvider"); | |||
| ledgerInitSettingData.setConsensusProvider(consensusProvider); | |||
| JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting"); | |||
| boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash"); | |||
| short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm"); | |||
| CryptoConfig cryptoConfig = new CryptoConfig(); | |||
| cryptoConfig.setAutoVerifyHash(autoVerifyHash); | |||
| cryptoConfig.setHashAlgorithm(hashAlgorithm); | |||
| ledgerInitSettingData.setCryptoSetting(cryptoConfig); | |||
| JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings"); | |||
| Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value")); | |||
| ledgerInitSettingData.setConsensusSettings(consensusSettings); | |||
| JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants"); | |||
| if (!consensusParticipantsArray.isEmpty()) { | |||
| ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()]; | |||
| for (int i = 0; i < consensusParticipantsArray.size(); i++) { | |||
| JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i); | |||
| String addressBase58 = currConsensusParticipant.getString("address"); | |||
| String name = currConsensusParticipant.getString("name"); | |||
| int id = currConsensusParticipant.getInteger("id"); | |||
| JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||
| String pubKeyBase58 = pubKeyObj.getString("value"); | |||
| // 生成ParticipantNode对象 | |||
| ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, | |||
| new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||
| participantNodes[i] = participantCertData; | |||
| } | |||
| ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||
| } | |||
| return new LedgerInitOpTemplate(ledgerInitSettingData); | |||
| } | |||
| public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) { | |||
| JSONObject user = jsonObject.getJSONObject("userID"); | |||
| return new UserRegisterOpTemplate(blockchainIdentity(user)); | |||
| } | |||
| public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) { | |||
| JSONObject contract = jsonObject.getJSONObject("contractID"); | |||
| BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); | |||
| String chainCodeStr = jsonObject.getString("chainCode"); | |||
| ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, | |||
| BytesUtils.toBytes(chainCodeStr)); | |||
| return contractCodeDeployOpTemplate; | |||
| } | |||
| public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) { | |||
| JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress"); | |||
| String contractAddress = contractAddressObj.getString("value"); | |||
| String argsStr = jsonObject.getString("args"); | |||
| String event = jsonObject.getString("event"); | |||
| return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, | |||
| BytesDataList.singleText(argsStr)); | |||
| } | |||
| private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { | |||
| JSONObject addressObj = jsonObject.getJSONObject("address"); | |||
| // base58值 | |||
| String addressBase58 = addressObj.getString("value"); | |||
| Bytes address = Bytes.fromBase58(addressBase58); | |||
| JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey"); | |||
| // base58值 | |||
| String pubKeyBase58 = pubKeyObj.getString("value"); | |||
| PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()); | |||
| // 生成对应的对象 | |||
| return new BlockchainIdentityData(address, pubKey); | |||
| } | |||
| public static class CryptoConfig implements CryptoSetting { | |||
| private short hashAlgorithm; | |||
| private boolean autoVerifyHash; | |||
| @Override | |||
| public CryptoProvider[] getSupportedProviders() { | |||
| return new CryptoProvider[0]; | |||
| } | |||
| @Override | |||
| public short getHashAlgorithm() { | |||
| return hashAlgorithm; | |||
| } | |||
| @Override | |||
| public boolean getAutoVerifyHash() { | |||
| return autoVerifyHash; | |||
| } | |||
| public void setHashAlgorithm(short hashAlgorithm) { | |||
| this.hashAlgorithm = hashAlgorithm; | |||
| } | |||
| public void setAutoVerifyHash(boolean autoVerifyHash) { | |||
| this.autoVerifyHash = autoVerifyHash; | |||
| } | |||
| } | |||
| public static class ParticipantCertData implements ParticipantNode { | |||
| private int id; | |||
| private String address; | |||
| private String name; | |||
| private PubKey pubKey; | |||
| public ParticipantCertData() { | |||
| } | |||
| public ParticipantCertData(ParticipantNode participantNode) { | |||
| this.address = participantNode.getAddress(); | |||
| this.name = participantNode.getName(); | |||
| this.pubKey = participantNode.getPubKey(); | |||
| } | |||
| public ParticipantCertData(int id, String address, String name, PubKey pubKey) { | |||
| this.id = id; | |||
| this.address = address; | |||
| this.name = name; | |||
| this.pubKey = pubKey; | |||
| } | |||
| @Override | |||
| public String getAddress() { | |||
| return address; | |||
| } | |||
| @Override | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public int getId() { | |||
| return id; | |||
| } | |||
| public void setId(int id) { | |||
| this.id = id; | |||
| } | |||
| } | |||
| public static class KvData implements KVDataEntry { | |||
| private String key; | |||
| private long version; | |||
| private DataType dataType; | |||
| private Object value; | |||
| public KvData() { | |||
| } | |||
| public KvData(String key, long version, DataType dataType) { | |||
| this(key, version, dataType, null); | |||
| } | |||
| public KvData(String key, long version, DataType dataType, Object value) { | |||
| this.key = key; | |||
| this.version = version; | |||
| this.dataType = dataType; | |||
| this.value = value; | |||
| } | |||
| public void setKey(String key) { | |||
| this.key = key; | |||
| } | |||
| public void setVersion(long version) { | |||
| this.version = version; | |||
| } | |||
| public void setDataType(DataType dataType) { | |||
| this.dataType = dataType; | |||
| } | |||
| public void setValue(Object value) { | |||
| this.value = value; | |||
| } | |||
| @Override | |||
| public String getKey() { | |||
| return key; | |||
| } | |||
| @Override | |||
| public long getVersion() { | |||
| return version; | |||
| } | |||
| @Override | |||
| public DataType getType() { | |||
| return dataType; | |||
| } | |||
| @Override | |||
| public Object getValue() { | |||
| return value; | |||
| } | |||
| } | |||
| } | |||
| @@ -11,7 +11,7 @@ import com.jd.blockchain.ledger.PreparedTransaction; | |||
| import com.jd.blockchain.ledger.TransactionResponse; | |||
| import com.jd.blockchain.ledger.TransactionTemplate; | |||
| import com.jd.blockchain.transaction.LongValueHolder; | |||
| import com.jd.blockchain.transaction.ValueHolder; | |||
| import com.jd.blockchain.transaction.GenericValueHolder; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
| @@ -92,7 +92,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
| GenericValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } | |||
| @@ -122,7 +122,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
| GenericValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } | |||
| @@ -142,7 +142,7 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { | |||
| if (useContract) { | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
| GenericValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } else { | |||
| @@ -20,7 +20,7 @@ import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
| import com.jd.blockchain.sdk.samples.SDKDemo_Constant; | |||
| import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
| import com.jd.blockchain.transaction.LongValueHolder; | |||
| import com.jd.blockchain.transaction.ValueHolder; | |||
| import com.jd.blockchain.transaction.GenericValueHolder; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class SDKDemo_Contract_Test { | |||
| @@ -108,7 +108,7 @@ public class SDKDemo_Contract_Test { | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
| GenericValueHolder<String> result = decode(transferContract.readAll(address, account)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } | |||
| @@ -126,7 +126,7 @@ public class SDKDemo_Contract_Test { | |||
| TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
| GenericValueHolder<String> result = decode(transferContract.transfer(address, from, to, money)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } | |||
| @@ -146,7 +146,7 @@ public class SDKDemo_Contract_Test { | |||
| if (useContract) { | |||
| // 使用合约创建 | |||
| TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||
| ValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
| GenericValueHolder<String> result = decode(transferContract.create(address, account, money)); | |||
| commit(txTpl); | |||
| return result.get(); | |||
| } else { | |||
| @@ -24,6 +24,7 @@ import com.jd.blockchain.crypto.PrivKey; | |||
| import com.jd.blockchain.ledger.BlockchainIdentity; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.ledger.BytesDataList; | |||
| import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
| import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
| import com.jd.blockchain.ledger.LedgerBlock; | |||
| @@ -143,8 +144,9 @@ public class LedgerPerformanceTest { | |||
| batchCount = Integer.parseInt(args[1]); | |||
| } | |||
| } | |||
| if (contract){ | |||
| testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, silent); | |||
| if (contract) { | |||
| testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, | |||
| silent); | |||
| } | |||
| if (usertest) { | |||
| @@ -177,8 +179,9 @@ public class LedgerPerformanceTest { | |||
| * @param batchCount | |||
| * @param silent | |||
| */ | |||
| private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, | |||
| DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
| private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, | |||
| LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, | |||
| boolean silent) { | |||
| LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); | |||
| ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [注册用户] ================="); | |||
| @@ -273,7 +276,7 @@ public class LedgerPerformanceTest { | |||
| * @param silent | |||
| */ | |||
| private static void testContract(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, | |||
| DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
| DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { | |||
| LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); | |||
| ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [执行合约] ================="); | |||
| @@ -285,8 +288,8 @@ public class LedgerPerformanceTest { | |||
| // 准备请求 | |||
| int totalCount = batchSize * batchCount; | |||
| List<TransactionRequest> contractTxList = prepareContractRequests(ledgerHash, | |||
| adminKey, totalCount, false, txProc); | |||
| List<TransactionRequest> contractTxList = prepareContractRequests(ledgerHash, adminKey, totalCount, false, | |||
| txProc); | |||
| Prompter consolePrompter = new PresetAnswerPrompter("N"); | |||
| @@ -303,6 +306,7 @@ public class LedgerPerformanceTest { | |||
| } | |||
| } | |||
| private static void execPerformanceTest(int batchCount, int batchSize, List<TransactionRequest> txList, | |||
| LedgerRepository ledger, LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, | |||
| boolean statistic) { | |||
| @@ -407,8 +411,7 @@ public class LedgerPerformanceTest { | |||
| // BlockchainKeyPair dataAccountKey = | |||
| // BlockchainKeyGenerator.getInstance().generate(); | |||
| BlockchainIdentity targetAccount = dataAccounts[count % dataAccounts.length]; | |||
| txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, | |||
| "value-" + i, -1L); | |||
| txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, "value-" + i, -1L); | |||
| TransactionRequestBuilder reqBuilder = txbuilder.prepareRequest(); | |||
| reqBuilder.signAsEndpoint(adminKey); | |||
| txList.add(reqBuilder.buildRequest()); | |||
| @@ -426,8 +429,9 @@ public class LedgerPerformanceTest { | |||
| public static ConsensusProvider getConsensusProvider(String provider) { | |||
| return ConsensusProviders.getProvider(provider); | |||
| } | |||
| public static List<TransactionRequest> prepareContractRequests(HashDigest ledgerHash, | |||
| AsymmetricKeypair adminKey, int count, boolean statistic, TransactionBatchProcessor txProc) { | |||
| public static List<TransactionRequest> prepareContractRequests(HashDigest ledgerHash, AsymmetricKeypair adminKey, | |||
| int count, boolean statistic, TransactionBatchProcessor txProc) { | |||
| // deploy contract | |||
| byte[] chainCode; | |||
| @@ -436,7 +440,7 @@ public class LedgerPerformanceTest { | |||
| InputStream input = LedgerPerformanceTest.class.getClassLoader().getResourceAsStream("example1.jar"); | |||
| chainCode = new byte[input.available()]; | |||
| input.read(chainCode); | |||
| }catch (IOException e){ | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| return null; | |||
| } | |||
| @@ -457,10 +461,10 @@ public class LedgerPerformanceTest { | |||
| System.out.println(resp.isSuccess()); | |||
| TransactionBatchResultHandle handle = txProc.prepare(); | |||
| handle.commit(); | |||
| try{ | |||
| try { | |||
| Thread.sleep(1000); | |||
| } catch (Exception e){ | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| @@ -468,8 +472,9 @@ public class LedgerPerformanceTest { | |||
| List<TransactionRequest> txList = new ArrayList<>(); | |||
| for (int i = 0; i < count; i++) { | |||
| txbuilder = new TxBuilder(ledgerHash); | |||
| String args = dataIdentity.getAddress().toString() + "##"+Integer.toString(i)+ "##"+Integer.toString(i); | |||
| txbuilder.contractEvents().send(contractIdentity.getAddress(), "hello", args.getBytes()); | |||
| String args = dataIdentity.getAddress().toString() + "##" + Integer.toString(i) + "##" | |||
| + Integer.toString(i); | |||
| txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", BytesDataList.singleText("hello")); | |||
| // txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", args.getBytes()); | |||
| reqBuilder = txbuilder.prepareRequest(); | |||
| reqBuilder.signAsEndpoint(adminKey); | |||
| @@ -485,7 +490,8 @@ public class LedgerPerformanceTest { | |||
| return txList; | |||
| } | |||
| public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, String config) { | |||
| public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, | |||
| String config) { | |||
| Map<NetworkAddress, LedgerInitConsensusService> serviceRegisterMap = new ConcurrentHashMap<>(); | |||
| Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); | |||
| @@ -29,7 +29,6 @@ import org.apache.commons.io.FileUtils; | |||
| import org.springframework.core.io.ClassPathResource; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.contract.ContractSerializeUtils; | |||
| import com.jd.blockchain.contract.ReadContract; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| @@ -51,7 +50,7 @@ import com.jd.blockchain.sdk.BlockchainService; | |||
| import com.jd.blockchain.storage.service.DbConnection; | |||
| import com.jd.blockchain.storage.service.DbConnectionFactory; | |||
| import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
| import com.jd.blockchain.transaction.ValueHolder; | |||
| import com.jd.blockchain.transaction.GenericValueHolder; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.concurrent.ThreadInvoker; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| @@ -586,7 +585,7 @@ public class IntegrationBase { | |||
| ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
| ValueHolder<String> result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); | |||
| GenericValueHolder<String> result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); | |||
| ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
| @@ -594,7 +593,7 @@ public class IntegrationBase { | |||
| ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
| ValueHolder<Long> result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); | |||
| GenericValueHolder<Long> result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); | |||
| // 签名; | |||
| PreparedTransaction contractPtx = txContract.prepare(); | |||
| @@ -610,10 +609,10 @@ public class IntegrationBase { | |||
| System.out.printf("readContract3.result = %s \r\n", result3.get()); | |||
| // 打印结果 | |||
| for (OperationResult or : operationResults) { | |||
| System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); | |||
| } | |||
| // // 打印结果 | |||
| // for (OperationResult or : operationResults) { | |||
| // System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); | |||
| // } | |||
| // | |||
| // // 验证结果 | |||
| // assertNotNull(contractReturn); | |||
| @@ -6,7 +6,6 @@ import java.util.concurrent.ConcurrentHashMap; | |||
| import com.jd.blockchain.contract.ContractEventContext; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.contract.ContractSerializeUtils; | |||
| import com.jd.blockchain.contract.EventProcessingAware; | |||
| import com.jd.blockchain.contract.LedgerContext; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| @@ -75,7 +74,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||
| } | |||
| // No return value; | |||
| return ContractSerializeUtils.serialize(result); | |||
| return null; | |||
| } | |||
| @Override | |||
| @@ -1,88 +1,88 @@ | |||
| package com.jd.blockchain.mocker.proxy; | |||
| import java.lang.annotation.Annotation; | |||
| import java.lang.reflect.InvocationHandler; | |||
| import java.lang.reflect.Method; | |||
| import com.jd.blockchain.contract.Contract; | |||
| import com.jd.blockchain.contract.ContractEvent; | |||
| import com.jd.blockchain.contract.ContractSerializeUtils; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.BlockchainIdentity; | |||
| import com.jd.blockchain.ledger.BytesValueEncoding; | |||
| import com.jd.blockchain.ledger.OperationResult; | |||
| import com.jd.blockchain.ledger.OperationResultData; | |||
| import com.jd.blockchain.ledger.TransactionRequest; | |||
| import com.jd.blockchain.mocker.MockerNodeContext; | |||
| import com.jd.blockchain.mocker.handler.MockerContractExeHandle; | |||
| import com.jd.blockchain.transaction.TxBuilder; | |||
| import java.lang.annotation.Annotation; | |||
| import java.lang.reflect.InvocationHandler; | |||
| import java.lang.reflect.Method; | |||
| public class ContractProxy<T> implements InvocationHandler { | |||
| private BlockchainIdentity identity; | |||
| private BlockchainIdentity identity; | |||
| private MockerNodeContext mockerNodeContext; | |||
| private MockerNodeContext mockerNodeContext; | |||
| private T instance; | |||
| private T instance; | |||
| private MockerContractExeHandle operationHandle; | |||
| private MockerContractExeHandle operationHandle; | |||
| public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, | |||
| T instance, MockerContractExeHandle operationHandle) { | |||
| this.identity = identity; | |||
| this.mockerNodeContext = mockerNodeContext; | |||
| this.instance = instance; | |||
| this.operationHandle = operationHandle; | |||
| } | |||
| public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, T instance, | |||
| MockerContractExeHandle operationHandle) { | |||
| this.identity = identity; | |||
| this.mockerNodeContext = mockerNodeContext; | |||
| this.instance = instance; | |||
| this.operationHandle = operationHandle; | |||
| } | |||
| @Override | |||
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||
| // 实际执行时,首先判断执行的是否是添加注解的方法 | |||
| if (!isExecuteContractMethod(method)) { | |||
| return method.invoke(instance, args); | |||
| } | |||
| @Override | |||
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |||
| // 实际执行时,首先判断执行的是否是添加注解的方法 | |||
| if (!isExecuteContractMethod(method)) { | |||
| return method.invoke(instance, args); | |||
| } | |||
| // 首先发送一次执行的请求 | |||
| TxBuilder txBuilder = mockerNodeContext.txBuilder(); | |||
| // 首先发送一次执行的请求 | |||
| TxBuilder txBuilder = mockerNodeContext.txBuilder(); | |||
| Class<?> contractInft = null; | |||
| Class<?> contractInft = null; | |||
| Class<?>[] instanceInfts = instance.getClass().getInterfaces(); | |||
| Class<?>[] instanceInfts = instance.getClass().getInterfaces(); | |||
| for (Class<?> instanceInft : instanceInfts) { | |||
| if (instanceInft.isAnnotationPresent(Contract.class)) { | |||
| contractInft = instanceInft; | |||
| break; | |||
| } | |||
| } | |||
| for (Class<?> instanceInft : instanceInfts) { | |||
| if (instanceInft.isAnnotationPresent(Contract.class)) { | |||
| contractInft = instanceInft; | |||
| break; | |||
| } | |||
| } | |||
| if (contractInft == null) { | |||
| throw new IllegalStateException("This object does not implement the interface for the @Contract annotation !!!"); | |||
| } | |||
| if (contractInft == null) { | |||
| throw new IllegalStateException( | |||
| "This object does not implement the interface for the @Contract annotation !!!"); | |||
| } | |||
| // 生成代理类 | |||
| Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); | |||
| // 代理方式执行一次 | |||
| method.invoke(proxyInstance, args); | |||
| // 生成代理类 | |||
| Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); | |||
| // 代理方式执行一次 | |||
| method.invoke(proxyInstance, args); | |||
| TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); | |||
| TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); | |||
| // 放入到Map中 | |||
| HashDigest txHash = txRequest.getTransactionContent().getHash(); | |||
| operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); | |||
| // 放入到Map中 | |||
| HashDigest txHash = txRequest.getTransactionContent().getHash(); | |||
| operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); | |||
| // 提交该请求至整个区块链系统 | |||
| OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); | |||
| if (operationResults == null || operationResults.length == 0) { | |||
| return null; | |||
| } | |||
| OperationResult opResult = operationResults[0]; | |||
| // 提交该请求至整个区块链系统 | |||
| OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); | |||
| if (operationResults == null || operationResults.length == 0) { | |||
| return null; | |||
| } | |||
| OperationResult opResult = operationResults[0]; | |||
| // 处理返回值 | |||
| return ContractSerializeUtils.resolve(opResult.getResult()); | |||
| } | |||
| // 处理返回值 | |||
| return BytesValueEncoding.encode(opResult.getResult(), method.getReturnType()); | |||
| } | |||
| private boolean isExecuteContractMethod(Method method) { | |||
| Annotation annotation = method.getAnnotation(ContractEvent.class); | |||
| return annotation != null; | |||
| } | |||
| private boolean isExecuteContractMethod(Method method) { | |||
| Annotation annotation = method.getAnnotation(ContractEvent.class); | |||
| return annotation != null; | |||
| } | |||
| } | |||
| @@ -5,8 +5,6 @@ import java.lang.reflect.Method; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import com.jd.blockchain.utils.console.CommandConsole; | |||
| public class DefaultExceptionHandle<TListener> implements ExceptionHandle<TListener> { | |||
| @Override | |||
| @@ -21,9 +19,8 @@ public class DefaultExceptionHandle<TListener> implements ExceptionHandle<TListe | |||
| } | |||
| argsValue = String.format(argsFormat.toString(), args); | |||
| } | |||
| String message = String.format("Error occurred on firing event!--[listener.class=%s][method=%s][args=%s]--[%s]%s", | |||
| String message = String.format("Error occurred while firing event!--[listener.class=%s][method=%s][args=%s]--[%s]%s", | |||
| listener.getClass().getName(), method.getName(), argsValue, ex.getClass().getName(), ex.getMessage()); | |||
| // System.err.println(message); | |||
| logger.error(message, ex); | |||
| } | |||
| private Logger logger = LoggerFactory.getLogger(DefaultExceptionHandle.class); | |||
| @@ -3,11 +3,12 @@ package com.jd.blockchain.utils.event; | |||
| import java.lang.reflect.InvocationHandler; | |||
| import java.lang.reflect.Method; | |||
| import java.lang.reflect.Proxy; | |||
| import java.util.LinkedList; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import java.util.concurrent.CopyOnWriteArrayList; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.util.ReflectionUtils; | |||
| import com.jd.blockchain.utils.Disposable; | |||
| @@ -36,17 +37,22 @@ public class EventMulticaster<TListener> implements Disposable { | |||
| } | |||
| public EventMulticaster(Class<TListener> listenerClass, Logger errorLogger) { | |||
| this(listenerClass, new ExceptionLoggingHandle<TListener>(errorLogger)); | |||
| this(listenerClass, new RethrowExceptionHandler<TListener>(errorLogger)); | |||
| } | |||
| @SuppressWarnings("unchecked") | |||
| public EventMulticaster(Class<TListener> listenerClass, ExceptionHandle<TListener> exHandle) { | |||
| if (!listenerClass.isInterface()) { | |||
| throw new IllegalArgumentException("The specified class of listener does not represent an interface!"); | |||
| } | |||
| // 初始化错误处理器; | |||
| this.exHandle = exHandle == null ? new DefaultExceptionHandle<TListener>() : exHandle; | |||
| this.exHandle = exHandle == null | |||
| ? new RethrowExceptionHandler<TListener>(LoggerFactory.getLogger(EventMulticaster.class)) | |||
| : exHandle; | |||
| // 解析出不支持的方法; | |||
| Method[] methods = ReflectionUtils.getAllDeclaredMethods(listenerClass); | |||
| List<Method> supMths = new LinkedList<Method>(); | |||
| List<Method> supMths = new ArrayList<Method>(); | |||
| for (Method method : methods) { | |||
| if (method.getDeclaringClass() == Object.class) { | |||
| // 不支持 Object 方法; | |||
| @@ -86,14 +92,14 @@ public class EventMulticaster<TListener> implements Disposable { | |||
| throw new UnsupportedOperationException("Unsupported method for event multicasting!"); | |||
| } | |||
| } | |||
| protected void doNotify(List<TListener> listeners, Method method, Object[] args){ | |||
| protected void doNotify(List<TListener> listeners, Method method, Object[] args) { | |||
| for (TListener listener : listeners) { | |||
| doNotifySingle(listener, method, args); | |||
| } | |||
| } | |||
| protected void doNotifySingle(TListener listener, Method method, Object[] args){ | |||
| protected void doNotifySingle(TListener listener, Method method, Object[] args) { | |||
| try { | |||
| ReflectionUtils.invokeMethod(method, listener, args); | |||
| } catch (Exception e) { | |||
| @@ -104,12 +110,12 @@ public class EventMulticaster<TListener> implements Disposable { | |||
| public void addListener(TListener listener) { | |||
| listeners.add(listener); | |||
| } | |||
| public void removeListener(TListener listener) { | |||
| listeners.remove(listener); | |||
| } | |||
| public TListener broadcast() { | |||
| public TListener getBroadcaster() { | |||
| return listenerProxy; | |||
| } | |||