/****************************************************************************** * Copyright © 2013-2016 The Nxt Core Developers. * * * * See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * Nxt software, including this file, may be copied, modified, propagated, * * or distributed except according to the terms contained in the LICENSE.txt * * file. * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ package nxt; import nxt.db.DbClause; import nxt.db.DbIterator; import nxt.db.DbKey; import nxt.db.VersionedEntityDbTable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public final class Asset { private static final DbKey.LongKeyFactory<Asset> assetDbKeyFactory = new DbKey.LongKeyFactory<Asset>("id") { @Override public DbKey newKey(Asset asset) { return asset.dbKey; } }; private static final VersionedEntityDbTable<Asset> assetTable = new VersionedEntityDbTable<Asset>("asset", assetDbKeyFactory, "name,description") { @Override protected Asset load(Connection con, ResultSet rs) throws SQLException { return new Asset(rs); } @Override protected void save(Connection con, Asset asset) throws SQLException { asset.save(con); } @Override public void trim(int height) { super.trim(Math.max(0, height - Constants.MAX_DIVIDEND_PAYMENT_ROLLBACK)); } @Override public void checkAvailable(int height) { if (height + Constants.MAX_DIVIDEND_PAYMENT_ROLLBACK < Nxt.getBlockchainProcessor().getMinRollbackHeight()) { throw new IllegalArgumentException("Historical data as of height " + height +" not available."); } if (height > Nxt.getBlockchain().getHeight()) { throw new IllegalArgumentException("Height " + height + " exceeds blockchain height " + Nxt.getBlockchain().getHeight()); } } }; public static DbIterator<Asset> getAllAssets(int from, int to) { return assetTable.getAll(from, to); } public static int getCount() { return assetTable.getCount(); } public static Asset getAsset(long id) { return assetTable.get(assetDbKeyFactory.newKey(id)); } public static Asset getAsset(long id, int height) { return assetTable.get(assetDbKeyFactory.newKey(id), height); } public static DbIterator<Asset> getAssetsIssuedBy(long accountId, int from, int to) { return assetTable.getManyBy(new DbClause.LongClause("account_id", accountId), from, to); } public static DbIterator<Asset> searchAssets(String query, int from, int to) { return assetTable.search(query, DbClause.EMPTY_CLAUSE, from, to, " ORDER BY ft.score DESC "); } static void addAsset(Transaction transaction, Attachment.ColoredCoinsAssetIssuance attachment) { assetTable.insert(new Asset(transaction, attachment)); } static void deleteAsset(Transaction transaction, long assetId, long quantityQNT) { Asset asset = getAsset(assetId); asset.quantityQNT = Math.max(0, asset.quantityQNT - quantityQNT); assetTable.insert(asset); AssetDelete.addAssetDelete(transaction, assetId, quantityQNT); } static void init() {} private final long assetId; private final DbKey dbKey; private final long accountId; private final String name; private final String description; private final long initialQuantityQNT; private long quantityQNT; private final byte decimals; private Asset(Transaction transaction, Attachment.ColoredCoinsAssetIssuance attachment) { this.assetId = transaction.getId(); this.dbKey = assetDbKeyFactory.newKey(this.assetId); this.accountId = transaction.getSenderId(); this.name = attachment.getName(); this.description = attachment.getDescription(); this.quantityQNT = attachment.getQuantityQNT(); this.initialQuantityQNT = this.quantityQNT; this.decimals = attachment.getDecimals(); } private Asset(ResultSet rs) throws SQLException { this.assetId = rs.getLong("id"); this.dbKey = assetDbKeyFactory.newKey(this.assetId); this.accountId = rs.getLong("account_id"); this.name = rs.getString("name"); this.description = rs.getString("description"); this.initialQuantityQNT = rs.getLong("initial_quantity"); this.quantityQNT = rs.getLong("quantity"); this.decimals = rs.getByte("decimals"); } private void save(Connection con) throws SQLException { try (PreparedStatement pstmt = con.prepareStatement("MERGE INTO asset " + "(id, account_id, name, description, initial_quantity, quantity, decimals, height, latest) " + "KEY(id, height) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, TRUE)")) { int i = 0; pstmt.setLong(++i, this.assetId); pstmt.setLong(++i, this.accountId); pstmt.setString(++i, this.name); pstmt.setString(++i, this.description); pstmt.setLong(++i, this.initialQuantityQNT); pstmt.setLong(++i, this.quantityQNT); pstmt.setByte(++i, this.decimals); pstmt.setInt(++i, Nxt.getBlockchain().getHeight()); pstmt.executeUpdate(); } } public long getId() { return assetId; } public long getAccountId() { return accountId; } public String getName() { return name; } public String getDescription() { return description; } public long getInitialQuantityQNT() { return initialQuantityQNT; } public long getQuantityQNT() { return quantityQNT; } public byte getDecimals() { return decimals; } public DbIterator<Account.AccountAsset> getAccounts(int from, int to) { return Account.getAssetAccounts(this.assetId, from, to); } public DbIterator<Account.AccountAsset> getAccounts(int height, int from, int to) { return Account.getAssetAccounts(this.assetId, height, from, to); } public DbIterator<Trade> getTrades(int from, int to) { return Trade.getAssetTrades(this.assetId, from, to); } public DbIterator<AssetTransfer> getAssetTransfers(int from, int to) { return AssetTransfer.getAssetTransfers(this.assetId, from, to); } }