Added tests for all repositories, fixed some bugs and made database configurable
This commit is contained in:
		@@ -1,3 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.demo;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.BitmessageContext;
 | 
			
		||||
@@ -5,10 +21,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress;
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
 | 
			
		||||
import ch.dissem.bitmessage.networking.NetworkNode;
 | 
			
		||||
import ch.dissem.bitmessage.repository.JdbcAddressRepository;
 | 
			
		||||
import ch.dissem.bitmessage.repository.JdbcInventory;
 | 
			
		||||
import ch.dissem.bitmessage.repository.JdbcMessageRepository;
 | 
			
		||||
import ch.dissem.bitmessage.repository.JdbcNodeRegistry;
 | 
			
		||||
import ch.dissem.bitmessage.repository.*;
 | 
			
		||||
import ch.dissem.bitmessage.utils.Strings;
 | 
			
		||||
import org.flywaydb.core.internal.util.logging.slf4j.Slf4jLog;
 | 
			
		||||
import org.flywaydb.core.internal.util.logging.slf4j.Slf4jLogCreator;
 | 
			
		||||
@@ -29,12 +42,13 @@ public class Application {
 | 
			
		||||
    private BitmessageContext ctx;
 | 
			
		||||
 | 
			
		||||
    public Application() {
 | 
			
		||||
        JdbcConfig jdbcConfig = new JdbcConfig();
 | 
			
		||||
        ctx = new BitmessageContext.Builder()
 | 
			
		||||
                .addressRepo(new JdbcAddressRepository())
 | 
			
		||||
                .inventory(new JdbcInventory())
 | 
			
		||||
                .nodeRegistry(new JdbcNodeRegistry())
 | 
			
		||||
                .addressRepo(new JdbcAddressRepository(jdbcConfig))
 | 
			
		||||
                .inventory(new JdbcInventory(jdbcConfig))
 | 
			
		||||
                .nodeRegistry(new JdbcNodeRegistry(jdbcConfig))
 | 
			
		||||
                .messageRepo(new JdbcMessageRepository(jdbcConfig))
 | 
			
		||||
                .networkHandler(new NetworkNode())
 | 
			
		||||
                .messageRepo(new JdbcMessageRepository())
 | 
			
		||||
                .port(48444)
 | 
			
		||||
                .streams(1)
 | 
			
		||||
                .build();
 | 
			
		||||
@@ -59,7 +73,7 @@ public class Application {
 | 
			
		||||
            System.out.println("i) identities");
 | 
			
		||||
            System.out.println("c) contacts");
 | 
			
		||||
            System.out.println("m) messages");
 | 
			
		||||
            System.out.println("e) Exit");
 | 
			
		||||
            System.out.println("e) exit");
 | 
			
		||||
 | 
			
		||||
            command = nextCommand();
 | 
			
		||||
            try {
 | 
			
		||||
 
 | 
			
		||||
@@ -97,7 +97,6 @@ public class BitmessageContext {
 | 
			
		||||
        Plaintext msg = new Plaintext.Builder()
 | 
			
		||||
                .from(from)
 | 
			
		||||
                .to(to)
 | 
			
		||||
                .encoding(Encoding.SIMPLE)
 | 
			
		||||
                .message(subject, message)
 | 
			
		||||
                .build();
 | 
			
		||||
        if (to.getPubkey() == null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -340,6 +340,7 @@ public class Plaintext implements Streamable {
 | 
			
		||||
 | 
			
		||||
        public Builder message(String subject, String message) {
 | 
			
		||||
            try {
 | 
			
		||||
                this.encoding = Encoding.SIMPLE.getCode();
 | 
			
		||||
                this.message = ("Subject:" + subject + '\n' + "Body:" + message).getBytes("UTF-8");
 | 
			
		||||
            } catch (UnsupportedEncodingException e) {
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package ch.dissem.bitmessage.utils;
 | 
			
		||||
package ch.dissem.bitmessage.exception;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Indicates an illegal Bitmessage address
 | 
			
		||||
@@ -1,3 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.exception;
 | 
			
		||||
 | 
			
		||||
public class DecryptionFailedException extends Exception {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,19 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.exception;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.utils.Strings;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,23 +17,35 @@
 | 
			
		||||
package ch.dissem.bitmessage.utils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 13.04.15.
 | 
			
		||||
 * Intended to count the bytes read or written during (de-)serialization.
 | 
			
		||||
 */
 | 
			
		||||
public class AccessCounter {
 | 
			
		||||
    private int count;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases the counter by one, if not null.
 | 
			
		||||
     */
 | 
			
		||||
    public static void inc(AccessCounter counter) {
 | 
			
		||||
        if (counter != null) counter.inc();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void inc(AccessCounter counter, int count) {
 | 
			
		||||
        if (counter != null) counter.inc(count);
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases the counter by length, if not null.
 | 
			
		||||
     */
 | 
			
		||||
    public static void inc(AccessCounter counter, int length) {
 | 
			
		||||
        if (counter != null) counter.inc(length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases the counter by one.
 | 
			
		||||
     */
 | 
			
		||||
    private void inc() {
 | 
			
		||||
        count++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases the counter by length.
 | 
			
		||||
     */
 | 
			
		||||
    private void inc(int length) {
 | 
			
		||||
        count += length;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,16 @@
 | 
			
		||||
 | 
			
		||||
package ch.dissem.bitmessage.utils;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.exception.AddressFormatException;
 | 
			
		||||
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
 | 
			
		||||
import static java.util.Arrays.copyOfRange;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base58 encoder and decoder
 | 
			
		||||
 * Base58 encoder and decoder.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Christian Basler: I removed some dependencies to the BitcoinJ code so it can be used here more easily.
 | 
			
		||||
 */
 | 
			
		||||
public class Base58 {
 | 
			
		||||
    private static char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,9 @@ import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A helper class for working with byte arrays interpreted as unsigned big endian integers.
 | 
			
		||||
 * This is one part due to the fact that Java doesn't support unsigned numbers, and another
 | 
			
		||||
 * part so we don't have to convert between byte arrays and numbers in time critical
 | 
			
		||||
 * situations.
 | 
			
		||||
 */
 | 
			
		||||
public class Bytes {
 | 
			
		||||
    public static void inc(byte[] nonce) {
 | 
			
		||||
@@ -33,6 +36,9 @@ public class Bytes {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Increases nonce by value, which is used as an unsigned byte value.
 | 
			
		||||
     */
 | 
			
		||||
    public static void inc(byte[] nonce, byte value) {
 | 
			
		||||
        int i = nonce.length - 1;
 | 
			
		||||
        nonce[i] += value;
 | 
			
		||||
@@ -67,7 +73,7 @@ public class Bytes {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns true if a < b, where the first [size] bytes are checked.
 | 
			
		||||
     * Returns true if a < b, where the first [size] bytes are used as the numbers to check.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean lt(byte[] a, byte[] b, int size) {
 | 
			
		||||
        for (int i = 0; i < size; i++) {
 | 
			
		||||
@@ -84,6 +90,9 @@ public class Bytes {
 | 
			
		||||
        return a < b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a new byte array of length, left-padded with '0'.
 | 
			
		||||
     */
 | 
			
		||||
    public static byte[] expand(byte[] source, int size) {
 | 
			
		||||
        byte[] result = new byte[size];
 | 
			
		||||
        System.arraycopy(source, 0, result, size - source.length, source.length);
 | 
			
		||||
@@ -99,19 +108,10 @@ public class Bytes {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static byte[] subArray(byte[] source, int offset, int length) {
 | 
			
		||||
        byte[] result = new byte[length];
 | 
			
		||||
        System.arraycopy(source, offset, result, 0, length);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static byte[] concatenate(byte first, byte[] bytes) {
 | 
			
		||||
        byte[] result = new byte[bytes.length + 1];
 | 
			
		||||
        result[0] = first;
 | 
			
		||||
        System.arraycopy(bytes, 0, result, 1, bytes.length);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the byte array that hex represents. This is meant for test use and should be rewritten if used in
 | 
			
		||||
     * production code.
 | 
			
		||||
     */
 | 
			
		||||
    public static byte[] fromHex(String hex) {
 | 
			
		||||
        if (hex.length() % 2 != 0) throw new IllegalArgumentException("expected even number of characters");
 | 
			
		||||
        byte[] result = new byte[hex.length() / 2];
 | 
			
		||||
@@ -135,6 +135,9 @@ public class Bytes {
 | 
			
		||||
        throw new IllegalArgumentException("'" + c + "' is not a valid hex value");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the number of leading '0' of a byte array.
 | 
			
		||||
     */
 | 
			
		||||
    public static int numberOfLeadingZeros(byte[] bytes) {
 | 
			
		||||
        int i;
 | 
			
		||||
        for (i = 0; i < bytes.length; i++) {
 | 
			
		||||
@@ -143,10 +146,16 @@ public class Bytes {
 | 
			
		||||
        return i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a copy of bytes with leading zeroes stripped.
 | 
			
		||||
     */
 | 
			
		||||
    public static byte[] stripLeadingZeros(byte[] bytes) {
 | 
			
		||||
        return Arrays.copyOfRange(bytes, numberOfLeadingZeros(bytes), bytes.length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the byte array of the serialized data.
 | 
			
		||||
     */
 | 
			
		||||
    public static byte[] from(Streamable data) {
 | 
			
		||||
        try {
 | 
			
		||||
            ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
			
		||||
 
 | 
			
		||||
@@ -23,42 +23,6 @@ import ch.dissem.bitmessage.entity.payload.ObjectType;
 | 
			
		||||
 * TODO: Probably this should be split in a GUI related and an SQL related utility class.
 | 
			
		||||
 */
 | 
			
		||||
public class Strings {
 | 
			
		||||
    public static StringBuilder join(byte[]... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(hex(objects[i]));
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(long... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(objects[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(ObjectType... types) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < types.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(types[i].getNumber());
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(Enum... types) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < types.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append('\'').append(types[i].name()).append('\'');
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(Object... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,12 @@
 | 
			
		||||
package ch.dissem.bitmessage.utils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 18.04.15.
 | 
			
		||||
 * A simple utility class that simplifies using the second based time used in Bitmessage.
 | 
			
		||||
 */
 | 
			
		||||
public class UnixTime {
 | 
			
		||||
    /**
 | 
			
		||||
     * Length of a day in seconds, intended for use with {@link #now(long)}.
 | 
			
		||||
     */
 | 
			
		||||
    public static final long DAY = 60 * 60 * 24;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -29,6 +32,9 @@ public class UnixTime {
 | 
			
		||||
        return System.currentTimeMillis() / 1000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Same as {@link #now()} + shiftSeconds, but might be more readable.
 | 
			
		||||
     */
 | 
			
		||||
    public static long now(long shiftSeconds) {
 | 
			
		||||
        return (System.currentTimeMillis() / 1000) + shiftSeconds;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,6 @@ public class SerializationTest {
 | 
			
		||||
        Plaintext p1 = new Plaintext.Builder()
 | 
			
		||||
                .from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
 | 
			
		||||
                .to(TestUtils.loadContact())
 | 
			
		||||
                .encoding(Plaintext.Encoding.SIMPLE)
 | 
			
		||||
                .message("Subject", "Message")
 | 
			
		||||
                .ack("ack".getBytes())
 | 
			
		||||
                .signature(new byte[0])
 | 
			
		||||
 
 | 
			
		||||
@@ -21,12 +21,6 @@ import org.junit.Test;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
 | 
			
		||||
public class StringsTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureJoinWorksWithLongArray() {
 | 
			
		||||
        long[] test = {1L, 2L};
 | 
			
		||||
        assertEquals("1, 2", Strings.join(test).toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testHexString() {
 | 
			
		||||
        assertEquals("48656c6c6f21", Strings.hex("Hello!".getBytes()).toString());
 | 
			
		||||
 
 | 
			
		||||
@@ -34,12 +34,13 @@ import java.util.Arrays;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 23.04.15.
 | 
			
		||||
 */
 | 
			
		||||
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")) {
 | 
			
		||||
@@ -81,8 +82,8 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
 | 
			
		||||
 | 
			
		||||
    private List<BitmessageAddress> find(String where) {
 | 
			
		||||
        List<BitmessageAddress> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        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;
 | 
			
		||||
@@ -114,8 +115,8 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean exists(BitmessageAddress address) {
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        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;
 | 
			
		||||
@@ -139,23 +140,26 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void update(BitmessageAddress address) throws IOException, SQLException {
 | 
			
		||||
        PreparedStatement ps = getConnection().prepareStatement(
 | 
			
		||||
        try(Connection connection = config.getConnection()){
 | 
			
		||||
        PreparedStatement ps = connection.prepareStatement(
 | 
			
		||||
                "UPDATE Address SET alias=?, public_key=?, private_key=? WHERE address=?");
 | 
			
		||||
        ps.setString(1, address.getAlias());
 | 
			
		||||
        writePubkey(ps, 2, address.getPubkey());
 | 
			
		||||
        writeBlob(ps, 3, address.getPrivateKey());
 | 
			
		||||
        ps.setString(4, address.getAddress());
 | 
			
		||||
        ps.executeUpdate();
 | 
			
		||||
    }
 | 
			
		||||
    }}
 | 
			
		||||
 | 
			
		||||
    private void insert(BitmessageAddress address) throws IOException, SQLException {
 | 
			
		||||
        PreparedStatement ps = getConnection().prepareStatement(
 | 
			
		||||
                "INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?)");
 | 
			
		||||
        ps.setString(1, address.getAddress());
 | 
			
		||||
        ps.setString(2, address.getAlias());
 | 
			
		||||
        writePubkey(ps, 3, address.getPubkey());
 | 
			
		||||
        writeBlob(ps, 4, address.getPrivateKey());
 | 
			
		||||
        ps.executeUpdate();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            PreparedStatement ps = connection.prepareStatement(
 | 
			
		||||
                    "INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?)");
 | 
			
		||||
            ps.setString(1, address.getAddress());
 | 
			
		||||
            ps.setString(2, address.getAlias());
 | 
			
		||||
            writePubkey(ps, 3, address.getPubkey());
 | 
			
		||||
            writeBlob(ps, 4, address.getPrivateKey());
 | 
			
		||||
            ps.executeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void writePubkey(PreparedStatement ps, int parameterIndex, Pubkey data) throws SQLException, IOException {
 | 
			
		||||
@@ -171,8 +175,8 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void remove(BitmessageAddress address) {
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        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);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 org.flywaydb.core.Flyway;
 | 
			
		||||
 | 
			
		||||
import java.sql.Connection;
 | 
			
		||||
import java.sql.DriverManager;
 | 
			
		||||
import java.sql.SQLException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The base configuration for all JDBC based repositories. You should only make one instance,
 | 
			
		||||
 * as flyway initializes/updates the database at object creation.
 | 
			
		||||
 */
 | 
			
		||||
public class JdbcConfig {
 | 
			
		||||
    protected final Flyway flyway;
 | 
			
		||||
    private final String dbUrl;
 | 
			
		||||
    private final String dbUser;
 | 
			
		||||
    private final String dbPassword;
 | 
			
		||||
 | 
			
		||||
    public JdbcConfig(String dbUrl, String dbUser, String dbPassword) {
 | 
			
		||||
        this.dbUrl = dbUrl;
 | 
			
		||||
        this.dbUser = dbUser;
 | 
			
		||||
        this.dbPassword = dbPassword;
 | 
			
		||||
        this.flyway = new Flyway();
 | 
			
		||||
        flyway.setDataSource(dbUrl, dbUser, dbPassword);
 | 
			
		||||
        flyway.migrate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JdbcConfig() {
 | 
			
		||||
        this("jdbc:h2:~/jabit", "sa", null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Connection getConnection() {
 | 
			
		||||
        try {
 | 
			
		||||
            return DriverManager.getConnection(dbUrl, dbUser, dbPassword);
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
package ch.dissem.bitmessage.repository;
 | 
			
		||||
 | 
			
		||||
import ch.dissem.bitmessage.entity.Streamable;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
 | 
			
		||||
import org.flywaydb.core.Flyway;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
@@ -26,21 +27,54 @@ import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.sql.*;
 | 
			
		||||
 | 
			
		||||
import static ch.dissem.bitmessage.utils.Strings.hex;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper class that does Flyway migration, provides JDBC connections and some helper methods.
 | 
			
		||||
 */
 | 
			
		||||
abstract class JdbcHelper {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(JdbcHelper.class);
 | 
			
		||||
 | 
			
		||||
    private static final String DB_URL = "jdbc:h2:~/jabit";
 | 
			
		||||
    private static final String DB_USER = "sa";
 | 
			
		||||
    private static final String DB_PWD = null;
 | 
			
		||||
    protected final JdbcConfig config;
 | 
			
		||||
 | 
			
		||||
    protected JdbcHelper(JdbcConfig config) {
 | 
			
		||||
        this.config = config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        Flyway flyway = new Flyway();
 | 
			
		||||
        flyway.setDataSource(DB_URL, DB_USER, DB_PWD);
 | 
			
		||||
        flyway.migrate();
 | 
			
		||||
    public static StringBuilder join(long... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(objects[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(byte[]... objects) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < objects.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(hex(objects[i]));
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(ObjectType... types) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < types.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append(types[i].getNumber());
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static StringBuilder join(Enum... types) {
 | 
			
		||||
        StringBuilder streamList = new StringBuilder();
 | 
			
		||||
        for (int i = 0; i < types.length; i++) {
 | 
			
		||||
            if (i > 0) streamList.append(", ");
 | 
			
		||||
            streamList.append('\'').append(types[i].name()).append('\'');
 | 
			
		||||
        }
 | 
			
		||||
        return streamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void writeBlob(PreparedStatement ps, int parameterIndex, Streamable data) throws SQLException, IOException {
 | 
			
		||||
@@ -53,12 +87,4 @@ abstract class JdbcHelper {
 | 
			
		||||
            ps.setBlob(parameterIndex, (Blob) null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected Connection getConnection() {
 | 
			
		||||
        try {
 | 
			
		||||
            return DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,20 +28,20 @@ import java.sql.*;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static ch.dissem.bitmessage.utils.Strings.join;
 | 
			
		||||
import static ch.dissem.bitmessage.utils.UnixTime.now;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 24.04.15.
 | 
			
		||||
 */
 | 
			
		||||
public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(JdbcInventory.class);
 | 
			
		||||
 | 
			
		||||
    public JdbcInventory(JdbcConfig config) {
 | 
			
		||||
        super(config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<InventoryVector> getInventory(long... streams) {
 | 
			
		||||
        List<InventoryVector> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT hash FROM Inventory WHERE expires > " + now() +
 | 
			
		||||
                    " AND stream IN (" + join(streams) + ")");
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
@@ -54,8 +54,8 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
    }
 | 
			
		||||
    private List<InventoryVector> getFullInventory(long... streams) {
 | 
			
		||||
        List<InventoryVector> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT hash FROM Inventory WHERE stream IN (" + join(streams) + ")");
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                result.add(new InventoryVector(rs.getBytes("hash")));
 | 
			
		||||
@@ -74,8 +74,8 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ObjectMessage getObject(InventoryVector vector) {
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = X'" + vector + "'");
 | 
			
		||||
            if (rs.next()) {
 | 
			
		||||
                Blob data = rs.getBlob("data");
 | 
			
		||||
@@ -92,7 +92,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<ObjectMessage> getObjects(long stream, long version, ObjectType... types) {
 | 
			
		||||
        try {
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            StringBuilder query = new StringBuilder("SELECT data, version FROM Inventory WHERE 1=1");
 | 
			
		||||
            if (stream > 0) {
 | 
			
		||||
                query.append(" AND stream = ").append(stream);
 | 
			
		||||
@@ -103,7 +103,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
            if (types.length > 0) {
 | 
			
		||||
                query.append(" AND type IN (").append(join(types)).append(")");
 | 
			
		||||
            }
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery(query.toString());
 | 
			
		||||
            List<ObjectMessage> result = new LinkedList<>();
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
@@ -119,8 +119,8 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void storeObject(ObjectMessage object) {
 | 
			
		||||
        try {
 | 
			
		||||
            PreparedStatement ps = getConnection().prepareStatement("INSERT INTO Inventory (hash, stream, expires, data, type, version) VALUES (?, ?, ?, ?, ?, ?)");
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            PreparedStatement ps = connection.prepareStatement("INSERT INTO Inventory (hash, stream, expires, data, type, version) VALUES (?, ?, ?, ?, ?, ?)");
 | 
			
		||||
            InventoryVector iv = object.getInventoryVector();
 | 
			
		||||
            LOG.trace("Storing object " + iv);
 | 
			
		||||
            ps.setBytes(1, iv.getHash());
 | 
			
		||||
@@ -139,9 +139,9 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void cleanup() {
 | 
			
		||||
        try {
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            // We delete only objects that expired 5 minutes ago or earlier, so we don't request objects we just deleted
 | 
			
		||||
            getConnection().createStatement().executeUpdate("DELETE FROM Inventory WHERE expires < " + (now() - 300));
 | 
			
		||||
            connection.createStatement().executeUpdate("DELETE FROM Inventory WHERE expires < " + (now() - 300));
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            LOG.debug(e.getMessage(), e);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.BitmessageAddress;
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label;
 | 
			
		||||
import ch.dissem.bitmessage.ports.MessageRepository;
 | 
			
		||||
import ch.dissem.bitmessage.utils.Strings;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
@@ -37,17 +36,21 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
 | 
			
		||||
    private InternalContext ctx;
 | 
			
		||||
 | 
			
		||||
    public JdbcMessageRepository(JdbcConfig config) {
 | 
			
		||||
        super(config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Label> getLabels() {
 | 
			
		||||
        List<Label> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label ORDER BY ord");
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                result.add(getLabel(rs));
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            LOG.error(e.getMessage(), e);
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
@@ -67,9 +70,9 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Label> getLabels(Label.Type... types) {
 | 
			
		||||
        List<Label> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE type IN (" + Strings.join(types) +
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE type IN (" + join(types) +
 | 
			
		||||
                    ") ORDER BY ord");
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                result.add(getLabel(rs));
 | 
			
		||||
@@ -97,8 +100,8 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
 | 
			
		||||
    private List<Plaintext> find(String where) {
 | 
			
		||||
        List<Plaintext> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, sender, recipient, data, sent, received, status FROM Message WHERE " + where);
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                Blob data = rs.getBlob("data");
 | 
			
		||||
@@ -110,7 +113,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
                builder.sent(rs.getLong("sent"));
 | 
			
		||||
                builder.received(rs.getLong("received"));
 | 
			
		||||
                builder.status(Plaintext.Status.valueOf(rs.getString("status")));
 | 
			
		||||
                builder.labels(findLabels(id));
 | 
			
		||||
                builder.labels(findLabels(connection, id));
 | 
			
		||||
                result.add(builder.build());
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException | SQLException e) {
 | 
			
		||||
@@ -119,10 +122,10 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Collection<Label> findLabels(long messageId) {
 | 
			
		||||
    private Collection<Label> findLabels(Connection connection, long messageId) {
 | 
			
		||||
        List<Label> result = new ArrayList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT id, label, type, color FROM Label WHERE id IN (SELECT label_id FROM Message_Label WHERE message_id=" + messageId + ")");
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                result.add(getLabel(rs));
 | 
			
		||||
@@ -146,34 +149,37 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Connection connection = getConnection();
 | 
			
		||||
        try {
 | 
			
		||||
            connection.setAutoCommit(false);
 | 
			
		||||
            // save message
 | 
			
		||||
            if (message.getId() == null) {
 | 
			
		||||
                insert(connection, message);
 | 
			
		||||
 | 
			
		||||
                // remove existing labels
 | 
			
		||||
                Statement stmt = connection.createStatement();
 | 
			
		||||
                stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId());
 | 
			
		||||
            } else {
 | 
			
		||||
                update(connection, message);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // save labels
 | 
			
		||||
            PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + message.getId() + ", ?)");
 | 
			
		||||
            for (Label label : message.getLabels()) {
 | 
			
		||||
                ps.setLong(1, (Long) label.getId());
 | 
			
		||||
                ps.executeUpdate();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            connection.commit();
 | 
			
		||||
        } catch (IOException | SQLException e) {
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            try {
 | 
			
		||||
                connection.rollback();
 | 
			
		||||
            } catch (SQLException e1) {
 | 
			
		||||
                LOG.debug(e1.getMessage(), e);
 | 
			
		||||
                connection.setAutoCommit(false);
 | 
			
		||||
                // save message
 | 
			
		||||
                if (message.getId() == null) {
 | 
			
		||||
                    insert(connection, message);
 | 
			
		||||
 | 
			
		||||
                    // remove existing labels
 | 
			
		||||
                    Statement stmt = connection.createStatement();
 | 
			
		||||
                    stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId());
 | 
			
		||||
                } else {
 | 
			
		||||
                    update(connection, message);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // save labels
 | 
			
		||||
                PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + message.getId() + ", ?)");
 | 
			
		||||
                for (Label label : message.getLabels()) {
 | 
			
		||||
                    ps.setLong(1, (Long) label.getId());
 | 
			
		||||
                    ps.executeUpdate();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                connection.commit();
 | 
			
		||||
            } catch (IOException | SQLException e) {
 | 
			
		||||
                try {
 | 
			
		||||
                    connection.rollback();
 | 
			
		||||
                } catch (SQLException e1) {
 | 
			
		||||
                    LOG.debug(e1.getMessage(), e);
 | 
			
		||||
                }
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -204,18 +210,15 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
 | 
			
		||||
                "UPDATE Message SET sent=?, received=?, status=? WHERE id=?");
 | 
			
		||||
        ps.setLong(1, message.getSent());
 | 
			
		||||
        ps.setLong(2, message.getReceived());
 | 
			
		||||
        ps.setLong(3, (Long) message.getId());
 | 
			
		||||
        if (message.getStatus() != null)
 | 
			
		||||
            ps.setString(3, message.getStatus().name());
 | 
			
		||||
        else
 | 
			
		||||
            ps.setString(3, null);
 | 
			
		||||
        ps.setString(3, message.getStatus() != null ? message.getStatus().name() : null);
 | 
			
		||||
        ps.setLong(4, (Long) message.getId());
 | 
			
		||||
        ps.executeUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void remove(Plaintext message) {
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            stmt.executeUpdate("DELETE FROM Message WHERE id = " + message.getId());
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            LOG.error(e.getMessage(), e);
 | 
			
		||||
 
 | 
			
		||||
@@ -25,28 +25,27 @@ import java.sql.*;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static ch.dissem.bitmessage.utils.Strings.join;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 24.04.15.
 | 
			
		||||
 */
 | 
			
		||||
public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(JdbcNodeRegistry.class);
 | 
			
		||||
 | 
			
		||||
    public JdbcNodeRegistry(JdbcConfig config) {
 | 
			
		||||
        super(config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
 | 
			
		||||
        List<NetworkAddress> result = new LinkedList<>();
 | 
			
		||||
        try {
 | 
			
		||||
            Statement stmt = getConnection().createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT * FROM Node WHERE stream IN (" + join(streams) + ")");
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            Statement stmt = connection.createStatement();
 | 
			
		||||
            ResultSet rs = stmt.executeQuery("SELECT * FROM Node WHERE stream IN (" + join(streams) + ") LIMIT " + limit);
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
//                result.add(new NetworkAddress.Builder()
 | 
			
		||||
//                        .ipv6(rs.getBytes("ip"))
 | 
			
		||||
//                        .port(rs.getByte("port"))
 | 
			
		||||
//                        .services(rs.getLong("services"))
 | 
			
		||||
//                        .stream(rs.getLong("stream"))
 | 
			
		||||
//                        .time(rs.getLong("time"))
 | 
			
		||||
//                        .build());
 | 
			
		||||
                result.add(new NetworkAddress.Builder()
 | 
			
		||||
                        .ipv6(rs.getBytes("ip"))
 | 
			
		||||
                        .port(rs.getInt("port"))
 | 
			
		||||
                        .services(rs.getLong("services"))
 | 
			
		||||
                        .stream(rs.getLong("stream"))
 | 
			
		||||
                        .time(rs.getLong("time"))
 | 
			
		||||
                        .build());
 | 
			
		||||
            }
 | 
			
		||||
        } catch (SQLException e) {
 | 
			
		||||
            LOG.error(e.getMessage(), e);
 | 
			
		||||
@@ -60,8 +59,7 @@ public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void offerAddresses(List<NetworkAddress> addresses) {
 | 
			
		||||
        try {
 | 
			
		||||
            Connection connection = getConnection();
 | 
			
		||||
        try (Connection connection = config.getConnection()) {
 | 
			
		||||
            PreparedStatement exists = connection.prepareStatement("SELECT port FROM Node WHERE ip = ? AND port = ? AND stream = ?");
 | 
			
		||||
            PreparedStatement insert = connection.prepareStatement(
 | 
			
		||||
                    "INSERT INTO Node (ip, port, services, stream, time) VALUES (?, ?, ?, ?, ?)");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.valueobject.PrivateKey;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
public class JdbcAddressRepositoryTest {
 | 
			
		||||
    public static final String CONTACT_A = "BM-2cW7cD5cDQJDNkE7ibmyTxfvGAmnPqa9Vt";
 | 
			
		||||
    public static final String CONTACT_B = "BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj";
 | 
			
		||||
    public static final String CONTACT_C = "BM-2cV5f9EpzaYARxtoruSpa6pDoucSf9ZNke";
 | 
			
		||||
    public String IDENTITY_A;
 | 
			
		||||
    public String IDENTITY_B;
 | 
			
		||||
 | 
			
		||||
    private TestJdbcConfig config;
 | 
			
		||||
    private JdbcAddressRepository repo;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() throws InterruptedException {
 | 
			
		||||
        config = new TestJdbcConfig();
 | 
			
		||||
        config.reset();
 | 
			
		||||
 | 
			
		||||
        repo = new JdbcAddressRepository(config);
 | 
			
		||||
 | 
			
		||||
        repo.save(new BitmessageAddress(CONTACT_A));
 | 
			
		||||
        repo.save(new BitmessageAddress(CONTACT_B));
 | 
			
		||||
        repo.save(new BitmessageAddress(CONTACT_C));
 | 
			
		||||
 | 
			
		||||
        BitmessageAddress identityA = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000));
 | 
			
		||||
        repo.save(identityA);
 | 
			
		||||
        IDENTITY_A = identityA.getAddress();
 | 
			
		||||
        BitmessageAddress identityB = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000));
 | 
			
		||||
        repo.save(identityB);
 | 
			
		||||
        IDENTITY_B = identityB.getAddress();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindContact() throws Exception {
 | 
			
		||||
        BitmessageAddress address = new BitmessageAddress(CONTACT_A);
 | 
			
		||||
        assertEquals(4, address.getVersion());
 | 
			
		||||
        assertEquals(address, repo.findContact(address.getTag()));
 | 
			
		||||
        assertNull(repo.findIdentity(address.getTag()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindIdentity() throws Exception {
 | 
			
		||||
        BitmessageAddress identity = new BitmessageAddress(IDENTITY_A);
 | 
			
		||||
        assertEquals(4, identity.getVersion());
 | 
			
		||||
        assertEquals(identity, repo.findIdentity(identity.getTag()));
 | 
			
		||||
        assertNull(repo.findContact(identity.getTag()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetIdentities() throws Exception {
 | 
			
		||||
        List<BitmessageAddress> identities = repo.getIdentities();
 | 
			
		||||
        assertEquals(2, identities.size());
 | 
			
		||||
        for (BitmessageAddress identity : identities) {
 | 
			
		||||
            assertNotNull(identity.getPrivateKey());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetSubscriptions() throws Exception {
 | 
			
		||||
        List<BitmessageAddress> subscriptions = repo.getSubscriptions();
 | 
			
		||||
        assertEquals(0, subscriptions.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetContacts() throws Exception {
 | 
			
		||||
        List<BitmessageAddress> contacts = repo.getContacts();
 | 
			
		||||
        assertEquals(3, contacts.size());
 | 
			
		||||
        for (BitmessageAddress contact : contacts) {
 | 
			
		||||
            assertNull(contact.getPrivateKey());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureNewAddressIsSaved() throws Exception {
 | 
			
		||||
        repo.save(new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000)));
 | 
			
		||||
        List<BitmessageAddress> identities = repo.getIdentities();
 | 
			
		||||
        assertEquals(3, identities.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureExistingAddressIsUpdated() throws Exception {
 | 
			
		||||
        BitmessageAddress address = repo.getAddress(CONTACT_A);
 | 
			
		||||
        address.setAlias("Test-Alias");
 | 
			
		||||
        repo.save(address);
 | 
			
		||||
        address = repo.getAddress(address.getAddress());
 | 
			
		||||
        assertEquals("Test-Alias", address.getAlias());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testRemove() throws Exception {
 | 
			
		||||
        BitmessageAddress address = repo.getAddress(IDENTITY_A);
 | 
			
		||||
        repo.remove(address);
 | 
			
		||||
        assertNull(repo.getAddress(IDENTITY_A));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetAddress() throws Exception {
 | 
			
		||||
        BitmessageAddress address = repo.getAddress(IDENTITY_A);
 | 
			
		||||
        assertNotNull(address);
 | 
			
		||||
        assertNotNull(address.getPrivateKey());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
 | 
			
		||||
public class JdbcHelperTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    public void ensureJoinWorksWithLongArray() {
 | 
			
		||||
        long[] test = {1L, 2L};
 | 
			
		||||
        assertEquals("1, 2", JdbcHelper.join(test).toString());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,132 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.ObjectMessage;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.GetPubkey;
 | 
			
		||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
 | 
			
		||||
import ch.dissem.bitmessage.ports.Inventory;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static ch.dissem.bitmessage.entity.payload.ObjectType.GET_PUBKEY;
 | 
			
		||||
import static ch.dissem.bitmessage.entity.payload.ObjectType.MSG;
 | 
			
		||||
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
 | 
			
		||||
import static ch.dissem.bitmessage.utils.UnixTime.now;
 | 
			
		||||
import static org.junit.Assert.*;
 | 
			
		||||
 | 
			
		||||
public class JdbcInventoryTest {
 | 
			
		||||
    private TestJdbcConfig config;
 | 
			
		||||
    private Inventory inventory;
 | 
			
		||||
 | 
			
		||||
    private InventoryVector inventoryVector1;
 | 
			
		||||
    private InventoryVector inventoryVector2;
 | 
			
		||||
    private InventoryVector inventoryVectorIgnore;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() throws Exception {
 | 
			
		||||
        config = new TestJdbcConfig();
 | 
			
		||||
        config.reset();
 | 
			
		||||
 | 
			
		||||
        inventory = new JdbcInventory(config);
 | 
			
		||||
 | 
			
		||||
        ObjectMessage object1 = getObjectMessage(1, 300, getGetPubkey());
 | 
			
		||||
        inventoryVector1 = object1.getInventoryVector();
 | 
			
		||||
        inventory.storeObject(object1);
 | 
			
		||||
 | 
			
		||||
        ObjectMessage object2 = getObjectMessage(2, 300, getGetPubkey());
 | 
			
		||||
        inventoryVector2 = object2.getInventoryVector();
 | 
			
		||||
        inventory.storeObject(object2);
 | 
			
		||||
 | 
			
		||||
        ObjectMessage ignore = getObjectMessage(1, -1 * DAY, getGetPubkey());
 | 
			
		||||
        inventoryVectorIgnore = ignore.getInventoryVector();
 | 
			
		||||
        inventory.storeObject(ignore);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetInventory() throws Exception {
 | 
			
		||||
        List<InventoryVector> inventoryVectors = inventory.getInventory(1);
 | 
			
		||||
        assertEquals(1, inventoryVectors.size());
 | 
			
		||||
 | 
			
		||||
        inventoryVectors = inventory.getInventory(2);
 | 
			
		||||
        assertEquals(1, inventoryVectors.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetMissing() throws Exception {
 | 
			
		||||
        InventoryVector newIV = getObjectMessage(1, 200, getGetPubkey()).getInventoryVector();
 | 
			
		||||
        List<InventoryVector> offer = new LinkedList<>();
 | 
			
		||||
        offer.add(newIV);
 | 
			
		||||
        offer.add(inventoryVector1);
 | 
			
		||||
        List<InventoryVector> missing = inventory.getMissing(offer, 1, 2);
 | 
			
		||||
        assertEquals(1, missing.size());
 | 
			
		||||
        assertEquals(newIV, missing.get(0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetObject() throws Exception {
 | 
			
		||||
        ObjectMessage object = inventory.getObject(inventoryVectorIgnore);
 | 
			
		||||
        assertNotNull(object);
 | 
			
		||||
        assertEquals(1, object.getStream());
 | 
			
		||||
        assertEquals(inventoryVectorIgnore, object.getInventoryVector());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetObjects() throws Exception {
 | 
			
		||||
        List<ObjectMessage> objects = inventory.getObjects(1, 4);
 | 
			
		||||
        assertEquals(2, objects.size());
 | 
			
		||||
 | 
			
		||||
        objects = inventory.getObjects(1, 4, GET_PUBKEY);
 | 
			
		||||
        assertEquals(2, objects.size());
 | 
			
		||||
 | 
			
		||||
        objects = inventory.getObjects(1, 4, MSG);
 | 
			
		||||
        assertEquals(0, objects.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testStoreObject() throws Exception {
 | 
			
		||||
        ObjectMessage object = getObjectMessage(5, 0, getGetPubkey());
 | 
			
		||||
        inventory.storeObject(object);
 | 
			
		||||
 | 
			
		||||
        assertNotNull(inventory.getObject(object.getInventoryVector()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCleanup() throws Exception {
 | 
			
		||||
        assertNotNull(inventory.getObject(inventoryVectorIgnore));
 | 
			
		||||
        inventory.cleanup();
 | 
			
		||||
        assertNull(inventory.getObject(inventoryVectorIgnore));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ObjectMessage getObjectMessage(long stream, long TTL, ObjectPayload payload) {
 | 
			
		||||
        return new ObjectMessage.Builder()
 | 
			
		||||
                .nonce(new byte[8])
 | 
			
		||||
                .expiresTime(now(+TTL))
 | 
			
		||||
                .stream(stream)
 | 
			
		||||
                .payload(payload)
 | 
			
		||||
                .build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private GetPubkey getGetPubkey() {
 | 
			
		||||
        return new GetPubkey(new BitmessageAddress("BM-2cW7cD5cDQJDNkE7ibmyTxfvGAmnPqa9Vt"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,155 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.BitmessageContext;
 | 
			
		||||
import ch.dissem.bitmessage.InternalContext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
 | 
			
		||||
import ch.dissem.bitmessage.entity.Plaintext;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.Label;
 | 
			
		||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
 | 
			
		||||
import ch.dissem.bitmessage.ports.AddressRepository;
 | 
			
		||||
import ch.dissem.bitmessage.ports.MessageRepository;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertNotNull;
 | 
			
		||||
 | 
			
		||||
public class JdbcMessageRepositoryTest {
 | 
			
		||||
    private BitmessageAddress contactA;
 | 
			
		||||
    private BitmessageAddress contactB;
 | 
			
		||||
    private BitmessageAddress identity;
 | 
			
		||||
 | 
			
		||||
    private TestJdbcConfig config;
 | 
			
		||||
    private AddressRepository addressRepo;
 | 
			
		||||
    private MessageRepository repo;
 | 
			
		||||
 | 
			
		||||
    private Label inbox;
 | 
			
		||||
    private Label drafts;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() throws Exception {
 | 
			
		||||
        config = new TestJdbcConfig();
 | 
			
		||||
        config.reset();
 | 
			
		||||
        addressRepo = new JdbcAddressRepository(config);
 | 
			
		||||
        repo = new JdbcMessageRepository(config);
 | 
			
		||||
        new InternalContext(new BitmessageContext.Builder().addressRepo(addressRepo).messageRepo(repo));
 | 
			
		||||
 | 
			
		||||
        BitmessageAddress tmp = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000));
 | 
			
		||||
        contactA = new BitmessageAddress(tmp.getAddress());
 | 
			
		||||
        contactA.setPubkey(tmp.getPubkey());
 | 
			
		||||
        addressRepo.save(contactA);
 | 
			
		||||
        contactB = new BitmessageAddress("BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj");
 | 
			
		||||
        addressRepo.save(contactB);
 | 
			
		||||
 | 
			
		||||
        identity = new BitmessageAddress(new PrivateKey(false, 1, 1000, 1000));
 | 
			
		||||
        addressRepo.save(identity);
 | 
			
		||||
 | 
			
		||||
        inbox = repo.getLabels(Label.Type.INBOX).get(0);
 | 
			
		||||
        drafts = repo.getLabels(Label.Type.DRAFTS).get(0);
 | 
			
		||||
 | 
			
		||||
        addMessage(contactA, identity, Plaintext.Status.RECEIVED, inbox);
 | 
			
		||||
        addMessage(identity, contactA, Plaintext.Status.DRAFT, drafts);
 | 
			
		||||
        addMessage(identity, contactB, Plaintext.Status.DRAFT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetLabels() throws Exception {
 | 
			
		||||
        List<Label> labels = repo.getLabels();
 | 
			
		||||
        assertEquals(5, labels.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetLabelsByType() throws Exception {
 | 
			
		||||
        List<Label> labels = repo.getLabels(Label.Type.INBOX);
 | 
			
		||||
        assertEquals(1, labels.size());
 | 
			
		||||
        assertEquals("Inbox", labels.get(0).toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindMessagesByLabel() throws Exception {
 | 
			
		||||
        List<Plaintext> messages = repo.findMessages(inbox);
 | 
			
		||||
        assertEquals(1, messages.size());
 | 
			
		||||
        Plaintext m = messages.get(0);
 | 
			
		||||
        assertEquals(contactA, m.getFrom());
 | 
			
		||||
        assertEquals(identity, m.getTo());
 | 
			
		||||
        assertEquals(Plaintext.Status.RECEIVED, m.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindMessagesByStatus() throws Exception {
 | 
			
		||||
        List<Plaintext> messages = repo.findMessages(Plaintext.Status.RECEIVED);
 | 
			
		||||
        assertEquals(1, messages.size());
 | 
			
		||||
        Plaintext m = messages.get(0);
 | 
			
		||||
        assertEquals(contactA, m.getFrom());
 | 
			
		||||
        assertEquals(identity, m.getTo());
 | 
			
		||||
        assertEquals(Plaintext.Status.RECEIVED, m.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindMessagesByStatusAndRecipient() throws Exception {
 | 
			
		||||
        List<Plaintext> messages = repo.findMessages(Plaintext.Status.DRAFT, contactB);
 | 
			
		||||
        assertEquals(1, messages.size());
 | 
			
		||||
        Plaintext m = messages.get(0);
 | 
			
		||||
        assertEquals(identity, m.getFrom());
 | 
			
		||||
        assertEquals(contactB, m.getTo());
 | 
			
		||||
        assertEquals(Plaintext.Status.DRAFT, m.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSave() throws Exception {
 | 
			
		||||
        Plaintext message = new Plaintext.Builder()
 | 
			
		||||
                .from(identity)
 | 
			
		||||
                .to(contactA)
 | 
			
		||||
                .message("Subject", "Message")
 | 
			
		||||
                .status(Plaintext.Status.DOING_PROOF_OF_WORK)
 | 
			
		||||
                .build();
 | 
			
		||||
        repo.save(message);
 | 
			
		||||
 | 
			
		||||
        assertNotNull(message.getId());
 | 
			
		||||
 | 
			
		||||
        message.addLabels(inbox);
 | 
			
		||||
        repo.save(message);
 | 
			
		||||
 | 
			
		||||
        List<Plaintext> messages = repo.findMessages(Plaintext.Status.DOING_PROOF_OF_WORK);
 | 
			
		||||
 | 
			
		||||
        assertEquals(1, messages.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testRemove() throws Exception {
 | 
			
		||||
        Plaintext toRemove = repo.findMessages(Plaintext.Status.DRAFT, contactB).get(0);
 | 
			
		||||
        repo.remove(toRemove);
 | 
			
		||||
        List<Plaintext> messages = repo.findMessages(Plaintext.Status.DRAFT);
 | 
			
		||||
        assertEquals(1, messages.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addMessage(BitmessageAddress from, BitmessageAddress to, Plaintext.Status status, Label... labels) {
 | 
			
		||||
        Plaintext message = new Plaintext.Builder()
 | 
			
		||||
                .from(from)
 | 
			
		||||
                .to(to)
 | 
			
		||||
                .message("Subject", "Message")
 | 
			
		||||
                .status(status)
 | 
			
		||||
                .labels(Arrays.asList(labels))
 | 
			
		||||
                .build();
 | 
			
		||||
        repo.save(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.valueobject.NetworkAddress;
 | 
			
		||||
import ch.dissem.bitmessage.ports.NodeRegistry;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static ch.dissem.bitmessage.utils.UnixTime.now;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
 | 
			
		||||
public class JdbcNodeRegistryTest {
 | 
			
		||||
    private TestJdbcConfig config;
 | 
			
		||||
    private NodeRegistry registry;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() throws Exception {
 | 
			
		||||
        config = new TestJdbcConfig();
 | 
			
		||||
        config.reset();
 | 
			
		||||
        registry = new JdbcNodeRegistry(config);
 | 
			
		||||
 | 
			
		||||
        registry.offerAddresses(Arrays.asList(
 | 
			
		||||
                createAddress(1, 8444, 1, now()),
 | 
			
		||||
                createAddress(2, 8444, 1, now()),
 | 
			
		||||
                createAddress(3, 8444, 1, now())
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetKnownAddresses() throws Exception {
 | 
			
		||||
        List<NetworkAddress> knownAddresses = registry.getKnownAddresses(2, 1);
 | 
			
		||||
        assertEquals(2, knownAddresses.size());
 | 
			
		||||
 | 
			
		||||
        knownAddresses = registry.getKnownAddresses(1000, 1);
 | 
			
		||||
        assertEquals(3, knownAddresses.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testOfferAddresses() throws Exception {
 | 
			
		||||
        registry.offerAddresses(Arrays.asList(
 | 
			
		||||
                createAddress(1, 8444, 1, now()),
 | 
			
		||||
                createAddress(10, 8444, 1, now()),
 | 
			
		||||
                createAddress(11, 8444, 1, now())
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        List<NetworkAddress> knownAddresses = registry.getKnownAddresses(1000, 1);
 | 
			
		||||
        assertEquals(5, knownAddresses.size());
 | 
			
		||||
 | 
			
		||||
        registry.offerAddresses(Arrays.asList(
 | 
			
		||||
                createAddress(1, 8445, 1, now())
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        knownAddresses = registry.getKnownAddresses(1000, 1);
 | 
			
		||||
        assertEquals(6, knownAddresses.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private NetworkAddress createAddress(int lastByte, int port, long stream, long time) {
 | 
			
		||||
        return new NetworkAddress.Builder()
 | 
			
		||||
                .ipv6(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, lastByte)
 | 
			
		||||
                .port(port)
 | 
			
		||||
                .stream(stream)
 | 
			
		||||
                .time(time)
 | 
			
		||||
                .build();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Created by chris on 02.06.15.
 | 
			
		||||
 */
 | 
			
		||||
public class TestJdbcConfig extends JdbcConfig {
 | 
			
		||||
    public TestJdbcConfig() {
 | 
			
		||||
        super("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void reset() {
 | 
			
		||||
        flyway.clean();
 | 
			
		||||
        flyway.migrate();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user