/*
* Copyright 2014 http://Bither.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bither.db;
import net.bither.ApplicationInstanceManager;
import net.bither.bitherj.core.Peer;
import net.bither.bitherj.db.AbstractDb;
import net.bither.bitherj.db.IPeerProvider;
import net.bither.bitherj.utils.Utils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class PeerProvider implements IPeerProvider {
private static final String insertPeerSql = "insert into peers " +
"(peer_address,peer_port,peer_services,peer_timestamp,peer_connected_cnt)" +
" values (?,?,?,?,?) ";
private static PeerProvider peerProvider = new PeerProvider(ApplicationInstanceManager.txDBHelper);
public static PeerProvider getInstance() {
return peerProvider;
}
private TxDBHelper mDb;
public PeerProvider(TxDBHelper db) {
this.mDb = db;
}
public List<Peer> getAllPeers() {
List<Peer> peers = new ArrayList<Peer>();
String sql = "select * from peers";
try {
PreparedStatement statement = this.mDb.getPreparedStatement(sql, null);
ResultSet c = statement.executeQuery();
while (c.next()) {
Peer peer = applyCursor(c);
if (peer != null) {
peers.add(peer);
}
}
c.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
return peers;
}
public void deletePeersNotInAddresses(List<InetAddress> peerAddrsses) {
final List<Long> needDeletePeers = new ArrayList<Long>();
String sql = "select peer_address from peers";
try {
PreparedStatement statement = this.mDb.getPreparedStatement(sql, null);
ResultSet c = statement.executeQuery();
while (c.next()) {
int idColumn = c.findColumn(AbstractDb.PeersColumns.PEER_ADDRESS);
if (idColumn != -1) {
long peerAddress = c.getLong(idColumn);
boolean in = false;
for (InetAddress a : peerAddrsses) {
if (Utils.parseLongFromAddress(a) == peerAddress) {
in = true;
break;
}
}
if (!in) {
needDeletePeers.add(peerAddress);
}
}
}
c.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
this.mDb.getConn().setAutoCommit(false);
for (long i : needDeletePeers) {
PreparedStatement preparedStatement = this.mDb.getConn().prepareStatement("delete peers where peer_address=?");
preparedStatement.setLong(1, i);
preparedStatement.executeUpdate();
preparedStatement.close();
}
this.mDb.getConn().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
public ArrayList<InetAddress> exists(ArrayList<InetAddress> peerAddresses) {
ArrayList<InetAddress> exists = new ArrayList<InetAddress>();
List<Peer> peerItemList = getAllPeers();
for (Peer item : peerItemList) {
if (peerAddresses.contains(item.getPeerAddress())) {
exists.add(item.getPeerAddress());
}
}
peerItemList.clear();
return exists;
}
public synchronized void addPeers(List<Peer> items) {
final List<Peer> addItems = new ArrayList<Peer>();
List<Peer> allItems = getAllPeers();
for (Peer peerItem : items) {
if (!allItems.contains(peerItem) && !addItems.contains(peerItem)) {
addItems.add(peerItem);
}
}
allItems.clear();
if (addItems.size() > 0) {
try {
this.mDb.getConn().setAutoCommit(false);
for (Peer item : addItems) {
PreparedStatement preparedStatement = this.mDb.getConn().prepareStatement(insertPeerSql);
preparedStatement.setLong(1, Utils.parseLongFromAddress(item
.getPeerAddress()));
preparedStatement.setLong(2, item.getPeerPort());
preparedStatement.setLong(3, item.getPeerServices());
preparedStatement.setLong(4, item.getPeerTimestamp());
preparedStatement.setLong(5, item.getPeerConnectedCnt());
preparedStatement.executeUpdate();
preparedStatement.close();
}
this.mDb.getConn().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void removePeer(InetAddress address) {
try {
if (this.mDb.getConn() != null && !this.mDb.getConn().isClosed()) {
this.mDb.executeUpdate("delete from peers where peer_address = ?", new String[]{Long.toString(Utils.parseLongFromAddress
(address))});
//TODO Database synchronization is wrong
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void conncetFail(InetAddress address) {
try {
long addressLong = Utils.parseLongFromAddress(address);
String sql = "select count(0) cnt from peers where peer_address=? and peer_connected_cnt=0";
PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Long.toString(addressLong)});
ResultSet c = statement.executeQuery();
int cnt = 0;
if (c.next()) {
int idColumn = c.findColumn("cnt");
if (idColumn != -1) {
cnt = c.getInt(idColumn);
}
}
c.close();
statement.close();
if (cnt == 0) {
sql = "update peers set peer_connected_cnt=peer_connected_cnt+1 where peer_address="
+ Long.toString(addressLong);
this.mDb.executeUpdate(sql, null);
} else {
sql = "update peers set peer_connected_cnt=2 where peer_address=" + Long.toString
(addressLong);
this.mDb.executeUpdate(sql, null);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void connectSucceed(InetAddress address) {
long addressLong = Utils.parseLongFromAddress(address);
this.mDb.executeUpdate("update peers set peer_connected_cnt=1 , peer_timestamp=? where peer_address=?",
new String[]{Long.toString(new Date().getTime()), Long.toString(addressLong)});
}
public List<Peer> getPeersWithLimit(int limit) {
List<Peer> peerItemList = new ArrayList<Peer>();
String sql = "select * from peers order by peer_address limit ?";
try {
PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(limit)});
ResultSet c = statement.executeQuery();
while (c.next()) {
Peer peer = applyCursor(c);
if (peer != null) {
peerItemList.add(peer);
}
}
c.close();
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
return peerItemList;
}
public void cleanPeers() {
try {
int maxPeerSaveCnt = 1000;
String disconnectingPeerCntSql = "select count(0) cnt from peers where " +
"peer_connected_cnt<>1";
int disconnectingPeerCnt = 0;
PreparedStatement statement = this.mDb.getPreparedStatement(disconnectingPeerCntSql, null);
ResultSet c = statement.executeQuery();
if (c.next()) {
int idColumn = c.findColumn("cnt");
if (idColumn != -1) {
disconnectingPeerCnt = c.getInt(idColumn);
}
}
c.close();
statement.close();
if (disconnectingPeerCnt > maxPeerSaveCnt) {
String sql = "select peer_timestamp from peers where peer_connected_cnt<>1 " +
"order by peer_timestamp desc limit 1 offset ? ";
statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(maxPeerSaveCnt)});
c = statement.executeQuery();
long timestamp = 0;
if (c.next()) {
int idColumn = c.findColumn(AbstractDb.PeersColumns.PEER_TIMESTAMP);
if (idColumn != -1) {
timestamp = c.getLong(idColumn);
}
}
c.close();
statement.close();
if (timestamp > 0) {
mDb.executeUpdate("delete peers where peer_connected_cnt<>1 and peer_timestamp<=?"
, new String[]{Long.toString(timestamp)});
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void deleteUnknowHost(long address) {
this.mDb.executeUpdate("delete peers where peer_address=?"
, new String[]{Long.toString(address)});
}
private Peer applyCursor(ResultSet rs) throws SQLException {
InetAddress address = null;
int idColumn = rs.findColumn(AbstractDb.PeersColumns.PEER_ADDRESS);
if (idColumn != -1) {
long addressLong = rs.getLong(idColumn);
try {
address = Utils.parseAddressFromLong(addressLong);
} catch (UnknownHostException e) {
e.printStackTrace();
deleteUnknowHost(addressLong);
}
}
if (address == null) {
return null;
}
Peer peerItem = new Peer(address);
idColumn = rs.findColumn(AbstractDb.PeersColumns.PEER_CONNECTED_CNT);
if (idColumn != -1) {
peerItem.setPeerConnectedCnt(rs.getInt(idColumn));
}
idColumn = rs.findColumn(AbstractDb.PeersColumns.PEER_PORT);
if (idColumn != -1) {
peerItem.setPeerPort(rs.getInt(idColumn));
}
idColumn = rs.findColumn(AbstractDb.PeersColumns.PEER_SERVICES);
if (idColumn != -1) {
peerItem.setPeerServices(rs.getLong(idColumn));
}
idColumn = rs.findColumn(AbstractDb.PeersColumns.PEER_TIMESTAMP);
if (idColumn != -1) {
peerItem.setPeerTimestamp(rs.getInt(idColumn));
}
return peerItem;
}
public void recreate() {
try {
Connection connection = this.mDb.getConn();
Statement stmt = connection.createStatement();
stmt.executeUpdate("drop table " + AbstractDb.Tables.PEERS + ";");
stmt.executeUpdate(AbstractDb.CREATE_PEER_SQL);
connection.commit();
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}