diff --git a/configurations/evaluation/settingsProphet.txt b/configurations/evaluation/settingsProphet.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0a2d1365bd247123ca3decf6cc3da1cca7cd500f
--- /dev/null
+++ b/configurations/evaluation/settingsProphet.txt
@@ -0,0 +1,4 @@
+# Add this file as argument if you want to use ProphetRouter
+
+Group.router = ProphetRouter
+ProphetRouter.secondsInTimeUnit = 30
\ No newline at end of file
diff --git a/src/routing/ProphetRouter.java b/src/routing/ProphetRouter.java
index 40738cdf632e9b0dbca0c6cf4ff3f340f8fb0461..11ce70e23adcfac74a98379daec708a489d109ff 100644
--- a/src/routing/ProphetRouter.java
+++ b/src/routing/ProphetRouter.java
@@ -12,6 +12,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import core.DataMessage;
+import core.MulticastMessage;
+import routing.util.DatabaseApplicationUtil;
 import routing.util.RoutingInfo;
 
 import util.Tuple;
@@ -55,7 +58,7 @@ public class ProphetRouter extends ActiveRouter {
 	private double beta;
 
 	/** delivery predictabilities */
-	private Map<DTNHost, Double> preds;
+	private Map<Integer, Double> preds;
 	/** last delivery predictability update (sim)time */
 	private double lastAgeUpdate;
 
@@ -93,7 +96,7 @@ public class ProphetRouter extends ActiveRouter {
 	 * Initializes predictability hash
 	 */
 	private void initPreds() {
-		this.preds = new HashMap<DTNHost, Double>();
+        this.preds = new HashMap<>();
 	}
 
 	@Override
@@ -115,9 +118,45 @@ public class ProphetRouter extends ActiveRouter {
 	private void updateDeliveryPredFor(DTNHost host) {
 		double oldValue = getPredFor(host);
 		double newValue = oldValue + (1 - oldValue) * P_INIT;
-		preds.put(host, newValue);
+		preds.put(host.getAddress(), newValue);
 	}
 
+    /**
+     * Returns the current prediction (P) value for a message or 0 if no entry for any recipient exists.
+     * @param message Message to find P for. Either a one-to-one message or a multicast.
+     * @return The current P value. In case of multicast, the maximum P value of remaining recipients.
+     */
+    private double getPredFor(Message message) {
+        switch (message.getType()) {
+            case ONE_TO_ONE:
+                return this.getPredFor(message.getTo());
+            case MULTICAST:
+                MulticastMessage multicast = (MulticastMessage)message;
+                return this.getMaxPredFor(multicast.getRemainingRecipients());
+            default:
+                throw new IllegalArgumentException(
+                        "No delivery predictability for messages of type " + message.getType() + " defined!");
+        }
+    }
+
+    /**
+     * Returns the maximum prediction (P) value for all hosts matching the provided addresses. If no such P values
+     * exist, returns 0.
+     * @param addresses The addresses to check.
+     * @return The maximum P value.
+     */
+    private double getMaxPredFor(Collection<Integer> addresses) {
+        // Make sure preds are updated once before getting.
+        this.ageDeliveryPreds();
+
+        double maxPred = 0;
+        for (int address : addresses) {
+            double predForAddress = this.preds.getOrDefault(address, 0D);
+            maxPred = Math.max(maxPred, predForAddress);
+        }
+        return maxPred;
+    }
+
 	/**
 	 * Returns the current prediction (P) value for a host or 0 if entry for
 	 * the host doesn't exist.
@@ -125,15 +164,21 @@ public class ProphetRouter extends ActiveRouter {
 	 * @return the current P value
 	 */
 	public double getPredFor(DTNHost host) {
-		ageDeliveryPreds(); // make sure preds are updated before getting
-		if (preds.containsKey(host)) {
-			return preds.get(host);
-		}
-		else {
-			return 0;
-		}
+        return this.getPredFor(host.getAddress());
 	}
 
+    /**
+     * Returns the current prediction (P) value for a host address or 0 if entry for
+     * the host doesn't exist.
+     * @param address The host address to look the P for
+     * @return the current P value
+     */
+    private double getPredFor(Integer address) {
+        // make sure preds are updated before getting
+        this.ageDeliveryPreds();
+        return preds.getOrDefault(address, 0D);
+    }
+
 	/**
 	 * Updates transitive (A->B->C) delivery predictions.
 	 * <CODE>P(a,c) = P(a,c)_old + (1 - P(a,c)_old) * P(a,b) * P(b,c) * BETA
@@ -146,11 +191,11 @@ public class ProphetRouter extends ActiveRouter {
 			" with other routers of same type";
 
 		double pForHost = getPredFor(host); // P(a,b)
-		Map<DTNHost, Double> othersPreds =
+		Map<Integer, Double> othersPreds =
 			((ProphetRouter)otherRouter).getDeliveryPreds();
 
-		for (Map.Entry<DTNHost, Double> e : othersPreds.entrySet()) {
-			if (e.getKey() == getHost()) {
+		for (Map.Entry<Integer, Double> e : othersPreds.entrySet()) {
+			if (e.getKey().equals(getHost().getAddress())) {
 				continue; // don't add yourself
 			}
 
@@ -175,7 +220,7 @@ public class ProphetRouter extends ActiveRouter {
 		}
 
 		double mult = Math.pow(GAMMA, timeDiff);
-		for (Map.Entry<DTNHost, Double> e : preds.entrySet()) {
+		for (Map.Entry<Integer, Double> e : preds.entrySet()) {
 			e.setValue(e.getValue()*mult);
 		}
 
@@ -186,7 +231,7 @@ public class ProphetRouter extends ActiveRouter {
 	 * Returns a map of this router's delivery predictions
 	 * @return a map of this router's delivery predictions
 	 */
-	private Map<DTNHost, Double> getDeliveryPreds() {
+	private Map<Integer, Double> getDeliveryPreds() {
 		ageDeliveryPreds(); // make sure the aging is done
 		return this.preds;
 	}
@@ -206,6 +251,16 @@ public class ProphetRouter extends ActiveRouter {
 		tryOtherMessages();
 	}
 
+    /**
+     * Checks whether this router has anything to send out.
+     *
+     * @return Whether or not the router has anything to send out.
+     */
+    @Override
+    protected boolean hasNothingToSend() {
+        return DatabaseApplicationUtil.hasNoMessagesToSend(this);
+	}
+
 	/**
 	 * Tries to send all other messages to all connected hosts ordered by
 	 * their delivery probability
@@ -219,6 +274,7 @@ public class ProphetRouter extends ActiveRouter {
 
 		/* for all connected hosts collect all messages that have a higher
 		   probability of delivery by the other host */
+		List<Connection> availableConnections = new ArrayList<>();
 		for (Connection con : getConnections()) {
 			DTNHost other = con.getOtherNode(getHost());
 			ProphetRouter othRouter = (ProphetRouter)other.getRouter();
@@ -226,18 +282,23 @@ public class ProphetRouter extends ActiveRouter {
 			if (othRouter.isTransferring()) {
 				continue; // skip hosts that are transferring
 			}
+			availableConnections.add(con);
 
 			for (Message m : msgCollection) {
 				if (othRouter.hasMessage(m.getId())) {
 					continue; // skip messages that the other one has
 				}
-				if (othRouter.getPredFor(m.getTo()) > getPredFor(m.getTo())) {
+				if (othRouter.getPredFor(m) > getPredFor(m)) {
 					// the other node has higher probability of delivery
 					messages.add(new Tuple<Message, Connection>(m,con));
 				}
 			}
 		}
 
+		/* For all available connections, add useful data messages. */
+		messages.addAll(DatabaseApplicationUtil.wrapUsefulDataIntoMessages(
+		        this, this.getHost(), availableConnections));
+
 		if (messages.size() == 0) {
 			return null;
 		}
@@ -248,37 +309,44 @@ public class ProphetRouter extends ActiveRouter {
 	}
 
 	/**
-	 * Comparator for Message-Connection-Tuples that orders the tuples by
-	 * their delivery probability by the host on the other side of the
-	 * connection (GRTRMax)
+	 * Comparator for Message-Connection-Tuples that orders the tuples by the utility computed by
+     * {@link #computeUtility(Tuple)}, higher utilities first.
 	 */
 	private class TupleComparator implements Comparator
 		<Tuple<Message, Connection>> {
 
 		public int compare(Tuple<Message, Connection> tuple1,
 				Tuple<Message, Connection> tuple2) {
-			// delivery probability of tuple1's message with tuple1's connection
-			double p1 = ((ProphetRouter)tuple1.getValue().
-					getOtherNode(getHost()).getRouter()).getPredFor(
-					tuple1.getKey().getTo());
-			// -"- tuple2...
-			double p2 = ((ProphetRouter)tuple2.getValue().
-					getOtherNode(getHost()).getRouter()).getPredFor(
-					tuple2.getKey().getTo());
-
-			// bigger probability should come first
-			if (p2-p1 == 0) {
-				/* equal probabilities -> let queue mode decide */
+            double utility1 = this.computeUtility(tuple1);
+            double utility2 = this.computeUtility(tuple2);
+
+            // bigger utility should come first
+            int utilityComparison = (-1) * Double.compare(utility1, utility2);
+            if (utilityComparison == 0) {
+                /* equal utilities -> let queue mode decide */
 				return compareByQueueMode(tuple1.getKey(), tuple2.getKey());
 			}
-			else if (p2-p1 < 0) {
-				return -1;
-			}
-			else {
-				return 1;
-			}
+            return utilityComparison;
 		}
-	}
+
+        /**
+         * Computes a utility value for a Message-Connection tuple. This is
+         * - either the delivery probability by the host on the other side of the connection (GRTRMax) if the message is
+         *   not a data message, or
+         * - the data message's utility.
+         * @param tuple Tuple to compute utility for.
+         * @return The tuple's utility.
+         */
+        private double computeUtility(Tuple<Message, Connection> tuple) {
+            Message message = tuple.getKey();
+            if (message instanceof DataMessage) {
+                return ((DataMessage) message).getUtility();
+            }
+
+            DTNHost neighbor = tuple.getValue().getOtherNode(getHost());
+            return ((ProphetRouter)neighbor.getRouter()).getPredFor(message);
+        }
+    }
 
 	@Override
 	public RoutingInfo getRoutingInfo() {
@@ -287,12 +355,12 @@ public class ProphetRouter extends ActiveRouter {
 		RoutingInfo ri = new RoutingInfo(preds.size() +
 				" delivery prediction(s)");
 
-		for (Map.Entry<DTNHost, Double> e : preds.entrySet()) {
-			DTNHost host = e.getKey();
+		for (Map.Entry<Integer, Double> e : preds.entrySet()) {
+			Integer hostAddress = e.getKey();
 			Double value = e.getValue();
 
 			ri.addMoreInfo(new RoutingInfo(String.format("%s : %.6f",
-					host, value)));
+					hostAddress, value)));
 		}
 
 		top.addMoreInfo(ri);
diff --git a/src/test/AbstractReportTest.java b/src/test/AbstractReportTest.java
index 971f4b5a4c1d68ef7ba32b8c149dbc5af1abe997..174e3e97c5bed5237b6026c48f4ff2bedad67e58 100644
--- a/src/test/AbstractReportTest.java
+++ b/src/test/AbstractReportTest.java
@@ -1,5 +1,6 @@
 package test;
 
+import core.Group;
 import core.SimClock;
 import org.junit.After;
 import org.junit.Before;
@@ -53,6 +54,16 @@ public abstract class AbstractReportTest {
         this.outputFile.delete();
     }
 
+    @After
+    public void resetGroups() {
+        Group.clearGroups();
+    }
+
+    @After
+    public void resetSimClock() {
+        SimClock.reset();
+    }
+
     /**
      * Checks that the report correctly handles the warm up time as set by the {@link Report#WARMUP_S} setting.
      */
diff --git a/src/test/AbstractRouterTest.java b/src/test/AbstractRouterTest.java
index 433d749dc6e8b3d5d80ab2ee0259e337a6a1980a..b40f47f260e537861f8244c9ad51b21940c9e73d 100644
--- a/src/test/AbstractRouterTest.java
+++ b/src/test/AbstractRouterTest.java
@@ -84,6 +84,7 @@ public abstract class AbstractRouterTest extends TestCase {
     protected void tearDown() throws Exception {
         super.tearDown();
         Settings.init(null);
+        SimClock.reset();
     }
 
 	protected void setRouterProto(MessageRouter r) {
diff --git a/src/test/ActivenessHandlerTest.java b/src/test/ActivenessHandlerTest.java
index 49af953f70008dbb1e4ec9a687ba9d8234be35b9..9ce05176e02839e819ed295ff7a3dfe6be8a9773 100644
--- a/src/test/ActivenessHandlerTest.java
+++ b/src/test/ActivenessHandlerTest.java
@@ -24,6 +24,11 @@ public class ActivenessHandlerTest extends TestCase {
 				moreTimes);
 		ah = new ActivenessHandler(ts);
 		clock = SimClock.getInstance();
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
 		SimClock.reset();
 	}
 
diff --git a/src/test/ConnectionTest.java b/src/test/ConnectionTest.java
index dfdc68a53f9fb633da8bb490af40e1cc33c6d35e..8faeb692be84db9e0b5864a54bb1faa69de1edb9 100644
--- a/src/test/ConnectionTest.java
+++ b/src/test/ConnectionTest.java
@@ -32,7 +32,6 @@ public class ConnectionTest extends TestCase {
 
 	protected void setUp() throws Exception {
 		super.setUp();
-		SimClock.reset();
 		clock.setTime(START_TIME);
 		TestSettings testSettings = new TestSettings();
 		testSettings.setNameSpace(TestUtils.IFACE_NS);
@@ -65,6 +64,12 @@ public class ConnectionTest extends TestCase {
 		conCount = 3;
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	private void con(DTNHost from, DTNHost to) {
 		c[index] = new CBRConnection(from, from.getInterfaces().get(0), to, to.getInterfaces().get(0), speed[index]);
 		index++;
diff --git a/src/test/ContactTimesReportTest.java b/src/test/ContactTimesReportTest.java
index 2e708b8766a861e6418c4dd3671075f498de5115..a757c65e91a51360f951b32e2b1c49a72a3c069e 100644
--- a/src/test/ContactTimesReportTest.java
+++ b/src/test/ContactTimesReportTest.java
@@ -72,6 +72,12 @@ public class ContactTimesReportTest extends TestCase {
 
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	private void generateConnections(TestUtils utils) {
 		Coord c1 = new Coord(0,0);
 		Coord c2 = new Coord(1,0);
diff --git a/src/test/DistanceDelayReportTest.java b/src/test/DistanceDelayReportTest.java
index 614add0e9311b8ed889a75d1e781c28161e94e4f..432b124d6366311a02404c145b9f0a9e9d88dc09 100644
--- a/src/test/DistanceDelayReportTest.java
+++ b/src/test/DistanceDelayReportTest.java
@@ -44,6 +44,12 @@ public class DistanceDelayReportTest extends TestCase {
 		this.utils = new TestUtils(null, ml, ts);
 	}
 
+	@Override
+	protected void tearDown() throws Exception{
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	@Test
 	public void testMessageTransferred() throws IOException {
 		DTNHost h1 = utils.createHost(new Coord(0,0));
diff --git a/src/test/ExternalMovementTest.java b/src/test/ExternalMovementTest.java
index 1cdc4509da2f8e76677abd11be341dc0f67f7f7d..7e8f83c4b1aac6d1a8148a98c672571daf854db8 100644
--- a/src/test/ExternalMovementTest.java
+++ b/src/test/ExternalMovementTest.java
@@ -79,6 +79,12 @@ public class ExternalMovementTest extends TestCase {
 		clock.setTime(0);
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	public void testMovement() throws Exception {
 		setUpUsing(INPUT);
 
diff --git a/src/test/GroupTest.java b/src/test/GroupTest.java
index 8069545a493d46fff074f08bb557e30418320ae5..bae1212c0dc92b6eed1472e7a029f58d707ac310 100644
--- a/src/test/GroupTest.java
+++ b/src/test/GroupTest.java
@@ -5,7 +5,7 @@ import core.DTNHost;
 import core.Group;
 import core.MessageListener;
 import junit.framework.TestCase;
-import org.junit.Before;
+import org.junit.After;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -21,8 +21,8 @@ public class GroupTest {
     private TestUtils utils = new TestUtils(new ArrayList<ConnectionListener>(),
             new ArrayList<MessageListener>(), new TestSettings());
 
-    @Before
-    public void setUp(){
+    @After
+    public void tearDown(){
         Group.clearGroups();
         DTNHost.reset();
     }
diff --git a/src/test/ImmediateMessageDelayReportTest.java b/src/test/ImmediateMessageDelayReportTest.java
index b1c19e50c5ad1da9a0ee8347c2b42506fb6d1bdb..54a1f466ae9535469d031c256f1d1d9e73b32c42 100644
--- a/src/test/ImmediateMessageDelayReportTest.java
+++ b/src/test/ImmediateMessageDelayReportTest.java
@@ -86,11 +86,12 @@ public class ImmediateMessageDelayReportTest extends AbstractReportTest {
     }
 
     /**
-     * Resets the clock to 0.
+     * Resets the clock to 0 and clears all groups.
      */
     @After
-    public void resetClock() {
+    public void tearDown() {
         this.clock.setTime(0);
+        Group.clearGroups();
     }
 
     /***
diff --git a/src/test/MessageRouterTest.java b/src/test/MessageRouterTest.java
index 02fc9080dc7553f48eb3e0c88f88286e8639b83d..dc4119ad48ebe60ccd84cdb5ab162504b814846d 100644
--- a/src/test/MessageRouterTest.java
+++ b/src/test/MessageRouterTest.java
@@ -8,6 +8,7 @@ import core.Group;
 import core.Message;
 import core.MessageListener;
 import core.MulticastMessage;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -47,7 +48,6 @@ public class MessageRouterTest {
 
     @Before
     public void setUp() {
-        Group.clearGroups();
         TestSettings ts = new TestSettings();
         ts.putSetting(MessageRouter.B_SIZE_S, ""+BUFFER_SIZE);
         List<MessageListener> mListener = new ArrayList<>(1);
@@ -69,6 +69,11 @@ public class MessageRouterTest {
         this.multicast = new MulticastMessage(sender, g,"G",DEFAULT_MESSAGE_SIZE);
     }
 
+    @After
+    public void tearDown() {
+        Group.clearGroups();
+    }
+
     @Test
     public void testMessageTransferredForNonRecipientPutsMessageIntoBufferButNotIntoDelivered() {
         DTNHost nonRecipient = this.utils.createHost();
diff --git a/src/test/MessageStatsReportTest.java b/src/test/MessageStatsReportTest.java
index aeee40aab359355cbf3b302186e2c340e652ef8e..967ae4a62851f80e36a41df4b3995b7581d415c7 100644
--- a/src/test/MessageStatsReportTest.java
+++ b/src/test/MessageStatsReportTest.java
@@ -41,7 +41,6 @@ public class MessageStatsReportTest {
     public void init() throws IOException{
         SimScenario.reset();
         DTNHost.reset();
-        Group.clearGroups();
         Settings.init(null);
         java.util.Locale.setDefault(java.util.Locale.US);
 
@@ -68,6 +67,7 @@ public class MessageStatsReportTest {
         // Cleanup to make further tests with other settings possible.
         SimScenario.reset();
         DTNHost.reset();
+        Group.clearGroups();
     }
 
     private void playScenario() {
diff --git a/src/test/MessageTest.java b/src/test/MessageTest.java
index d3a6c003b4b71875c056675ed436c41593eadac3..eb3294ee727ce6069c2805be29b49a964150f7c2 100644
--- a/src/test/MessageTest.java
+++ b/src/test/MessageTest.java
@@ -48,6 +48,12 @@ public class MessageTest extends TestCase {
         msg.setTtl(10);
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        SimClock.reset();
+    }
+
     @Test
     public void testGetTtl() {
         assertEquals(10, msg.getTtl());
diff --git a/src/test/MessageTransferAcceptPolicyTest.java b/src/test/MessageTransferAcceptPolicyTest.java
index 27b8f6ebcf5fc20b8f071b1adb2c0d613f10e963..530004b103f75b4d4104f1fb7637ede36da69582 100644
--- a/src/test/MessageTransferAcceptPolicyTest.java
+++ b/src/test/MessageTransferAcceptPolicyTest.java
@@ -8,6 +8,7 @@ import core.DisasterData;
 import core.Group;
 import core.Message;
 import core.MulticastMessage;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import routing.util.MessageTransferAcceptPolicy;
@@ -53,7 +54,6 @@ public class MessageTransferAcceptPolicyTest {
 
     @Before
     public void init() {
-        Group.clearGroups();
         DTNHost.reset();
         this.settings = new TestSettings();
         TestUtils utils = new TestUtils(
@@ -83,6 +83,11 @@ public class MessageTransferAcceptPolicyTest {
         this.setAcceptableRecipientAddress(this.recipient.getAddress());
     }
 
+    @After
+    public void tearDown() {
+        Group.clearGroups();
+    }
+
     @Test
     public void testAcceptSendingReturnsTrueForMessageAdheringToSimplePolicies() {
         MessageTransferAcceptPolicy policy = new MessageTransferAcceptPolicy(this.settings);
diff --git a/src/test/MulticastCreateEventTest.java b/src/test/MulticastCreateEventTest.java
index 8bd37f1f4484b591791cb083f14ccc6651ebda72..05ced8a3f95ba52745e1fe2a5f43d50997a40a7d 100644
--- a/src/test/MulticastCreateEventTest.java
+++ b/src/test/MulticastCreateEventTest.java
@@ -6,6 +6,7 @@ import core.Message;
 import core.MulticastMessage;
 import input.ExternalEvent;
 import input.MulticastCreateEvent;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -20,11 +21,15 @@ public class MulticastCreateEventTest extends AbstractMessageCreateEventTest {
     
     @Before
     public void createGroup(){
-        Group.clearGroups();
         Group g = Group.createGroup(0);
         g.addHost(creator);
     }
 
+    @After
+    public void tearDown() {
+        Group.clearGroups();
+    }
+
     @Test
     public void testProcessEventCreatesMulticastMessageWithCorrectGroupAddress() {
         int groupAddress = 0;
diff --git a/src/test/MulticastDeliveryReportTest.java b/src/test/MulticastDeliveryReportTest.java
index d886350751e88ee2b895721217ae7970ddbc637c..79770af5ca239072092460e3cc6bc865b509402f 100644
--- a/src/test/MulticastDeliveryReportTest.java
+++ b/src/test/MulticastDeliveryReportTest.java
@@ -68,8 +68,6 @@ public class MulticastDeliveryReportTest extends AbstractReportTest {
         // Let base do the basic report setup.
         super.setUp();
 
-        Group.clearGroups();
-
         // Set clock to 0.
         this.clock.setTime(0);
 
@@ -84,8 +82,9 @@ public class MulticastDeliveryReportTest extends AbstractReportTest {
     }
 
     @After
-    public void resetClock(){
+    public void tearDown(){
         clock.setTime(0);
+        Group.clearGroups();
     }
 
     @Test
diff --git a/src/test/MulticastEventGeneratorTest.java b/src/test/MulticastEventGeneratorTest.java
index 9b4998f1d028745c5ef89b751a0ae5f536c29e51..b8180577eb7bd2b2e8822cdd85c50a2e1243035b 100644
--- a/src/test/MulticastEventGeneratorTest.java
+++ b/src/test/MulticastEventGeneratorTest.java
@@ -8,6 +8,7 @@ import core.SimScenario;
 import input.AbstractMessageEventGenerator;
 import input.MulticastCreateEvent;
 import input.MulticastEventGenerator;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -34,7 +35,6 @@ public class MulticastEventGeneratorTest extends AbstractMessageEventGeneratorTe
     public void init(){
         super.init();
         SimScenario.reset();
-        Group.clearGroups();
         DTNHost.reset();
         TestSettings.addSettingsToEnableSimScenario(this.settings);
 
@@ -52,6 +52,11 @@ public class MulticastEventGeneratorTest extends AbstractMessageEventGeneratorTe
         settings.putSetting(MulticastEventGenerator.GROUP_SIZE_RANGE_S,MIN_GROUP_SIZE+", "+MAX_GROUP_SIZE);
     }
 
+    @After
+    public void tearDown() {
+        Group.clearGroups();
+    }
+
     @Test
     public void testNextEventCreatesMulticastMessages() {
         AbstractMessageEventGenerator generator = new MulticastEventGenerator(this.settings);
diff --git a/src/test/MulticastMessageTest.java b/src/test/MulticastMessageTest.java
index 097a7f668d293f6df5ed9a432ce6118ca5c5cf95..9fc108c399d32fbe0254c608552d2f3335a8e809 100644
--- a/src/test/MulticastMessageTest.java
+++ b/src/test/MulticastMessageTest.java
@@ -7,6 +7,7 @@ import core.Message;
 import core.MessageListener;
 import core.MulticastMessage;
 import core.SimError;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -48,13 +49,17 @@ public class MulticastMessageTest {
 
     @Before
     public void setUp()  {
-        Group.clearGroups();
         this.group1 = Group.createGroup(GROUP_ADDRESS_1);
         this.group1.addHost(from);
         msg = new MulticastMessage(from, this.group1, "M", MESSAGE_SIZE);
         msgPrio = new MulticastMessage(from, this.group1, "N", MESSAGE_SIZE, PRIORITY);
     }
 
+    @After
+    public void tearDown() {
+        Group.clearGroups();
+    }
+
     @Test(expected = java.lang.UnsupportedOperationException.class)
     public void testGetToThrowsException() {
         this.msg.getTo();
diff --git a/src/test/ProphetRouterTest.java b/src/test/ProphetRouterTest.java
index bc251e5c52da4d619f533560b4cb6c95802d2a68..66699483a4f0e4d0a6e8cf688217cd68510333d9 100644
--- a/src/test/ProphetRouterTest.java
+++ b/src/test/ProphetRouterTest.java
@@ -4,11 +4,23 @@
  */
 package test;
 
+import applications.DatabaseApplication;
+import core.BroadcastMessage;
+import core.Coord;
+import core.DTNHost;
+import core.DisasterData;
+import core.Group;
+import core.MulticastMessage;
+import core.SimClock;
+import org.junit.Assert;
 import org.junit.Test;
 import routing.MessageRouter;
 import routing.ProphetRouter;
 import core.Message;
 
+import java.util.Arrays;
+import java.util.HashSet;
+
 /**
  * Tests for PRoPHET router
  */
@@ -16,16 +28,33 @@ public class ProphetRouterTest extends AbstractRouterTest {
 
 	private static int SECONDS_IN_TIME_UNIT = 60;
 
+	private static final double ONE_HOUR = 60 * 60D;
+	private static final double ONE_DAY = 24 * ONE_HOUR;
+	private static final double ONE_WEEK = 7 * ONE_DAY;
+
+	private static final Coord FAR_AWAY_LOCATION = new Coord(30_000, 40_000);
+
 	@Override
 	public void setUp() throws Exception {
 		ts.putSetting(MessageRouter.B_SIZE_S, ""+BUFFER_SIZE);
 		ts.putSetting(ProphetRouter.PROPHET_NS + "." +
 				ProphetRouter.SECONDS_IN_UNIT_S , SECONDS_IN_TIME_UNIT+"");
 		setRouterProto(new ProphetRouter(ts));
+        DatabaseApplicationTest.addDatabaseApplicationSettings(ts);
 		super.setUp();
 	}
 
-	/**
+    /**
+     * Tears down the fixture, for example, close a network connection.
+     * This method is called after a test is executed.
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Group.clearGroups();
+    }
+
+    /**
 	 * Tests normal routing
 	 */
 	@Test
@@ -122,6 +151,173 @@ public class ProphetRouterTest extends AbstractRouterTest {
 
 	}
 
+    /**
+     * Checks that {@link ProphetRouter} correctly sorts direct messages, broadcasts, non-direct one-to-one messages,
+     * direct and non-direct multicasts, and data messages.
+     */
+    public void testPrioritization() {
+        // Create groups for multicasts.
+        Group directGroup = ProphetRouterTest.createGroup(0, this.h1, this.h2);
+        Group indirectGroup = ProphetRouterTest.createGroup(1, this.h1, this.h3, this.h4);
+
+        // Create all kinds of messages.
+        Message broadcast = new BroadcastMessage(this.h1, "B1", 0);
+        Message directMessage = new Message(this.h1, this.h2, "M1", 0);
+        Message nonDirectMessage = new Message(this.h1, this.h3, "M2", 0);
+        Message nonDirectMessage2 = new Message(this.h1, this.h5, "M3", 0);
+        Message directMulticast = new MulticastMessage(this.h1, directGroup, "m1", 0);
+        Message indirectMulticast = new MulticastMessage(this.h1, indirectGroup, "m2", 0);
+        this.h1.createNewMessage(broadcast);
+        this.h1.createNewMessage(directMessage);
+        this.h1.createNewMessage(nonDirectMessage);
+        this.h1.createNewMessage(nonDirectMessage2);
+        this.h1.createNewMessage(directMulticast);
+        this.h1.createNewMessage(indirectMulticast);
+
+        // Add data for data message.
+        this.clock.advance(ONE_DAY);
+        DisasterData data =
+                new DisasterData(DisasterData.DataType.MARKER, 0, 0, this.h1.getLocation());
+        DatabaseApplication app = this.createDatabaseApplicationFor(this.h1);
+        app.disasterDataCreated(h1, data);
+
+        // Modify utilities for testing:
+        // First, increase delivery predictability H2 --> H5, then advance clock to lower it again.
+        this.h2.connect(this.h5);
+        this.clock.advance(ONE_HOUR);
+        // Then, do the same for delivery predictability H2 --> H4.
+        this.h2.connect(this.h4);
+        this.clock.advance(ONE_HOUR);
+        // Finally, make sure the delivery predictability H2 --> H3 is high
+        this.h2.connect(this.h3);
+        disconnect(this.h2);
+        // And ensure that the multicast message was already delivered to H3.
+        ProphetRouterTest.addNodeOnPath(this.h1, indirectMulticast.getId(), this.h3);
+
+        // Connect h1 to h2.
+        this.h1.connect(this.h2);
+
+        // Check order of messages: First direct messages, then sorted by predictability / data utility
+        // Direct messages are pseudo-randomly sorted, so you might have to change the order if changing the clock.
+        String dataMessageId = "D" + Arrays.asList(data).hashCode();
+        String[] idsInExpectedOrder = {
+                broadcast.getId(), directMessage.getId(), directMulticast.getId(),
+                nonDirectMessage.getId(), dataMessageId, indirectMulticast.getId(), nonDirectMessage2.getId()
+        };
+        this.checkMessagesAreSentInOrder(idsInExpectedOrder);
+    }
+
+	/**
+	 * Checks that {@link ProphetRouter} sends {@link core.DataMessage}s wrapping useful data, but data with too low
+	 * utility is not sent.
+	 */
+	public void testUsefulDataGetsExchanged() {
+        // Add data.
+        DatabaseApplication app = this.createDatabaseApplicationFor(this.h1);
+        this.clock.advance(ONE_WEEK);
+        this.h1.setLocation(FAR_AWAY_LOCATION);
+        DisasterData uselessData = new DisasterData(DisasterData.DataType.MARKER, 0, 0, new Coord(0, 0));
+        DisasterData usefulData =
+                new DisasterData(DisasterData.DataType.MARKER, 0, SimClock.getTime(), this.h1.getLocation());
+        app.disasterDataCreated(this.h1, uselessData);
+        app.disasterDataCreated(this.h1, usefulData);
+
+        // Check that H1 only sends the useful data item to H2.
+        this.h1.connect(this.h2);
+        this.mc.reset();
+        h1.update(false);
+        do {
+            this.mc.next();
+        } while (!this.mc.TYPE_START.equals(this.mc.getLastType()));
+        Assert.assertEquals(
+                "Expected the useful data item to be sent.",
+                "D" + Arrays.asList(usefulData).hashCode(), mc.getLastMsg().getId());
+        Assert.assertFalse("Did not expect any additional message.", this.mc.next());
+	}
+
+    /**
+     * Checks that both one-to-one messages and multicast messages are only transferred to a neighbor if those messages
+     * have higher delivery predictability at the neighbor than at the current host.
+     */
+	public void testMessagesAreOnlyTransferredToHostsWithHigherPredictability() {
+	    // Make sure H1 has higher delivery predictability for H3, while H2 has higher delivery predictability for H4.
+        // First, increase delivery predictability H1 --> H4, then advance clock to lower it again.
+        this.h1.connect(this.h4);
+        this.clock.advance(ONE_HOUR);
+        // Then set high delivery predictabilities for H1 --> H3 and H2 --> H4.
+        this.h1.connect(this.h3);
+        this.h2.connect(this.h4);
+        disconnect(this.h1);
+        disconnect(this.h2);
+
+        // Create group including both H3 and H4.
+        Group group = ProphetRouterTest.createGroup(0, this.h1, this.h3, this.h4);
+
+        // Create multicasts and one to one messages to H3 and H4.
+        Message messageToH3 = new Message(this.h1, this.h3, "M1", 0);
+        Message messageToH4 = new Message(this.h1, this.h4, "M2", 0);
+        Message receivedMulticast = new MulticastMessage(this.h1, group, "m1", 0);
+        Message newMulticast = new MulticastMessage(this.h1, group, "m2", 0);
+        this.h1.createNewMessage(messageToH3);
+        this.h1.createNewMessage(messageToH4);
+        this.h1.createNewMessage(receivedMulticast);
+        this.h1.createNewMessage(newMulticast);
+
+        // Ensure that one of the multicast messages was already delivered to H4.
+        ProphetRouterTest.addNodeOnPath(this.h1, receivedMulticast.getId(), this.h4);
+
+        // Connect h1 to h2.
+        this.h1.connect(this.h2);
+
+        // Check that only half of the messages are transferred
+        HashSet<String> sentIds = new HashSet<>();
+        this.mc.reset();
+        this.h1.update(true);
+        while (this.mc.next()) {
+            sentIds.add(this.mc.getLastMsg().getId());
+            this.h1.update(true);
+        }
+        HashSet<String> expectedIds = new HashSet<>(2);
+        expectedIds.add(messageToH4.getId());
+        expectedIds.add(newMulticast.getId());
+        assertEquals("Expected different message set to be sent.", sentIds, expectedIds);
+    }
+
+    /**
+     * Checks that a host does not send out new messages to hosts which are already transferring.
+     */
+    public void testNoMessagesAreReceivedWhenAlreadyTransferring() {
+        // Let h2 be transferring.
+        this.h2.connect(this.h3);
+        Message m1 = new Message(this.h2, this.h3, "M1", 1);
+        this.h2.createNewMessage(m1);
+        this.updateAllNodes();
+
+        // Check the transfer started.
+        this.mc.next();
+        this.checkTransferStart(this.h2, this.h3, m1.getId());
+
+        // Let h1 try to send a message to h2 now.
+        Message m2 = new Message(this.h1, this.h2, "M2", 0);
+        this.h1.createNewMessage(m2);
+        this.h1.connect(this.h2);
+        this.updateAllNodes();
+
+        // Check that the new message was not sent.
+        while(this.mc.next()) {
+            Assert.assertNotEquals("Did not expect another transfer.", this.mc.TYPE_START, this.mc.getLastType());
+        }
+
+        // Finally, check that the original message will still be transferred.
+        this.clock.advance(1);
+        this.updateAllNodes();
+        this.mc.next();
+        Assert.assertEquals(
+                "Original message should have been processed next.", m1.getId(), this.mc.getLastMsg().getId());
+        Assert.assertEquals(
+                "Original message should have been transferred.", this.mc.TYPE_RELAY, this.mc.getLastType());
+    }
+
 	private void doRelay() {
 		clock.advance(10);
 		updateAllNodes();
@@ -153,4 +349,60 @@ public class ProphetRouterTest extends AbstractRouterTest {
 		assertEquals(newPred, r5.getPredFor(h4));
 	}
 
+    /**
+     * Observes which messages are sent by {@link #h1} and checks they match the provided IDs.
+     * @param idsInExpectedOrder The expected message IDs in expected order.
+     */
+	private void checkMessagesAreSentInOrder(String[] idsInExpectedOrder) {
+        this.mc.reset();
+        for (String expectedId : idsInExpectedOrder) {
+            this.h1.update(true);
+            do {
+                this.mc.next();
+            } while (!this.mc.TYPE_START.equals(this.mc.getLastType()));
+            Assert.assertEquals("Expected different message.", expectedId, mc.getLastMsg().getId());
+        }
+    }
+
+    /**
+     * Creates a group using the provided number as address.
+     * All provided hosts will be part of the group.
+     * @param address The new group's address.
+     * @param hosts The hosts in the new group.
+     * @return The created group.
+     */
+	private static Group createGroup(int address, DTNHost... hosts) {
+        Group group = Group.createGroup(address);
+        for (DTNHost host : hosts) {
+            group.addHost(host);
+        }
+        return group;
+    }
+
+    /**
+     * Creates and initializes a {@link DatabaseApplication} for the provided {@link DTNHost}.
+     * @param host Host to create the application for.
+     * @return The created application.
+     */
+    private DatabaseApplication createDatabaseApplicationFor(DTNHost host) {
+        DatabaseApplication app = new DatabaseApplication(this.ts);
+        host.getRouter().addApplication(app);
+        app.update(host);
+        return app;
+    }
+
+    /**
+     * Changes the meta data of the message with provided ID in the buffer of the provided host by adding the provided
+     * node to path.
+     * @param bufferToChange The host in which buffer the message should be changed.
+     * @param messageId The message's ID.
+     * @param node The host to add to path.
+     */
+    private static void addNodeOnPath(DTNHost bufferToChange, String messageId, DTNHost node) {
+        for (Message m : bufferToChange.getMessageCollection()) {
+            if (m.getId().equals(messageId)) {
+                m.addNodeOnPath(node);
+            }
+        }
+    }
 }
diff --git a/src/test/ScheduledUpdatesQueueTest.java b/src/test/ScheduledUpdatesQueueTest.java
index 43c11e609b236e5f9054d80d65c0989f44320b2a..08be166f122268a372f5dd1af6a7c8eec8260138 100644
--- a/src/test/ScheduledUpdatesQueueTest.java
+++ b/src/test/ScheduledUpdatesQueueTest.java
@@ -18,10 +18,15 @@ public class ScheduledUpdatesQueueTest extends TestCase {
 
 	protected void setUp() throws Exception {
 		super.setUp();
-		SimClock.reset();
 		suq = new ScheduledUpdatesQueue();
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	public void testUpdates() {
 		assertEquals(MAX, suq.nextEventsTime());
 		suq.addUpdate(1);
diff --git a/src/test/TotalContactTimeReportTest.java b/src/test/TotalContactTimeReportTest.java
index 9cfe62952ce8c6621e2385eb604f7041493d7d54..eeb4287eb9d74affb2864ba364898c8859508b36 100644
--- a/src/test/TotalContactTimeReportTest.java
+++ b/src/test/TotalContactTimeReportTest.java
@@ -36,7 +36,6 @@ public class TotalContactTimeReportTest extends TestCase {
 	protected void setUp() throws Exception {
 		java.util.Locale.setDefault(java.util.Locale.US);
 		super.setUp();
-		SimClock.reset();
 		outFile = File.createTempFile("cttest", ".tmp");
 		outFile.deleteOnExit();
 
@@ -61,6 +60,12 @@ public class TotalContactTimeReportTest extends TestCase {
 		h3 = utils.createHost(c3);
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	private void done() throws Exception {
 		ctr.done();
 		ctReader = new BufferedReader(new FileReader(outFile));
diff --git a/src/test/VhmBehaviorTest.java b/src/test/VhmBehaviorTest.java
index 63993b3fcc95d2ccae3d7f577707dd04068006b5..85072b38128d6c951ba41f2d92b2f5db856dfe86 100644
--- a/src/test/VhmBehaviorTest.java
+++ b/src/test/VhmBehaviorTest.java
@@ -9,6 +9,7 @@ import movement.CarMovement;
 import movement.PanicMovement;
 import movement.ShortestPathMapBasedMovement;
 import movement.VoluntaryHelperMovement;
+import org.junit.After;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -43,6 +44,11 @@ public class VhmBehaviorTest {
         vhm = VhmTestHelper.createMinimalVhm(testSettings,host);
     }
 
+    @After
+    public void tearDown() {
+        SimClock.reset();
+    }
+
     @Test
     public void testSetHostSetsHost(){
         assertEquals("Host was not set as expected",host,vhm.getHost());
diff --git a/src/test/WorldTest.java b/src/test/WorldTest.java
index a70de35d9cc922d3e9d95e732f7e9a28209eb0a3..1eab16bd202c8b33475fed95df026b9d3da56da1 100644
--- a/src/test/WorldTest.java
+++ b/src/test/WorldTest.java
@@ -35,7 +35,6 @@ public class WorldTest extends TestCase {
 
 	protected void setUp() throws Exception {
 		super.setUp();
-		SimClock.reset();
 		TestSettings testSettings = new TestSettings();
 		testSettings.setNameSpace(TestUtils.IFACE_NS);
 		testSettings.putSetting(NetworkInterface.TRANSMIT_RANGE_S, "1.0");
@@ -59,6 +58,12 @@ public class WorldTest extends TestCase {
 				ts.getExternalEvents() );
 	}
 
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		SimClock.reset();
+	}
+
 	public void testUpdate() {
 		double endTime = 1000;
 		int nrofRounds = (int)(endTime/upInterval);