diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java index e3d720a5..2f6e0610 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java @@ -1,7 +1,7 @@ package com.jd.blockchain.contract; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; @Contract public class ReadContractImpl implements EventProcessingAware, ReadContract { @@ -24,7 +24,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { @Override @ContractEvent(name = "read-key") public String read(String address, String key) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); if (kvDataEntries != null && kvDataEntries.length == 1) { return kvDataEntries[0].getValue().toString(); @@ -35,7 +35,7 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { @Override @ContractEvent(name = "version-key") public Long readVersion(String address, String key) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); if (kvDataEntries != null && kvDataEntries.length == 1) { return kvDataEntries[0].getVersion(); diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java index c312dd4f..d29ee281 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java @@ -2,7 +2,7 @@ package com.jd.blockchain.contract; import com.alibaba.fastjson.JSON; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVDataVO; import com.jd.blockchain.ledger.KVInfoVO; @@ -14,7 +14,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String create(String address, String account, long money) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); // 肯定有返回值,但若不存在则返回version=-1 if (kvDataEntries != null && kvDataEntries.length > 0) { long currVersion = kvDataEntries[0].getVersion(); @@ -32,13 +32,13 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String transfer(String address, String from, String to, long money) { // 首先查询余额 - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); if (kvDataEntries == null || kvDataEntries.length != 2) { throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); } else { // 判断from账号中钱数量是否足够 long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; - for (KVDataEntry kvDataEntry : kvDataEntries) { + for (TypedKVEntry kvDataEntry : kvDataEntries) { if (kvDataEntry.getKey().equals(from)) { fromMoney = (long) kvDataEntry.getValue(); fromVersion = kvDataEntry.getVersion(); @@ -62,7 +62,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public long read(String address, String account) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { return -1; } @@ -71,7 +71,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr @Override public String readAll(String address, String account) { - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); // 获取最新的版本号 if (kvDataEntries == null || kvDataEntries.length == 0) { return ""; @@ -91,7 +91,7 @@ public class TransferContractImpl implements EventProcessingAware, TransferContr KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); - KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); + TypedKVEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); return JSON.toJSONString(allEntries); } diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java index f39e9424..12dfb4f5 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java @@ -25,7 +25,7 @@ import com.jd.blockchain.gateway.PeerService; import com.jd.blockchain.gateway.service.DataRetrievalService; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -261,7 +261,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestParam("keys") String... keys) { return peerService.getQueryService().getDataEntries(ledgerHash, address, keys); } @@ -269,7 +269,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestBody KVInfoVO kvInfoVO) { return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO); } @@ -277,7 +277,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash, @PathVariable("address") String address, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java index 324de791..58452dc2 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java @@ -2,8 +2,8 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedKVData; import com.jd.blockchain.ledger.MerkleProof; import com.jd.blockchain.ledger.TypedValue; import com.jd.blockchain.utils.Bytes; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java index 2c9e92de..c58d5a5c 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerQueryService.java @@ -8,8 +8,9 @@ import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.TypedKVData; import com.jd.blockchain.ledger.KVDataVO; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; @@ -22,12 +23,15 @@ import com.jd.blockchain.ledger.ParticipantNode; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.transaction.BlockchainQueryService; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; import com.jd.blockchain.utils.QueryUtil; public class LedgerQueryService implements BlockchainQueryService { - private static final KVDataEntry[] EMPTY_ENTRIES = new KVDataEntry[0]; + private static final TypedKVEntry[] EMPTY_ENTRIES = new TypedKVEntry[0]; private HashDigest[] ledgerHashs; @@ -278,7 +282,7 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { if (keys == null || keys.length == 0) { return EMPTY_ENTRIES; } @@ -287,7 +291,8 @@ public class LedgerQueryService implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { final String currKey = keys[i]; @@ -295,17 +300,17 @@ public class LedgerQueryService implements BlockchainQueryService { ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); if (ver < 0) { - entries[i] = new KVDataObject(currKey, -1, null); + entries[i] = new TypedKVData(currKey, -1, null); } else { BytesValue value = dataAccount.getDataset().getValue(currKey, ver); - entries[i] = new KVDataObject(currKey, ver, value); + entries[i] = new TypedKVData(currKey, ver, value); } } return entries; } - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { // parse kvInfoVO; List keyList = new ArrayList<>(); List versionList = new ArrayList<>(); @@ -335,22 +340,22 @@ public class LedgerQueryService implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver = -1; for (int i = 0; i < entries.length; i++) { // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); // dataAccount.getBytes(Bytes.fromString(keys[i]),1); ver = versions[i]; if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { if (dataAccount.getDataset().getDataCount() == 0 || dataAccount.getDataset().getValue(keys[i], ver) == null) { // is the address is not exist; the result is null; - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); - entries[i] = new KVDataObject(keys[i], ver, value); + entries[i] = new TypedKVData(keys[i], ver, value); } } } @@ -359,14 +364,22 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { checkLedgerHash(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); - return dataAccount.getDataset()..getDataEntries(pages[0], pages[1]); +// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); +// return dataAccount.getDataset().getDataEntry(key, version).getDataEntries(pages[0], pages[1]); + + DataIterator iterator = dataAccount.getDataset().iterator(); + iterator.skip(fromIndex); + DataEntry[] dataEntries = iterator.next(count); + + TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, + e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); + return typedKVEntries; } @Override diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java index 73696c27..3cc65cb7 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccountSet.java @@ -136,7 +136,12 @@ public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQ * @return */ public boolean contains(Bytes address) { - long latestVersion = getVersion(address); + InnerMerkleAccount acc = latestAccountsCache.get(address); + if (acc != null) { + // 无论是新注册未提交的,还是缓存已提交的账户实例,都认为是存在; + return true; + } + long latestVersion = merkleDataset.getVersion(address); return latestVersion > -1; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java index 2e31c27e..80217efe 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleDataSet.java @@ -10,10 +10,12 @@ import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.storage.service.utils.BufferedKVStorage; import com.jd.blockchain.storage.service.utils.VersioningKVData; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.Transactional; import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; import com.jd.blockchain.utils.Dataset; +import com.jd.blockchain.utils.Transactional; import com.jd.blockchain.utils.io.BytesUtils; /** @@ -39,6 +41,9 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset[] EMPTY_ENTRIES = new DataEntry[0]; + private BufferedKVStorage bufferedStorage; private VersioningKVStorage valueStorage; @@ -162,11 +167,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset LedgerConsts.MAX_LIST_COUNT) { throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); } @@ -182,13 +192,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset[] getLatestDataEntries(int fromIndex, int count) { + public DataEntry[] getLatestDataEntries(long fromIndex, int count) { if (count > LedgerConsts.MAX_LIST_COUNT) { throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); } if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { throw new IllegalArgumentException("Index out of bound!"); } + if (count == 0) { + return EMPTY_ENTRIES; + } @SuppressWarnings("unchecked") DataEntry[] values = new DataEntry[count]; byte[] bytesValue; @@ -201,6 +214,19 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset getLatestDataEntry(long index) { + if (index < 0 || index + 1 > merkleTree.getDataCount()) { + throw new IllegalArgumentException("Index out of bound!"); + } + byte[] bytesValue; + MerkleDataNode dataNode = merkleTree.getData(index); + Bytes dataKey = encodeDataKey(dataNode.getKey()); + bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); + DataEntry entry = new VersioningKVData(dataNode.getKey(), dataNode.getVersion(), + bytesValue); + return entry; + } + /** * get the data at the specific index; * @@ -505,6 +531,16 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset(key, version, value); } + @Override + public DataIterator iterator() { + return new AscDataInterator(getDataCount()); + } + + @Override + public DataIterator iteratorDesc() { + return new DescDataInterator(getDataCount()); + } + public MerkleDataEntry getMerkleEntry(Bytes key, long version) { DataEntry dataEntry = getDataEntry(key, version); if (dataEntry == null) { @@ -586,4 +622,119 @@ public class MerkleDataSet implements Transactional, MerkleProvable, Dataset { + + private final long total; + + private long cursor = 0; + + public AscDataInterator(long total) { + this.total = total; + } + + @Override + public void skip(long count) { + cursor = nextCursor(count); + } + + private long nextCursor(long skippingCount) { + long c = cursor + skippingCount; + return c > total ? total : c; + } + + @Override + public DataEntry next() { + if (hasNext()) { + DataEntry entry = getLatestDataEntry(cursor); + cursor = nextCursor(1); + return entry; + } + return null; + } + + @Override + public DataEntry[] next(int count) { + if (hasNext()) { + long from = cursor; + long nextCursor = nextCursor(count); + long c = nextCursor - cursor; + if (c > LedgerConsts.MAX_LIST_COUNT) { + throw new IllegalArgumentException( + "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); + } + DataEntry[] entries = getLatestDataEntries(from, (int) c); + cursor = nextCursor; + return entries; + } + return EMPTY_ENTRIES; + } + + @Override + public boolean hasNext() { + return cursor < total; + } + + } + + private class DescDataInterator implements DataIterator { + + private final long total; + + private long cursor; + + public DescDataInterator(long total) { + this.total = total; + this.cursor = total - 1; + } + + @Override + public void skip(long count) { + cursor = nextCursor(count); + } + + private long nextCursor(long skippingCount) { + long c = cursor - skippingCount; + return c < 0 ? -1 : c; + } + + @Override + public DataEntry next() { + if (hasNext()) { + DataEntry entry = getLatestDataEntry(cursor); + cursor = nextCursor(1); + return entry; + } + return null; + } + + @Override + public DataEntry[] next(int count) { + if (hasNext()) { + long nextCursor = nextCursor(count); + long from = nextCursor + 1; + long c = cursor - nextCursor; + if (c > LedgerConsts.MAX_LIST_COUNT) { + throw new IllegalArgumentException( + "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); + } + DataEntry[] entries = getLatestDataEntries(from, (int) c); + // reverse; + ArrayUtils.reverse(entries); + + cursor = nextCursor; + return entries; + } + return EMPTY_ENTRIES; + } + + @Override + public boolean hasNext() { + return cursor < total; + } + + } + } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java index e86747db..fe3f9826 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractLedgerContext.java @@ -10,7 +10,7 @@ import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractInfo; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -172,17 +172,17 @@ public class ContractLedgerContext implements LedgerContext { } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { return innerQueryService.getDataEntries(ledgerHash, address, keys); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count); } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java index 60ee6864..a0bf65be 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TxTestContractImpl.java @@ -3,7 +3,7 @@ package test.com.jd.blockchain.ledger; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractLifecycleAware; import com.jd.blockchain.contract.EventProcessingAware; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.utils.Bytes; public class TxTestContractImpl implements TxTestContract, ContractLifecycleAware, EventProcessingAware { @@ -16,7 +16,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar @Override public boolean testReadable() { - KVDataEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), + TypedKVEntry v1 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), dataAddress.toBase58(), KEY)[0]; String text1 = (String) v1.getValue(); System.out.printf("k1=%s, version=%s \r\n", text1, v1.getVersion()); @@ -26,7 +26,7 @@ public class TxTestContractImpl implements TxTestContract, ContractLifecycleAwar System.out.printf("new value = %s\r\n", newValue); eventContext.getLedger().dataAccount(dataAddress).setText(KEY, newValue, v1.getVersion()); - KVDataEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), + TypedKVEntry v2 = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), dataAddress.toBase58(), KEY)[0]; System.out.printf("---- read new value ----\r\nk1=%s, version=%s \r\n", v2.getValue(), v2.getVersion()); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java index 6a99be27..64f99a23 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/AccountSetTest.java @@ -48,7 +48,8 @@ public class AccountSetTest { BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); accset.register(userKey.getAddress(), userKey.getPubKey()); - + + //尚未提交之前,可以检索到账户的存在,但版本仍然标记为 -1; MerkleAccount userAcc = accset.getAccount(userKey.getAddress()); assertNotNull(userAcc); assertTrue(accset.contains(userKey.getAddress())); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java index 4683f9ca..047e3c51 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java @@ -6,8 +6,9 @@ import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; @DataContract(code= DataCodes.CONTRACT_ACCOUNT_HEADER) -public interface ContractInfo extends BlockchainIdentity { +public interface ContractInfo extends BlockchainIdentity, MerkleSnapshot { @DataField(order=4, primitiveType= PrimitiveType.BYTES) byte[] getChainCode(); + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java deleted file mode 100644 index a19d9fff..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java +++ /dev/null @@ -1,616 +0,0 @@ -package com.jd.blockchain.ledger; - -import java.math.BigInteger; -import java.util.Date; - -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.io.BytesUtils; - -/** - * KV数据项; - * - *

- * - * {@link KVDataObject} 被设计为只读对象; - * - * @author huanghaiquan - * - */ -public class KVDataObject implements KVDataEntry { - - private String key; - - private long version; - - private BytesValue bytesValue; - - public KVDataObject(String key, long version, BytesValue bytesValue) { - this.key = key; - this.version = version < 0 ? -1 : version; - this.bytesValue = bytesValue; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getKey() - */ - @Override - public String getKey() { - return key; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getVersion() - */ - @Override - public long getVersion() { - return version; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.ledger.KVDataEntry#getType() - */ - @Override - public DataType getType() { - return bytesValue == null ? DataType.NIL : bytesValue.getType(); - } - - @Override - public Object getValue() { - if (bytesValue == null) { - return null; - } - - switch (getType()) { - case NIL: - return null; - case TEXT: - return bytesValue.getBytes().toUTF8String(); - case BYTES: - return ByteArray.toHex(bytesValue.getBytes().toBytes()); - case INT64: - return BytesUtils.toLong(bytesValue.getBytes().toBytes()); - case JSON: - return bytesValue.getBytes().toUTF8String(); - case XML: - return bytesValue.getBytes().toUTF8String(); - - default: - throw new IllegalStateException("Unsupported value type[" + getType() + "] to resolve!"); - } - } - - /** - * 是否为空值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#NIL} 时返回 true,其它情况返回 false; - *

- * - * @return - */ - public boolean isNil() { - return bytesValue == null || DataType.NIL == bytesValue.getType(); - } - - /** - * 字节数组形式的原始内容; - * - * @return - */ - Bytes bytesArray() { - return bytesValue.getBytes(); - } - - /** - * 返回 8 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT8} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public byte tinyValue() { - if (DataType.INT8 == getType()) { - return bytesValue.getBytes().toBytes()[0]; - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT8, getType())); - } - - /** - * 返回 16 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT16} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public short shortValue() { - if (DataType.INT16 == getType()) { - return BytesUtils.toShort(bytesValue.getBytes().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT16, getType())); - } - - /** - * 返回 32 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT32} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public int intValue() { - if (DataType.INT32 == getType()) { - return BytesUtils.toInt(bytesValue.getBytes().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT32, getType())); - } - - /** - * 返回 64 位整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#INT64} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public long longValue() { - if (DataType.INT64 == getType()) { - return BytesUtils.toLong(bytesValue.getBytes().toBytes(), 0); - } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); - - } - - /** - * 返回大整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public BigInteger bigIntValue() { - if (DataType.BIG_INT == getType()) { - return new BigInteger(bytesValue.getBytes().toBytes()); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.BIG_INT, getType())); - } - - /** - * 返回布尔值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#BIG_INT} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public boolean boolValue() { - if (DataType.BOOLEAN == getType()) { - return BytesUtils.toBoolean(bytesValue.getBytes().toBytes()[0]); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.BOOLEAN, getType())); - } - - /** - * 返回日期时间值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TIMESTAMP} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public Date datetimeValue() { - if (DataType.TIMESTAMP == getType()) { - long ts = BytesUtils.toLong(bytesValue.getBytes().toBytes()); - return new Date(ts); - } - throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", DataType.TIMESTAMP, getType())); - } - - /** - * 返回大整数值; - *

- * - * 仅当数据类型 {@link #getType()} 为 {@link PrimitiveType#TEXT} / - * {@link PrimitiveType#JSON} / {@link PrimitiveType#XML} 有效; - *

- * - * 无效类型将引发 {@link IllegalStateException} 异常; - * - * @return - */ - public String stringValue() { - DataType type = getType(); - if (DataType.TEXT == type || DataType.JSON == type || DataType.XML == type) { - return bytesValue.getBytes().toUTF8String(); - } - throw new IllegalStateException(String.format("Expected type [%s] or [%s] or [%s] , but [%s]", - PrimitiveType.TEXT, DataType.JSON, DataType.XML, type)); - } - -// // ---------------- -// public KVDataEntry nextVersionNil() { -// return nilState(key, version + 1); -// } -// -// public KVDataEntry nextVersionBoolean(boolean value) { -// return booleanState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionTiny(byte value) { -// return tinyState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionShort(short value) { -// return shortState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionInt(int value) { -// return intState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionLong(long value) { -// return longState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionDatetime(Date value) { -// return datetimeState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionJson(String value) { -// return jsonState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionXml(String value) { -// return xmlState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionBigInt(BigInteger value) { -// return bigIntState(key, version + 1, value); -// } -// -// public KVDataEntry nextVersionText(boolean encrypted, String value) { -// return textState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionBytes(boolean encrypted, byte[] value) { -// return bytesState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionImage(boolean encrypted, byte[] value) { -// return imageState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionVideo(boolean encrypted, byte[] value) { -// return videoState(key, version + 1, encrypted, value); -// } -// -// public KVDataEntry nextVersionLocation(boolean encrypted, byte[] value) { -// return locationState(key, version + 1, encrypted, value); -// } -// // ---------------- -// -// public KVDataEntry newNil() { -// return nilState(key, version); -// } -// -// public KVDataEntry newBoolean(boolean value) { -// return booleanState(key, version, value); -// } -// -// public KVDataEntry newTiny(byte value) { -// return tinyState(key, version, value); -// } -// -// public KVDataEntry newShort(short value) { -// return shortState(key, version, value); -// } -// -// public KVDataEntry newInt(int value) { -// return intState(key, version, value); -// } -// -// public KVDataObject newLong(long value) { -// return longState(key, version, value); -// } -// -// public KVDataEntry newDatetime(Date value) { -// return datetimeState(key, version, value); -// } -// -// public KVDataEntry newJson(String value) { -// return jsonState(key, version, value); -// } -// -// public KVDataEntry newXml(String value) { -// return xmlState(key, version, value); -// } -// -// public KVDataEntry newBigInt(BigInteger value) { -// return bigIntState(key, version, value); -// } -// -// public KVDataEntry newText(boolean encrypted, String value) { -// return textState(key, version, encrypted, value); -// } -// -// public KVDataEntry newBytes(boolean encrypted, byte[] value) { -// return bytesState(key, version, encrypted, value); -// } -// -// public KVDataEntry newImage(boolean encrypted, byte[] value) { -// return imageState(key, version, encrypted, value); -// } -// -// public KVDataEntry newVideo(boolean encrypted, byte[] value) { -// return videoState(key, version, encrypted, value); -// } -// -// public KVDataEntry newLocation(boolean encrypted, byte[] value) { -// return locationState(key, version, encrypted, value); -// } -// -// // ---------------- -// -// public KVDataEntry newNil(long version) { -// return nilState(key, version); -// } -// -// public KVDataEntry newBoolean(long version, boolean value) { -// return booleanState(key, version, value); -// } -// -// public KVDataEntry newTiny(long version, byte value) { -// return tinyState(key, version, value); -// } -// -// public KVDataEntry newShort(long version, short value) { -// return shortState(key, version, value); -// } -// -// public KVDataEntry newInt(long version, int value) { -// return intState(key, version, value); -// } -// -// public KVDataEntry newLong(long version, long value) { -// return longState(key, version, value); -// } -// -// public KVDataEntry newDatetime(long version, Date value) { -// return datetimeState(key, version, value); -// } -// -// public KVDataEntry newJson(long version, String value) { -// return jsonState(key, version, value); -// } -// -// public KVDataEntry newXml(long version, String value) { -// return xmlState(key, version, value); -// } -// -// public KVDataEntry newBigInt(long version, BigInteger value) { -// return bigIntState(key, version, value); -// } -// -// public KVDataEntry newText(long version, boolean encrypted, String value) { -// return textState(key, version, encrypted, value); -// } -// -// public KVDataEntry newBytes(long version, boolean encrypted, byte[] value) { -// return bytesState(key, version, encrypted, value); -// } -// -// public KVDataEntry newImage(long version, boolean encrypted, byte[] value) { -// return imageState(key, version, encrypted, value); -// } -// -// public KVDataEntry newVideo(long version, boolean encrypted, byte[] value) { -// return videoState(key, version, encrypted, value); -// } -// -// public KVDataEntry newLocation(long version, boolean encrypted, byte[] value) { -// return locationState(key, version, encrypted, value); -// } -// -// // ---------------- -// -// public static KVDataEntry booleanState(String key, boolean value) { -// return booleanState(key, -1, value); -// } -// -// public static KVDataEntry tinyState(String key, byte value) { -// return tinyState(key, -1, value); -// } -// -// public static KVDataEntry shortState(String key, short value) { -// return shortState(key, -1, value); -// } -// -// public static KVDataEntry intState(String key, int value) { -// return intState(key, -1, value); -// } -// -// public static KVDataEntry longState(String key, long value) { -// return longState(key, -1, value); -// } -// -// public static KVDataEntry datetimeState(String key, Date value) { -// return datetimeState(key, -1, value); -// } -// -// public static KVDataEntry jsonState(String key, String value) { -// return jsonState(key, -1, value); -// } -// -// public static KVDataEntry xmlState(String key, String value) { -// return xmlState(key, -1, value); -// } -// -// public static KVDataEntry bigIntState(String key, BigInteger value) { -// return bigIntState(key, -1, value); -// } -// -// public static KVDataObject textState(String key, String value) { -// return textState(key, -1, false, value); -// } -// -// public static KVDataEntry bytesState(String key, byte[] value) { -// return bytesState(key, -1, false, value); -// } -// -// public static KVDataEntry imageState(String key, byte[] value) { -// return imageState(key, -1, false, value); -// } -// -// public static KVDataEntry videoState(String key, byte[] value) { -// return videoState(key, -1, false, value); -// } -// -// public static KVDataEntry locationState(String key, byte[] value) { -// return locationState(key, -1, false, value); -// } -// -// // ---------------- -// -// public static KVDataEntry textState(String key, boolean encrypted, String value) { -// return textState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry bytesState(String key, boolean encrypted, byte[] value) { -// return bytesState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry imageState(String key, boolean encrypted, byte[] value) { -// return imageState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry videoState(String key, boolean encrypted, byte[] value) { -// return videoState(key, -1, encrypted, value); -// } -// -// public static KVDataEntry locationState(String key, boolean encrypted, byte[] value) { -// return locationState(key, -1, encrypted, value); -// } -// -// // ---------------------- -// -// public static KVDataEntry nilState(String key) { -// return new KVDataObject(key, ValueType.NIL, -1, false, BytesUtils.EMPTY_BYTES); -// } -// -// public static KVDataEntry nilState(String key, long version) { -// return new KVDataObject(key, ValueType.NIL, version, false, BytesUtils.EMPTY_BYTES); -// } -// -// public static KVDataEntry booleanState(String key, long version, boolean value) { -// byte[] v = { value ? (byte) 1 : (byte) 0 }; -// return new KVDataObject(key, ValueType.BOOLEAN, version, false, v); -// } -// -// public static KVDataEntry tinyState(String key, long version, byte value) { -// byte[] v = { value }; -// return new KVDataObject(key, ValueType.INT8, version, false, v); -// } -// -// public static KVDataEntry shortState(String key, long version, short value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT16, version, false, v); -// } -// -// public static KVDataEntry intState(String key, long version, int value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT32, version, false, v); -// } -// -// public static KVDataObject longState(String key, long version, long value) { -// byte[] v = BytesUtils.toBytes(value); -// return new KVDataObject(key, ValueType.INT64, version, false, v); -// } -// -// public static KVDataEntry datetimeState(String key, long version, Date value) { -// byte[] v = BytesUtils.toBytes(value.getTime()); -// return new KVDataObject(key, ValueType.DATETIME, version, false, v); -// } -// -// public static KVDataObject textState(String key, long version, boolean encrypted, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.TEXT, version, encrypted, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry jsonState(String key, long version, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.JSON, version, false, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry xmlState(String key, long version, String value) { -// try { -// byte[] v = value.getBytes("UTF-8"); -// return new KVDataObject(key, ValueType.XML, version, false, v); -// } catch (UnsupportedEncodingException e) { -// throw new IllegalStateException(e.getMessage(), e); -// } -// } -// -// public static KVDataEntry bigIntState(String key, long version, BigInteger value) { -// byte[] v = value.toByteArray(); -// return new KVDataObject(key, ValueType.BIG_INT, version, false, v); -// } -// -// public static KVDataEntry bytesState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.BYTES, version, encrypted, value); -// } -// -// public static KVDataEntry imageState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.IMG, version, encrypted, value); -// } -// -// public static KVDataEntry videoState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.VIDEO, version, encrypted, value); -// } -// -// public static KVDataEntry locationState(String key, long version, boolean encrypted, byte[] value) { -// return new KVDataObject(key, ValueType.LOCATION, version, encrypted, value); -// } - -} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java new file mode 100644 index 00000000..dd06de98 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVData.java @@ -0,0 +1,78 @@ +package com.jd.blockchain.ledger; + +/** + * 强类型的“键-值”数据对象; + * + *

+ * + * {@link TypedKVData} 被设计为只读对象; + * + * @author huanghaiquan + * + */ +public class TypedKVData implements TypedKVEntry { + + private String key; + + private long version; + + private DataType type; + + private Object value; + + public TypedKVData(String key, long version, DataType type, Object value) { + this.key = key; + this.version = version; + this.type = type; + this.value = value; + } + + public TypedKVData(String key, long version, BytesValue bytesValue) { + this.key = key; + this.version = version; + TypedValue typedValue; + if (bytesValue != null && bytesValue instanceof TypedValue) { + typedValue = (TypedValue) bytesValue; + } else { + typedValue = TypedValue.wrap(bytesValue); + } + this.type = typedValue.getType(); + this.value = typedValue.getValue(); + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getKey() + */ + @Override + public String getKey() { + return key; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getVersion() + */ + @Override + public long getVersion() { + return version; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.ledger.KVDataEntry#getType() + */ + @Override + public DataType getType() { + return type; + } + + @Override + public Object getValue() { + return value; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java similarity index 57% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java index 396cc36d..54165c61 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedKVEntry.java @@ -1,6 +1,6 @@ package com.jd.blockchain.ledger; -public interface KVDataEntry { +public interface TypedKVEntry { /** * 键名; @@ -33,4 +33,12 @@ public interface KVDataEntry { */ Object getValue(); + default long longValue() { + if (getType() == DataType.INT64) { + Object value = getValue(); + return value == null ? 0 : (long) value; + } + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); + } + } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java index e2c0c9d5..65dbd298 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TypedValue.java @@ -16,9 +16,9 @@ import com.jd.blockchain.utils.io.BytesUtils; * */ public class TypedValue implements BytesValue { - + public static final BytesValue NIL = new TypedValue(); - + private DataType type; private Bytes value; @@ -31,16 +31,19 @@ public class TypedValue implements BytesValue { this.type = type; this.value = bytes; } - + private TypedValue(BytesValue bytesValue) { - this.type = bytesValue.getType(); - this.value = bytesValue.getBytes(); + if (bytesValue == null) { + this.type = DataType.NIL; + } else { + this.type = bytesValue.getType(); + this.value = bytesValue.getBytes(); + } } - + private TypedValue() { this.type = DataType.NIL; } - @Override public DataType getType() { @@ -229,8 +232,7 @@ public class TypedValue implements BytesValue { if (DataType.BIG_INT == type) { return toBigInteger(); } - throw new IllegalStateException( - String.format("Type [%s] cannot be convert to BigInteger!", type)); + throw new IllegalStateException(String.format("Type [%s] cannot be convert to BigInteger!", type)); } private BigInteger toBigInteger() { @@ -280,8 +282,7 @@ public class TypedValue implements BytesValue { if (DataType.TIMESTAMP == type) { return toDatetime(); } - throw new IllegalStateException( - String.format("Type [%s] cannot be convert to datetime!", type)); + throw new IllegalStateException(String.format("Type [%s] cannot be convert to datetime!", type)); } private Date toDatetime() { @@ -346,8 +347,7 @@ public class TypedValue implements BytesValue { if (DataType.HASH_DIGEST == type) { return toHashDegist(); } - throw new IllegalStateException( - String.format("Type [%s] cannot be convert to hash digest!", type)); + throw new IllegalStateException(String.format("Type [%s] cannot be convert to hash digest!", type)); } private HashDigest toHashDegist() { @@ -375,14 +375,13 @@ public class TypedValue implements BytesValue { if (DataType.SIGNATURE_DIGEST == type) { return toSignatureDigest(); } - throw new IllegalStateException( - String.format("Type [%s] cannot be convert to signature digest!", type)); + throw new IllegalStateException(String.format("Type [%s] cannot be convert to signature digest!", type)); } private SignatureDigest toSignatureDigest() { return new SignatureDigest(toBytesArray()); } - + public static TypedValue wrap(BytesValue value) { return new TypedValue(value); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java index 9d8f5fa8..f63a7f2a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java @@ -5,7 +5,7 @@ import org.springframework.cglib.core.Block; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -264,9 +264,9 @@ public interface BlockchainQueryService { * @param keys * @return */ - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); /** * 返回指定数据账户中KV数据的总数;
@@ -287,7 +287,7 @@ public interface BlockchainQueryService { * 如果参数值为 -1,则返回全部的记录;
* @return */ - KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); + TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); /** * 返回合约账户信息; diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java index 8bbada7f..2fd0cd80 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java @@ -3,7 +3,6 @@ package com.jd.blockchain.peer.web; import java.util.ArrayList; import java.util.List; -import com.jd.blockchain.ledger.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -14,6 +13,22 @@ import org.springframework.web.bind.annotation.RestController; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.ContractInfo; +import com.jd.blockchain.ledger.KVDataVO; +import com.jd.blockchain.ledger.KVInfoVO; +import com.jd.blockchain.ledger.LedgerAdminInfo; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.LedgerMetadata; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TypedKVData; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedValue; +import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.ledger.core.ContractAccountQuery; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.DataAccountQuery; @@ -23,7 +38,10 @@ import com.jd.blockchain.ledger.core.ParticipantCertData; import com.jd.blockchain.ledger.core.TransactionQuery; import com.jd.blockchain.ledger.core.UserAccountQuery; import com.jd.blockchain.transaction.BlockchainQueryService; +import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.DataEntry; +import com.jd.blockchain.utils.DataIterator; import com.jd.blockchain.utils.QueryUtil; @RestController @@ -72,7 +90,7 @@ public class LedgerQueryController implements BlockchainQueryService { } return null; } - + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/admininfo") @Override public LedgerAdminInfo getLedgerAdminInfo(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { @@ -337,7 +355,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { if (keys == null || keys.length == 0) { return null; @@ -347,15 +365,15 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { ver = dataAccount.getDataset().getVersion(keys[i]); if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); - entries[i] = new KVDataObject(keys[i], ver, value); + entries[i] = new TypedKVData(keys[i], ver, value); } } @@ -365,7 +383,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestBody KVInfoVO kvInfoVO) { // parse kvInfoVO; List keyList = new ArrayList<>(); @@ -396,21 +414,21 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - KVDataEntry[] entries = new KVDataEntry[keys.length]; + TypedKVEntry[] entries = new TypedKVEntry[keys.length]; long ver = -1; for (int i = 0; i < entries.length; i++) { // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); ver = versions[i]; if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { if (dataAccount.getDataset().getDataCount() == 0 || dataAccount.getDataset().getValue(keys[i], ver) == null) { // is the address is not exist; the result is null; - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new TypedKVData(keys[i], -1, null); } else { BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); - entries[i] = new KVDataObject(keys[i], ver, value); + entries[i] = new TypedKVData(keys[i], ver, value); } } } @@ -421,7 +439,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + public TypedKVEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address, @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { @@ -431,15 +449,21 @@ public class LedgerQueryController implements BlockchainQueryService { DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); - return dataAccount.getDataEntries(pages[0], pages[1]); +// int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); +// return dataAccount.getDataEntries(pages[0], pages[1]); + + DataIterator iterator = dataAccount.getDataset().iterator(); + iterator.skip(fromIndex); + DataEntry[] dataEntries = iterator.next(count); + TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, + e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); + return typedKVEntries; } @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") @Override public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, @PathVariable(name = "address") String address) { - LedgerQuery ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); @@ -451,7 +475,7 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") @Override public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { + @PathVariable(name = "address") String address) { LedgerQuery ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java index cc6d41a7..4e7534a4 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java @@ -39,14 +39,14 @@ import com.jd.blockchain.utils.io.BytesUtils; public class ClientResolveUtil { - public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { + public static TypedKVEntry[] read(TypedKVEntry[] kvDataEntries) { if (kvDataEntries == null || kvDataEntries.length == 0) { return kvDataEntries; } - KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; + TypedKVEntry[] resolveKvDataEntries = new TypedKVEntry[kvDataEntries.length]; // kvDataEntries是代理对象,需要处理 for (int i = 0; i < kvDataEntries.length; i++) { - KVDataEntry kvDataEntry = kvDataEntries[i]; + TypedKVEntry kvDataEntry = kvDataEntries[i]; String key = kvDataEntry.getKey(); long version = kvDataEntry.getVersion(); DataType dataType = kvDataEntry.getType(); @@ -330,7 +330,7 @@ public class ClientResolveUtil { } - public static class KvData implements KVDataEntry { + public static class KvData implements TypedKVEntry { private String key; diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java index 4949a777..9984cef5 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java @@ -3,7 +3,7 @@ package com.jd.blockchain.sdk.proxy; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractInfo; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.KVInfoVO; import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; @@ -161,20 +161,20 @@ public abstract class BlockchainServiceProxy implements BlockchainService { } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); return ClientResolveUtil.read(kvDataEntries); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); return ClientResolveUtil.read(kvDataEntries); } @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { - KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); + public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + TypedKVEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); return ClientResolveUtil.read(kvDataEntries); } diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java index 56127820..d13fa436 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java @@ -504,13 +504,13 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries") @Override - KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address, @RequestParam(name="keys", array = true) String... keys); @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version") @Override - KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address, @RequestBody KVInfoVO kvInfoVO); @@ -531,7 +531,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") @Override - KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, + TypedKVEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash, @PathParam(name = "address") String address, @RequestParam(name = "fromIndex", required = false) int fromIndex, @RequestParam(name = "count", required = false) int count); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java index d662378d..1782d985 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java @@ -9,8 +9,8 @@ import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.contract.EventProcessingAware; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TypedKVEntry; +import com.jd.blockchain.ledger.TypedKVData; import com.jd.blockchain.utils.Bytes; /** @@ -47,16 +47,16 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { } // 查询当前值; - KVDataEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, + TypedKVEntry[] kvEntries = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, KEY_TOTAL, assetHolderAddress); // 计算资产的发行总数; - KVDataObject currTotal = (KVDataObject) kvEntries[0]; + TypedKVData currTotal = (TypedKVData) kvEntries[0]; long newTotal = currTotal.longValue() + amount; eventContext.getLedger().dataAccount(ASSET_ADDRESS).setInt64(KEY_TOTAL, newTotal, currTotal.getVersion()); // 分配到持有者账户; - KVDataObject holderAmount = (KVDataObject) kvEntries[1]; + TypedKVData holderAmount = (TypedKVData) kvEntries[1]; long newHodlerAmount = holderAmount.longValue() + amount; eventContext.getLedger().dataAccount(ASSET_ADDRESS) .setInt64(assetHolderAddress, newHodlerAmount, holderAmount.getVersion()).setText("K2", "info2", -1) @@ -77,10 +77,10 @@ public class AssetContractImpl implements EventProcessingAware, AssetContract { checkSignerPermission(fromAddress); // 查询现有的余额; - KVDataEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, + TypedKVEntry[] origBalances = eventContext.getLedger().getDataEntries(currentLedgerHash(), ASSET_ADDRESS, fromAddress, toAddress); - KVDataEntry fromBalanceKV = origBalances[0]; - KVDataEntry toBalanceKV = origBalances[1]; + TypedKVEntry fromBalanceKV = origBalances[0]; + TypedKVEntry toBalanceKV = origBalances[1]; long fromBalance = fromBalanceKV.getVersion() == -1 ? 0 : (long) fromBalanceKV.getValue(); long toBalance = toBalanceKV.getVersion() == -1 ? 0 : (long) toBalanceKV.getValue(); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java index 3205fd73..a3e44d95 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Query.java @@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.Transaction; @@ -67,7 +67,7 @@ public class SDKDemo_Query { // 获取数据; String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; String[] objKeys = new String[] { "x001", "x002" }; - KVDataEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); + TypedKVEntry[] kvData = service.getDataEntries(LEDGER_HASH, commerceAccount, objKeys); long payloadVersion = kvData[0].getVersion(); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java index 9d43b199..caae0d6d 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java @@ -6,7 +6,7 @@ import static com.jd.blockchain.transaction.ContractReturnValue.decode; import com.jd.blockchain.contract.TransferContract; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionTemplate; @@ -106,11 +106,11 @@ public class SDK_Contract_Demo extends SDK_Base_Demo { } private long readByKvOperation(String address, String account) { - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); } - KVDataEntry kvDataEntry = kvDataEntries[0]; + TypedKVEntry kvDataEntry = kvDataEntries[0]; if (kvDataEntry.getVersion() == -1) { return 0L; } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java index c73a7f91..868f3269 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Random_Demo.java @@ -79,11 +79,11 @@ public class SDK_Contract_Random_Demo extends SDK_Base_Demo { } private long readByKvOperation(String address, String account) { - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); if (kvDataEntries == null || kvDataEntries.length == 0) { throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); } - KVDataEntry kvDataEntry = kvDataEntries[0]; + TypedKVEntry kvDataEntry = kvDataEntries[0]; if (kvDataEntry.getVersion() == -1) { return 0L; } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java index 3a89c7a6..d90b5233 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_InsertData_Demo.java @@ -107,9 +107,9 @@ public class SDK_InsertData_Demo extends SDK_Base_Demo { // KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, objKeys); // 获取数据账户下所有的KV列表 - KVDataEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); + TypedKVEntry[] kvData = blockchainService.getDataEntries(ledgerHash, commerceAccount, 0, 100); if (kvData != null && kvData.length > 0) { - for (KVDataEntry kvDatum : kvData) { + for (TypedKVEntry kvDatum : kvData) { System.out.println("kvData.key=" + kvDatum.getKey()); System.out.println("kvData.version=" + kvDatum.getVersion()); System.out.println("kvData.type=" + kvDatum.getType()); diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java index 346aae79..3d291811 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_Query_Test_.java @@ -24,7 +24,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerTransaction; @@ -149,8 +149,8 @@ public class SDK_GateWay_Query_Test_ { String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; String[] objKeys = new String[] { "x001", "x002" }; - KVDataEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); - for (KVDataEntry kvDatum : kvData) { + TypedKVEntry[] kvData = service.getDataEntries(ledgerHash, commerceAccount, objKeys); + for (TypedKVEntry kvDatum : kvData) { System.out.println("kvData.key=" + kvDatum.getKey()); System.out.println("kvData.version=" + kvDatum.getVersion()); System.out.println("kvData.value=" + kvDatum.getValue()); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java index 421dfd89..0ffcbb3e 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java @@ -26,7 +26,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerInitProperties; @@ -216,8 +216,8 @@ public class IntegrationTest { ledgerOfNode0.retrieveLatestBlock(); // 更新内存 // 先验证应答 - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress, dataKey); + for (TypedKVEntry kvDataEntry : kvDataEntries) { String valHexText = (String) kvDataEntry.getValue(); byte[] valBytes = HexUtils.decode(valHexText); String valText = new String(valBytes); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index 9c3b3320..37c792f2 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -286,8 +286,8 @@ public class IntegrationBase { assertEquals(txResp.getContentHash(), transactionHash); assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, daAddress, dataKey); + for (TypedKVEntry kvDataEntry : kvDataEntries) { assertEquals(dataKey, kvDataEntry.getKey()); String valHexText = (String) kvDataEntry.getValue(); assertEquals(dataVal, valHexText); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java index 86b70840..6c8c762c 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java @@ -26,7 +26,7 @@ import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerInitProperties; @@ -302,9 +302,9 @@ public class IntegrationTestAll4Redis { assertEquals(txResp.getContentHash(), prepTx.getHash()); assertEquals(txResp.getBlockHash(), ledgerRepository.getLatestBlockHash()); - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, dataAccountAddress.toString(), dataKey); - for (KVDataEntry kvDataEntry : kvDataEntries) { + for (TypedKVEntry kvDataEntry : kvDataEntries) { assertEquals(dataKey, kvDataEntry.getKey()); String valHexText = (String) kvDataEntry.getValue(); byte[] valBytes = HexUtils.decode(valHexText); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java index c6361d89..e029dc09 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestDataAccount.java @@ -23,7 +23,7 @@ import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.TypedKVEntry; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInitProperties; import com.jd.blockchain.ledger.PreparedTransaction; @@ -214,7 +214,7 @@ public class IntegrationTestDataAccount { e.printStackTrace(); } - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", + TypedKVEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHashs[0], dataAddr.toBase58(), "A", "B", "C", "D"); for (int i = 0; i < kvDataEntries.length; i++) { Object result = kvDataEntries[i].getValue(); diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java index 79773915..cea92cbc 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/ArrayUtils.java @@ -9,17 +9,29 @@ import java.util.*; */ public abstract class ArrayUtils { private ArrayUtils() { - + } - + + public static R[] castTo(T[] objs, Class clazz, CastFunction cf) { + if (objs == null) { + return null; + } + @SuppressWarnings("unchecked") + R[] array = (R[]) Array.newInstance(clazz, objs.length); + for (int i = 0; i < objs.length; i++) { + array[i] = cf.cast(objs[i]); + } + return array; + } + public static T[] singleton(T obj, Class clazz) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, 1); array[0] = obj; return array; } - - public static T[] toArray(Iterator itr, Class clazz){ + + public static T[] toArray(Iterator itr, Class clazz) { List lst = new LinkedList(); while (itr.hasNext()) { T t = (T) itr.next(); @@ -30,19 +42,19 @@ public abstract class ArrayUtils { lst.toArray(array); return array; } - - public static T[] toArray(Collection collection, Class clazz){ + + public static T[] toArray(Collection collection, Class clazz) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, collection.size()); collection.toArray(array); return array; } - - public static List asList(T[] array){ + + public static List asList(T[] array) { return asList(array, 0, array.length); } - - public static Set asSet(T[] array){ + + public static Set asSet(T[] array) { if (array == null || array.length == 0) { return Collections.emptySet(); } @@ -52,8 +64,8 @@ public abstract class ArrayUtils { } return set; } - - public static SortedSet asSortedSet(T[] array){ + + public static SortedSet asSortedSet(T[] array) { if (array == null || array.length == 0) { return Collections.emptySortedSet(); } @@ -63,12 +75,12 @@ public abstract class ArrayUtils { } return set; } - - public static List asList(T[] array, int fromIndex){ + + public static List asList(T[] array, int fromIndex) { return asList(array, fromIndex, array.length); } - - public static List asList(T[] array, int fromIndex, int toIndex){ + + public static List asList(T[] array, int fromIndex, int toIndex) { if (toIndex < fromIndex) { throw new IllegalArgumentException("The toIndex less than fromIndex!"); } @@ -78,10 +90,33 @@ public abstract class ArrayUtils { if (toIndex > array.length) { throw new IllegalArgumentException("The toIndex great than the length of array!"); } - + if (fromIndex == toIndex) { return Collections.emptyList(); } return new ReadonlyArrayListWrapper(array, fromIndex, toIndex); } + + public static interface CastFunction { + public R cast(T data); + } + + /** + * Reverse all elements of the specified array;
+ * + * @param + * @param array + */ + public static void reverse(T[] array) { + if (array == null || array.length < 2) { + return; + } + + T t; + for (int i = 0, j = array.length - 1; i < j; i++, j--) { + t = array[i]; + array[i] = array[j]; + array[j] = t; + } + } } diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java index 4548dbad..890748e5 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java @@ -1,7 +1,5 @@ package com.jd.blockchain.utils; -import java.io.File; - /** * * @author zhaogw diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java index 6c538525..b02fa524 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataEntry.java @@ -1,7 +1,7 @@ package com.jd.blockchain.utils; /** - * 版本化的键值数据项; + * Versioning Key-Value data entry; * * @author huanghaiquan * diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java new file mode 100644 index 00000000..13a8a0d0 --- /dev/null +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataIterator.java @@ -0,0 +1,21 @@ +package com.jd.blockchain.utils; + +/** + * 数据迭代器; + * + * @author huanghaiquan + * + * @param + * @param + */ +public interface DataIterator { + + void skip(long count); + + DataEntry next(); + + DataEntry[] next(int count); + + boolean hasNext(); + +} diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java deleted file mode 100644 index 05952868..00000000 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DataTypeUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jd.blockchain.utils; - -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.util.TypeUtils; - -public abstract class DataTypeUtils { - - private static Map, Class> wrapperTypes = new HashMap, Class>(); - - static{ - wrapperTypes.put(long.class, Long.class); - wrapperTypes.put(int.class, Integer.class); - wrapperTypes.put(char.class, Character.class); - wrapperTypes.put(byte.class, Byte.class); - wrapperTypes.put(boolean.class, Boolean.class); - } - - public static boolean isAssignable(Type lhsType, Type rhsType) { - boolean assignable = TypeUtils.isAssignable(lhsType, rhsType); - if (assignable) { - return true; - } - if (lhsType instanceof Class) { - Class lhsClass = (Class) lhsType; - - } - - return false; - } - -} diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java index a84654c2..5cd2f2f3 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Dataset.java @@ -1,7 +1,20 @@ package com.jd.blockchain.utils; +/** + * Key-Value data set; + * + * @author huanghaiquan + * + * @param + * @param + */ public interface Dataset { - + + /** + * Total count of data entries; + * + * @return + */ long getDataCount(); /** @@ -26,17 +39,6 @@ public interface Dataset { */ long setValue(K key, V value, long version); -// /** -// * Return the specified version's value;
-// * -// * If the key with the specified version doesn't exist, then return null;
-// * If the version is specified to -1, then return the latest version's value; -// * -// * @param key -// * @param version -// */ -// byte[] getValue(String key, long version); - /** * Return the specified version's value;
* @@ -48,47 +50,51 @@ public interface Dataset { */ V getValue(K key, long version); -// /** -// * Return the latest version's value; -// * -// * @param key -// * @return return null if not exist; -// */ -// byte[] getValue(String key); - /** - * Return the latest version's value; + * Return the value of the latest version; * * @param key * @return return null if not exist; */ V getValue(K key); -// /** -// * Return the latest version entry associated the specified key; If the key -// * doesn't exist, then return -1; -// * -// * @param key -// * @return -// */ -// long getVersion(String key); - /** - * Return the latest version entry associated the specified key; If the key - * doesn't exist, then return -1; + * Return the latest version number of the specified key; * * @param key - * @return + * @return The version number of the specified key; If the key doesn't exist, + * then return -1; */ long getVersion(K key); /** + * Return data entry * * @param key * @return Null if the key doesn't exist! */ DataEntry getDataEntry(K key); + /** + * + * @param key + * @param version + * @return + */ DataEntry getDataEntry(K key, long version); + /** + * Ascending iterator; + * + * @return + */ + DataIterator iterator(); + + /** + * Descending iterator; + * + * @return + */ + DataIterator iteratorDesc(); + } \ No newline at end of file diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java index de96f665..acbdce51 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/DatasetHelper.java @@ -1,8 +1,12 @@ package com.jd.blockchain.utils; +/** + * Helper for {@link Dataset}; + * + * @author huanghaiquan + * + */ public class DatasetHelper { - - public static final TypeMapper UTF8_STRING_BYTES_MAPPER = new TypeMapper() { @@ -29,7 +33,7 @@ public class DatasetHelper { return Bytes.fromString(t2); } }; - + /** * 适配两个不同类型参数的数据集; * @@ -121,8 +125,8 @@ public class DatasetHelper { T2 decode(T1 t1); } - - private static class EmptyMapper implements TypeMapper{ + + private static class EmptyMapper implements TypeMapper { @Override public T encode(T t) { @@ -133,7 +137,7 @@ public class DatasetHelper { public T decode(T t) { return t; } - + } private static class DatasetUpdatingMonitor implements Dataset { @@ -186,6 +190,16 @@ public class DatasetHelper { return dataset.getDataEntry(key, version); } + @Override + public DataIterator iterator() { + return dataset.iterator(); + } + + @Override + public DataIterator iteratorDesc() { + return dataset.iteratorDesc(); + } + } /** @@ -269,6 +283,73 @@ public class DatasetHelper { return new KeyValueEntry(key, v, entry.getVersion()); } + @Override + public DataIterator iterator() { + DataIterator it = dataset.iterator(); + return new DataIteratorAdapter(it, keyMapper, valueMapper); + } + + @Override + public DataIterator iteratorDesc() { + DataIterator it = dataset.iteratorDesc(); + return new DataIteratorAdapter(it, keyMapper, valueMapper); + } + + } + + private static class DataIteratorAdapter implements DataIterator { + + private DataIterator iterator; + + private TypeMapper keyMapper; + private TypeMapper valueMapper; + + public DataIteratorAdapter(DataIterator iterator, TypeMapper keyMapper, + TypeMapper valueMapper) { + this.iterator = iterator; + this.keyMapper = keyMapper; + this.valueMapper = valueMapper; + } + + @Override + public void skip(long count) { + iterator.skip(count); + } + + @Override + public DataEntry next() { + DataEntry entry = iterator.next(); + return cast(entry); + } + + private DataEntry cast(DataEntry entry) { + if (entry == null) { + return null; + } + + K2 k = keyMapper.decode(entry.getKey()); + V2 v = valueMapper.decode(entry.getValue()); + return new KeyValueEntry(k, v, entry.getVersion()); + } + + @SuppressWarnings("unchecked") + @Override + public DataEntry[] next(int count) { + DataEntry[] entries = iterator.next(count); + if (entries == null) { + return null; + } + if (entries.length == 0) { + return (DataEntry[]) entries; + } + return ArrayUtils.castTo(entries, DataEntry.class, e -> cast(e)); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + } private static class KeyValueEntry implements DataEntry {