Jabit/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java

219 lines
8.2 KiB
Java

/*
* Copyright 2015 Christian Basler
*
* 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 ch.dissem.bitmessage.repository;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.AddressRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class JdbcAddressRepository extends JdbcHelper implements AddressRepository {
private static final Logger LOG = LoggerFactory.getLogger(JdbcAddressRepository.class);
public JdbcAddressRepository(JdbcConfig config) {
super(config);
}
@Override
public BitmessageAddress findContact(byte[] ripeOrTag) {
for (BitmessageAddress address : find("public_key is null")) {
if (address.getVersion() > 3) {
if (Arrays.equals(ripeOrTag, address.getTag())) return address;
} else {
if (Arrays.equals(ripeOrTag, address.getRipe())) return address;
}
}
return null;
}
@Override
public BitmessageAddress findIdentity(byte[] ripeOrTag) {
for (BitmessageAddress address : find("private_key is not null")) {
if (address.getVersion() > 3) {
if (Arrays.equals(ripeOrTag, address.getTag())) return address;
} else {
if (Arrays.equals(ripeOrTag, address.getRipe())) return address;
}
}
return null;
}
@Override
public List<BitmessageAddress> getIdentities() {
return find("private_key IS NOT NULL");
}
@Override
public List<BitmessageAddress> getSubscriptions() {
return find("subscribed = '1'");
}
@Override
public List<BitmessageAddress> getSubscriptions(long broadcastVersion) {
if (broadcastVersion > 4) {
return find("subscribed = '1' AND version > 3");
} else {
return find("subscribed = '1' AND version <= 3");
}
}
@Override
public List<BitmessageAddress> getContacts() {
return find("private_key IS NULL");
}
private List<BitmessageAddress> find(String where) {
List<BitmessageAddress> result = new LinkedList<>();
try (Connection connection = config.getConnection()) {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed FROM Address WHERE " + where);
while (rs.next()) {
BitmessageAddress address;
InputStream privateKeyStream = rs.getBinaryStream("private_key");
if (privateKeyStream != null) {
PrivateKey privateKey = PrivateKey.read(privateKeyStream);
address = new BitmessageAddress(privateKey);
} else {
address = new BitmessageAddress(rs.getString("address"));
Blob publicKeyBlob = rs.getBlob("public_key");
if (publicKeyBlob != null) {
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length(), false);
if (address.getVersion() == 4 && pubkey instanceof V3Pubkey) {
pubkey = new V4Pubkey((V3Pubkey) pubkey);
}
address.setPubkey(pubkey);
}
}
address.setAlias(rs.getString("alias"));
address.setSubscribed(rs.getBoolean("subscribed"));
result.add(address);
}
} catch (IOException | SQLException e) {
LOG.error(e.getMessage(), e);
}
return result;
}
private boolean exists(BitmessageAddress address) {
try (Connection connection = config.getConnection()) {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address WHERE address='" + address.getAddress() + "'");
rs.next();
return rs.getInt(1) > 0;
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
return false;
}
@Override
public void save(BitmessageAddress address) {
try {
if (exists(address)) {
update(address);
} else {
insert(address);
}
} catch (IOException | SQLException e) {
LOG.error(e.getMessage(), e);
}
}
private void update(BitmessageAddress address) throws IOException, SQLException {
try (Connection connection = config.getConnection()) {
StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?");
if (address.getPubkey() != null) {
statement.append(", public_key=?");
}
if (address.getPrivateKey() != null) {
statement.append(", private_key=?");
}
statement.append(", subscribed=? WHERE address=?");
PreparedStatement ps = connection.prepareStatement(statement.toString());
int i = 0;
ps.setString(++i, address.getAlias());
if (address.getPubkey() != null) {
writePubkey(ps, ++i, address.getPubkey());
}
if (address.getPrivateKey() != null) {
writeBlob(ps, ++i, address.getPrivateKey());
}
ps.setBoolean(++i, address.isSubscribed());
ps.setString(++i, address.getAddress());
ps.executeUpdate();
}
}
private void insert(BitmessageAddress address) throws IOException, SQLException {
try (Connection connection = config.getConnection()) {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO Address (address, version, alias, public_key, private_key, subscribed) VALUES (?, ?, ?, ?, ?, ?)");
ps.setString(1, address.getAddress());
ps.setLong(2, address.getVersion());
ps.setString(3, address.getAlias());
writePubkey(ps, 4, address.getPubkey());
writeBlob(ps, 5, address.getPrivateKey());
ps.setBoolean(6, address.isSubscribed());
ps.executeUpdate();
}
}
protected void writePubkey(PreparedStatement ps, int parameterIndex, Pubkey data) throws SQLException, IOException {
if (data != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
data.writeUnencrypted(out);
ps.setBytes(parameterIndex, out.toByteArray());
} else {
ps.setBytes(parameterIndex, null);
}
}
@Override
public void remove(BitmessageAddress address) {
try (Connection connection = config.getConnection()) {
Statement stmt = connection.createStatement();
stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.getAddress() + "'");
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
}
@Override
public BitmessageAddress getAddress(String address) {
List<BitmessageAddress> result = find("address = '" + address + "'");
if (result.size() > 0) return result.get(0);
return null;
}
}