Index: protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java	(revision 34)
@@ -14,6 +14,41 @@
 	}
 
+	public CurrentNegoState(NegoState state, Long now) {
+		super(now);
+		this.state = state;
+	}
+
 	public NegoState getState() {
 		return state;
 	}
+
+	@Override
+	public String toString() {
+		return "CurrentNegoState[" + getTime() + "," + state + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = super.hashCode();
+		result = prime * result + ((state == null) ? 0 : state.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (!super.equals(obj))
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		CurrentNegoState other = (CurrentNegoState) obj;
+		if (state == null) {
+			if (other.state != null)
+				return false;
+		} else if (!state.equals(other.state))
+			return false;
+		return true;
+	}
 }
Index: protocol/src/main/java/geniusweb/protocol/ProtocolException.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/ProtocolException.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/ProtocolException.java	(revision 34)
@@ -14,5 +14,7 @@
 	 * @param message the error message
 	 * @param party   offending party, either the {@link PartyId} or a
-	 *                {@link PartyRef}
+	 *                {@link PartyRef}. In exceptional cases this can be null,
+	 *                eg if it can not be determined which party failed. Null
+	 *                should be avoided if possible at all.
 	 */
 	public ProtocolException(String message, PartyId party) {
@@ -29,5 +31,7 @@
 	 * 
 	 * @param message the error message
-	 * @param party   offending {@link PartyId}
+	 * @param party   offending {@link PartyId}. In exceptional cases this can
+	 *                be null, eg if it can not be determined which party
+	 *                failed. Null should be avoided if possible at all.
 	 * @param e       the cause of the error
 	 */
@@ -39,5 +43,6 @@
 	/**
 	 * 
-	 * @return offending party, either the {@link PartyId} or a {@link PartyRef}
+	 * @return offending party, either the {@link PartyId} or a
+	 *         {@link PartyRef}. In exceptional cases this can be null.
 	 */
 	public PartyId getParty() {
Index: protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java	(revision 34)
@@ -65,15 +65,15 @@
 			this.partyprofiles = Collections.emptyMap();
 		} else {
-			this.partyprofiles = partyprofiles;
+			this.partyprofiles = new HashMap<>(partyprofiles);
 		}
 		if (conns == null) {
 			this.connections = Collections.emptyList();
 		} else {
-			this.connections = conns;
+			this.connections = new LinkedList<>(conns);
 		}
 		if (actions == null) {
 			this.actions = new LinkedList<>();
 		} else {
-			this.actions = actions;
+			this.actions = new LinkedList<>(actions);
 		}
 
@@ -115,5 +115,5 @@
 	 */
 	public List<PartyId> getConnections() {
-		return connections;
+		return Collections.unmodifiableList(connections);
 	}
 
@@ -124,5 +124,5 @@
 	 */
 	public Map<PartyId, PartyWithProfile> getPartyProfiles() {
-		return partyprofiles;
+		return Collections.unmodifiableMap(partyprofiles);
 	}
 
Index: protocol/src/main/java/geniusweb/protocol/session/SessionResult.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionResult.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionResult.java	(revision 34)
@@ -2,4 +2,5 @@
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
@@ -49,7 +50,7 @@
 			@JsonProperty("penalties") Map<PartyId, Double> penalties,
 			@JsonProperty("error") Throwable error) {
-		this.participants = participants;
+		this.participants = new HashMap<>(participants);
 		this.agreements = agreements;
-		this.penalties = penalties;
+		this.penalties = new HashMap<>(penalties);
 		this.error = error;
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/SessionState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 34)
@@ -60,7 +60,6 @@
 	/**
 	 * 
-	 * @return the current standing agreement, or null if there is no agreement
-	 *         at this point. An agreement does not necessarily mean
-	 *         {@link #isFinal(long)}.
+	 * @return the current standing {@link Agreements}. An agreement does not
+	 *         necessarily mean {@link #isFinal(long)}.
 	 */
 	Agreements getAgreements();
Index: protocol/src/main/java/geniusweb/protocol/session/TeamInfo.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/TeamInfo.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/TeamInfo.java	(revision 34)
@@ -49,5 +49,5 @@
 	 *         teams combined.
 	 */
-	public List<PartyWithProfile> getAllParties() {
+	public List<PartyWithProfile> getParties() {
 		return Collections.unmodifiableList(parties);
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/amop/AMOPSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/amop/AMOPSettings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/amop/AMOPSettings.java	(revision 34)
@@ -70,5 +70,5 @@
 	public List<PartyWithProfile> getAllParties() {
 		return participants.stream()
-				.map(particip -> particip.getAllParties().get(0))
+				.map(particip -> particip.getParties().get(0))
 				.collect(Collectors.toList());
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/learn/LearnSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/learn/LearnSettings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/learn/LearnSettings.java	(revision 34)
@@ -119,5 +119,5 @@
 	public List<PartyWithProfile> getAllParties() {
 		return participants.stream()
-				.map(particip -> particip.getAllParties().get(0))
+				.map(particip -> particip.getParties().get(0))
 				.collect(Collectors.toList());
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/mopac/MOPACSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/mopac/MOPACSettings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/mopac/MOPACSettings.java	(revision 34)
@@ -74,5 +74,5 @@
 	public List<PartyWithProfile> getAllParties() {
 		return participants.stream()
-				.map(particip -> particip.getAllParties().get(0))
+				.map(particip -> particip.getParties().get(0))
 				.collect(Collectors.toList());
 	}
@@ -155,5 +155,5 @@
 				throw new IllegalArgumentException(
 						"All teams must be size 1 but found " + team);
-			PartyWithProfile party = team.getAllParties().get(0);
+			PartyWithProfile party = team.getParties().get(0);
 			Object power = party.getParty().getParameters().get("power");
 			if (power != null) {
Index: protocol/src/main/java/geniusweb/protocol/session/mopac2/MOPAC2Settings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/mopac2/MOPAC2Settings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/mopac2/MOPAC2Settings.java	(revision 34)
@@ -75,5 +75,5 @@
 	public List<PartyWithProfile> getAllParties() {
 		return participants.stream()
-				.map(particip -> particip.getAllParties().get(0))
+				.map(particip -> particip.getParties().get(0))
 				.collect(Collectors.toList());
 	}
@@ -157,5 +157,5 @@
 				throw new IllegalArgumentException(
 						"All teams must be size 1 but found " + team);
-			PartyWithProfile party = team.getAllParties().get(0);
+			PartyWithProfile party = team.getParties().get(0);
 			Object power = party.getParty().getParameters().get("power");
 			if (power != null) {
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java	(revision 34)
@@ -326,5 +326,6 @@
 	 * 
 	 * @param message The message to attach to the error
-	 * @param party   the party where the error occured
+	 * @param party   the party where the error occured. Can be null in
+	 *                exceptional cases.
 	 * @param e       the exception that occured.
 	 */
@@ -337,5 +338,6 @@
 			setState(state.with(new ProtocolException(message, party, e)));
 		}
-		setState(state.withoutParty(party));
+		if (party != null)
+			setState(state.withoutParty(party));
 		log.log(Level.WARNING, "SAOP protocol intercepted error due to party "
 				+ party + ":" + message, e);
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java	(revision 34)
@@ -67,5 +67,5 @@
 	public List<PartyWithProfile> getAllParties() {
 		return participants.stream()
-				.map(particip -> particip.getAllParties().get(0))
+				.map(particip -> particip.getParties().get(0))
 				.collect(Collectors.toList());
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 34)
@@ -5,4 +5,7 @@
 import java.util.List;
 import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
 import geniusweb.actions.Accept;
@@ -28,5 +31,5 @@
 	 * 
 	 * @param actions       the actions done by the parties
-	 * @param conns         the existing party connections. If null, default
+	 * @param connections   the existing party connections. If null, default
 	 *                      empty list is used. Can be less than 2 parties in
 	 *                      the first phases of the setup or after parties
@@ -36,11 +39,15 @@
 	 * @param partyprofiles map with the {@link PartyWithProfile} for connected
 	 *                      parties. null is equivalent to an empty map.
-	 * @param e             the {@link ProtocolException}, or null if none
+	 * @param error         the {@link ProtocolException}, or null if none
 	 *                      occurred.
 	 */
-	public SAOPState(List<Action> actions, List<PartyId> conns,
-			Progress progress, SAOPSettings settings,
-			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
-		super(actions, conns, progress, settings, partyprofiles, e);
+	@JsonCreator
+	public SAOPState(@JsonProperty("actions") List<Action> actions,
+			@JsonProperty("connections") List<PartyId> connections,
+			@JsonProperty("progress") Progress progress,
+			@JsonProperty("settings") SAOPSettings settings,
+			@JsonProperty("partyprofiles") Map<PartyId, PartyWithProfile> partyprofiles,
+			@JsonProperty("error") ProtocolException error) {
+		super(actions, connections, progress, settings, partyprofiles, error);
 	}
 
Index: protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOP.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOP.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOP.java	(revision 34)
@@ -166,5 +166,5 @@
 			throws InterruptedException, IOException {
 		List<PartyWithProfile> participants = state.getSettings().getTeams()
-				.stream().map(team -> team.getAllParties())
+				.stream().map(team -> team.getParties())
 				.flatMap(List::stream).collect(Collectors.toList());
 		List<Reference> parties = participants.stream()
Index: protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOPSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOPSettings.java	(revision 33)
+++ protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOPSettings.java	(revision 34)
@@ -46,6 +46,6 @@
 				throw new IllegalArgumentException(
 						"Team must be size 2 but found " + team);
-			allParties.add(team.getAllParties().get(SHAOP));
-			allParties.add(team.getAllParties().get(COB));
+			allParties.add(team.getParties().get(SHAOP));
+			allParties.add(team.getParties().get(COB));
 		}
 	}
@@ -82,5 +82,5 @@
 	@Override
 	public List<PartyWithProfile> getAllParties() {
-		return participants.stream().map(team -> team.getAllParties())
+		return participants.stream().map(team -> team.getParties())
 				.flatMap(Collection::stream).collect(Collectors.toList());
 	}
Index: protocol/src/test/java/geniusweb/protocol/CurrentNegoStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/CurrentNegoStateTest.java	(revision 34)
+++ protocol/src/test/java/geniusweb/protocol/CurrentNegoStateTest.java	(revision 34)
@@ -0,0 +1,50 @@
+package geniusweb.protocol;
+
+import static org.mockito.Mockito.mock;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import geniusweb.actions.Action;
+import geniusweb.actions.PartyId;
+import geniusweb.progress.Progress;
+import geniusweb.progress.ProgressTime;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.protocol.session.saop.SAOPState;
+import tudelft.utilities.junit.GeneralTests;
+
+public class CurrentNegoStateTest extends GeneralTests<CurrentNegoState> {
+	private PartyId party1 = new PartyId("party1");
+	private PartyId party2 = new PartyId("party2");
+	private List<Action> actions1 = new LinkedList<>();
+
+	private List<PartyId> connections = Arrays.asList(party1);
+	private List<PartyId> connections2 = Arrays.asList(party1, party2);
+
+	private Progress progresstime = mock(ProgressTime.class);
+	private SAOPSettings settings = mock(SAOPSettings.class);
+
+	SAOPState saop1 = new SAOPState(actions1, connections2, progresstime,
+			settings, null, null);
+	SAOPState saop2 = new SAOPState(actions1, connections, progresstime,
+			settings, null, null);
+
+	CurrentNegoState state1 = new CurrentNegoState(saop1);
+	CurrentNegoState state1a = new CurrentNegoState(saop1);
+	CurrentNegoState state2 = new CurrentNegoState(saop2);
+
+	@Override
+	public List<List<CurrentNegoState>> getGeneralTestData() {
+		return Arrays.asList(Arrays.asList(state1, state1a),
+				Arrays.asList(state2));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList(
+				"CurrentNegoState.*SAOPState.*party1.*party2.*ProgressTime.*SAOPSettings.*",
+				"CurrentNegoState.*SAOPState.*party1.*ProgressTime.*SAOPSettings.*");
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/ProtocolExceptionTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/ProtocolExceptionTest.java	(revision 34)
+++ protocol/src/test/java/geniusweb/protocol/ProtocolExceptionTest.java	(revision 34)
@@ -0,0 +1,52 @@
+package geniusweb.protocol;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.util.ObjectBuffer;
+
+import geniusweb.actions.PartyId;
+
+public class ProtocolExceptionTest {
+	private ObjectBuffer jackson = new ObjectBuffer();
+	private Exception exception;
+	private String asString1 = "{\"cause\":null,\"stackTrace\":[],\"party\":\"party1\",\"message\":\"party1:test\",\"localizedMessage\":\"party1:test\",\"suppressed\":[]}";
+
+	@Before
+	public void before() {
+		try {
+			throw new ProtocolException("test", new PartyId("party1"));
+			// int x = 1 / 0;
+		} catch (Exception e) {
+			this.exception = e;
+			System.out.println(e);
+		}
+	}
+
+	@Test
+	public void testSerialize() throws JsonProcessingException {
+
+		ObjectMapper jackson = new ObjectMapper();
+		System.out.println(jackson.writeValueAsString(exception));
+		assertEquals(asString1, jackson.writeValueAsString(exception));
+
+	}
+
+	// ProtocolExceptions can not be deserialized now
+	@Ignore
+	@Test
+	public void testDeserialize() throws IOException {
+
+		ObjectMapper jackson = new ObjectMapper();
+		Exception read = jackson.readValue(asString1, ProtocolException.class);
+		assertEquals(exception, read);
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACSettingsTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACSettingsTest.java	(revision 34)
@@ -66,5 +66,5 @@
 		when(team.getSize()).thenReturn(1);
 		PartyWithParameters pwithp = mock(PartyWithParameters.class);
-		when(team.getAllParties()).thenReturn(Arrays
+		when(team.getParties()).thenReturn(Arrays
 				.asList(new PartyWithProfile(pwithp, mock(ProfileRef.class))));
 		when(team.toString()).thenReturn(partyname);
Index: protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac/MOPACStateTest.java	(revision 34)
@@ -87,5 +87,5 @@
 		PartyWithParameters pwithp = mock(PartyWithParameters.class);
 		when(pwithp.getParameters()).thenReturn(new Parameters());
-		when(party.getAllParties()).thenReturn(Arrays
+		when(party.getParties()).thenReturn(Arrays
 				.asList(new PartyWithProfile(pwithp, mock(ProfileRef.class))));
 		when(party.getSize()).thenReturn(1);
Index: protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2SettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2SettingsTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2SettingsTest.java	(revision 34)
@@ -65,5 +65,5 @@
 		when(team.getSize()).thenReturn(1);
 		PartyWithParameters pwithp = mock(PartyWithParameters.class);
-		when(team.getAllParties()).thenReturn(Arrays
+		when(team.getParties()).thenReturn(Arrays
 				.asList(new PartyWithProfile(pwithp, mock(ProfileRef.class))));
 		when(team.toString()).thenReturn(partyname);
Index: protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/mopac2/MOPAC2StateTest.java	(revision 34)
@@ -91,5 +91,5 @@
 		PartyWithParameters pwithp = mock(PartyWithParameters.class);
 		when(pwithp.getParameters()).thenReturn(new Parameters());
-		when(party.getAllParties()).thenReturn(Arrays
+		when(party.getParties()).thenReturn(Arrays
 				.asList(new PartyWithProfile(pwithp, mock(ProfileRef.class))));
 		when(party.getSize()).thenReturn(1);
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 34)
@@ -9,4 +9,6 @@
 import static org.mockito.Mockito.when;
 
+import java.io.IOException;
+import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.Date;
@@ -16,4 +18,7 @@
 import org.junit.Before;
 import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 
 import geniusweb.actions.Accept;
@@ -22,11 +27,19 @@
 import geniusweb.actions.Offer;
 import geniusweb.actions.PartyId;
+import geniusweb.deadline.Deadline;
+import geniusweb.deadline.DeadlineTime;
 import geniusweb.issuevalue.Bid;
 import geniusweb.progress.Progress;
 import geniusweb.progress.ProgressRounds;
 import geniusweb.progress.ProgressTime;
+import geniusweb.protocol.NegoState;
 import geniusweb.protocol.ProtocolException;
 import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
+import geniusweb.protocol.session.TeamInfo;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
 import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
 import tudelft.utilities.junit.GeneralTests;
 
@@ -37,5 +50,5 @@
 	private PartyId party2 = new PartyId("party2");
 	private PartyId party3 = new PartyId("party3");
-	private List<Action> actions = new LinkedList<>();
+	private List<Action> actions1 = new LinkedList<>();
 	private Action action = mock(Action.class);
 	private List<Action> actions2 = Arrays.asList(action);
@@ -53,5 +66,5 @@
 	private ProgressRounds progressrounds1 = mock(ProgressRounds.class);
 	private SAOPSettings settings = mock(SAOPSettings.class);
-	private SAOPState state1, state1a, state2, state3, state4;
+	private SAOPState state, state1, state1a, state2, state3, state4;
 
 	private Bid bid1 = mock(Bid.class);
@@ -63,6 +76,10 @@
 	private EndNegotiation endNegotiation1 = new EndNegotiation(party1);
 
+	private final ObjectMapper jackson = new ObjectMapper();
+
+	private String serialized = "{\"SAOPState\":{\"actions\":[],\"connections\":[\"party1\",\"party2\"],\"progress\":{\"ProgressTime\":{\"duration\":1000000,\"start\":2000000}},\"settings\":{\"SAOPSettings\":{\"participants\":[{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party1ref\",\"parameters\":{}},\"profile\":\"prof1\"}]}}],\"deadline\":{\"DeadlineTime\":{\"durationms\":123000}}}},\"partyprofiles\":{},\"error\":null}}";
+
 	@Before
-	public void before() {
+	public void before() throws URISyntaxException {
 		when(party1conn.getParty()).thenReturn(party1);
 		when(party2conn.getParty()).thenReturn(party2);
@@ -79,14 +96,26 @@
 		when(progressrounds.advance()).thenReturn(progressrounds1);
 
-		state1 = new SAOPState(actions, connections, progresstime, settings,
-				null, null);
-		state1a = new SAOPState(actions, connections, progresstime, settings,
+		state1 = new SAOPState(actions1, connections, progresstime, settings,
+				null, null);
+		state1a = new SAOPState(actions1, connections, progresstime, settings,
 				null, null);
 		state2 = new SAOPState(actions2, connections, progresstime, settings,
 				null, null);
-		state3 = new SAOPState(actions, connections2, progresstime, settings,
-				null, null);
-		state4 = new SAOPState(actions, connections, progressrounds, settings,
-				null, null);
+		state3 = new SAOPState(actions1, connections2, progresstime, settings,
+				null, null);
+		state4 = new SAOPState(actions1, connections, progressrounds, settings,
+				null, null);
+
+		List<PartyId> conns = Arrays.asList(party1, party2);
+		PartyWithParameters pwithp = new PartyWithParameters(
+				new PartyRef("party1ref"), new Parameters());
+		List<PartyWithProfile> teams = Arrays
+				.asList(new PartyWithProfile(pwithp, new ProfileRef("prof1")));
+		List<TeamInfo> participants = Arrays.asList(new TeamInfo(teams));
+		Deadline deadline = new DeadlineTime(123000);
+		SAOPSettings setts = new SAOPSettings(participants, deadline);
+		state = new SAOPState(actions1, conns,
+				new ProgressTime(1000000l, new Date(2000000l)), setts, null,
+				null);
 
 	}
@@ -110,5 +139,5 @@
 	@Test
 	public void constructWith0Connection() {
-		new SAOPState(actions, Arrays.asList(), progresstime, settings, null,
+		new SAOPState(actions1, Arrays.asList(), progresstime, settings, null,
 				null);
 	}
@@ -116,5 +145,5 @@
 	@Test
 	public void constructWithNullConnection() {
-		SAOPState state = new SAOPState(actions, null, progresstime, settings,
+		SAOPState state = new SAOPState(actions1, null, progresstime, settings,
 				null, null);
 		assertEquals(0, state.getConnections().size());
@@ -129,5 +158,5 @@
 	public void testNextActor2() {
 		List<PartyId> conns = Arrays.asList(party2, party3);
-		SAOPState state = new SAOPState(actions, conns, progresstime, settings,
+		SAOPState state = new SAOPState(actions1, conns, progresstime, settings,
 				null, null);
 		assertEquals(party2, state.getNextActor());
@@ -153,5 +182,5 @@
 	public void isFinalTest() {
 		assertFalse(state1.isFinal(NOW));
-		SAOPState state = new SAOPState(actions, connections, progresstime,
+		SAOPState state = new SAOPState(actions1, connections, progresstime,
 				settings, null, mock(ProtocolException.class));
 		assertTrue(state.isFinal(NOW));
@@ -216,13 +245,4 @@
 
 	@Test(expected = IllegalArgumentException.class)
-	public void withWrongActionTest() {
-		// wrong because action has actor null which does not match party1
-		SAOPState state = state1.with(party1, action);
-//		assertEquals(1, state.getActions().size());
-//		assertEquals(action, state.getActions().get(0));
-//		assertTrue(state.isFinal(NOW));
-	}
-
-	@Test(expected = IllegalArgumentException.class)
 	public void withActionTest() {
 		when(action.getActor()).thenReturn(party1);
@@ -249,5 +269,5 @@
 	@Test
 	public void isProtocolErrorFinal() {
-		SAOPState state = new SAOPState(actions, connections3, progressrounds,
+		SAOPState state = new SAOPState(actions1, connections3, progressrounds,
 				settings, null,
 				new ProtocolException("test error", new PartyId("test")));
@@ -259,5 +279,5 @@
 	public void RefuseImmediateAccept() {
 		Accept nullaccept = new Accept(party1, null);
-		SAOPState state = state1.with(party1, nullaccept);
+		state1.with(party1, nullaccept);
 	}
 
@@ -320,3 +340,20 @@
 
 	}
+
+	@Test
+	public void testDeserialize() throws IOException {
+		NegoState obj = jackson.readValue(serialized, NegoState.class);
+		System.out.println(obj);
+		assertEquals(state, obj);
+	}
+
+	@Test
+	public void testSerialize()
+			throws JsonProcessingException, URISyntaxException {
+
+		String string = jackson.writeValueAsString(state);
+		System.out.println(string);
+		assertEquals(serialized, string);
+	}
+
 }
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 33)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 34)
@@ -3,8 +3,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -17,4 +17,5 @@
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -27,5 +28,4 @@
 
 import geniusweb.actions.Accept;
-import geniusweb.actions.Action;
 import geniusweb.actions.EndNegotiation;
 import geniusweb.actions.Offer;
@@ -66,4 +66,5 @@
  */
 public class SAOPTest {
+
 	private final SAOPState state = mock(SAOPState.class),
 			connectedstate = mock(SAOPState.class),
@@ -71,5 +72,6 @@
 			finalstate = mock(SAOPState.class);
 
-	private ProtocolRef SAOP;
+	private static final long DEADLINE = 1000l;
+	private ProtocolRef SAOPPROTOCOL;
 	private static final PartyId PARTY2ID = new PartyId("party2");
 	private static final PartyId PARTY1ID = new PartyId("party1");
@@ -95,5 +97,5 @@
 	private final Parameters parameters = new Parameters();
 
-	private final long NOW = 1000;
+//	private final long NOW = 1000;
 	private final PartyWithParameters partywithparam1 = new PartyWithParameters(
 			party1ref, parameters);
@@ -103,8 +105,10 @@
 	private final Deadline deadlinetime = mock(DeadlineTime.class);
 
+	private Map<PartyId, PartyWithProfile> pwpmap;
+
 	@Before
 	public void before()
 			throws URISyntaxException, IOException, NoResourcesNowException {
-		SAOP = new ProtocolRef("SAOP");
+		SAOPPROTOCOL = new ProtocolRef("SAOP");
 
 		profile1 = mock(ProfileRef.class);
@@ -113,6 +117,6 @@
 		PartyWithProfile pwp1 = new PartyWithProfile(partywithparam1, profile1);
 		PartyWithProfile pwp2 = new PartyWithProfile(partywithparam2, profile2);
-		when(team1.getAllParties()).thenReturn(Arrays.asList(pwp1));
-		when(team2.getAllParties()).thenReturn(Arrays.asList(pwp2));
+		when(team1.getParties()).thenReturn(Arrays.asList(pwp1));
+		when(team2.getParties()).thenReturn(Arrays.asList(pwp2));
 
 		partyprofiles = new HashMap<>();
@@ -120,5 +124,9 @@
 		partyprofiles.put(PARTY2ID, team2);
 
-		when(deadlinetime.getDuration()).thenReturn(1000l);
+		pwpmap = new HashMap<>();
+		pwpmap.put(PARTY1ID, pwp1);
+		pwpmap.put(PARTY2ID, pwp2);
+
+		when(deadlinetime.getDuration()).thenReturn(DEADLINE);
 
 		List<TeamInfo> teams = new ArrayList<>();
@@ -139,9 +147,9 @@
 		when(conn2.getParty()).thenReturn(PARTY2ID);
 
-		mockState(connectedstate, "connected state");
-		mockState(state, "initial state");
-		mockState(finalstate, "final state");
+		mockState(connectedstate, "connected state", true);
+		mockState(state, "running state", true);
+		mockState(finalstate, "final state", true);
 		when(finalstate.isFinal(anyLong())).thenReturn(true);
-		mockState(failstate, "fail state");
+		mockState(failstate, "fail state", true);
 		when(failstate.isFinal(anyLong())).thenReturn(true);
 
@@ -171,17 +179,20 @@
 	 * 
 	 * @param state  the state to mock (must be already
-	 * @param asText
+	 * @param asText short name for the state, for debugging
+	 * @param bool   true if parties are connected
 	 */
-	private void mockState(SAOPState state, String asText) {
+	private void mockState(SAOPState state, String asText,
+			boolean isConnected) {
 		when(state.getSettings()).thenReturn(settings);
-		when(state.getConnections())
-				.thenReturn(Arrays.asList(PARTY1ID, PARTY2ID));
-		// when(state.getConnections()).thenReturn(connectionswithparties);
+		if (isConnected) {
+			when(state.getConnections())
+					.thenReturn(Arrays.asList(PARTY1ID, PARTY2ID));
+		} else {
+			when(state.getConnections()).thenReturn(Collections.emptyList());
+		}
 
 		when(state.getProgress()).thenReturn(progress);
 		when(state.with(any(PartyId.class), any(PartyWithProfile.class)))
 				.thenReturn(connectedstate);
-//		when(state.with(any(ProtocolToPartyConn.class),
-//				any(PartyWithProfile.class))).thenReturn(connectedstate);
 		when(state.getNextActor()).thenReturn(PARTY1ID);
 		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
@@ -193,4 +204,5 @@
 		when(state.with(any(ProtocolException.class))).thenReturn(failstate);
 		when(state.getAgreements()).thenReturn(mock(Agreements.class));
+		when(state.getPartyProfiles()).thenReturn(pwpmap);
 	}
 
@@ -260,13 +272,11 @@
 				.forClass(Settings.class);
 		verify(conn1).send(actualsettings.capture());
-		assertEquals(
-				new Settings(PARTY1ID, profile1, SAOP, progress, parameters),
-				actualsettings.getValue());
+		assertEquals(new Settings(PARTY1ID, profile1, SAOPPROTOCOL, progress,
+				parameters), actualsettings.getValue());
 
 		verify(conn2, times(1)).send(any(Settings.class));
 		verify(conn2).send(actualsettings.capture());
-		assertEquals(
-				new Settings(PARTY2ID, profile2, SAOP, progress, parameters),
-				actualsettings.getValue());
+		assertEquals(new Settings(PARTY2ID, profile2, SAOPPROTOCOL, progress,
+				parameters), actualsettings.getValue());
 		verify(state, times(0)).with(any(ProtocolException.class));
 		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
@@ -283,13 +293,15 @@
 
 	@Test
-	public void testActionRequest() throws IOException {
+	public void testActionRequest() throws IOException, ProtocolException {
+		saop.nextTurn();
+
 		when(state.getNextActor()).thenReturn(PARTY1ID);
-		when(state.with(any(PartyId.class), any(Action.class)))
-				.thenReturn(state);
+		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
+				.thenReturn(finalstate);
 
 		saop.actionRequest(conn1, mock(EndNegotiation.class));
 
 		verify(state, times(0)).with(any(ProtocolException.class));
-		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
+		verify(state, times(1)).with(eq(PARTY1ID), isA((EndNegotiation.class)));
 		// verify broadcast
 		verify(conn1, times(1)).send(isA(ActionDone.class));
@@ -299,5 +311,6 @@
 		verify(conn1, times(1)).send(isA(YourTurn.class));
 		verify(conn2, times(0)).send(isA(YourTurn.class));
-		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
+		// listener should be informed about final state.
+		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
 	}
 
@@ -374,3 +387,20 @@
 		saop.addParticipant(null);
 	}
+
+	@Test
+	public void testDeadlineTimer() throws InterruptedException, IOException {
+		SAOPState unconnectedstate = mock(SAOPState.class);
+		mockState(unconnectedstate, "unconnected state", false);
+		SAOP saopempty = new SAOP(unconnectedstate, new ReportToLogger("test"),
+				new ProtocolToPartyConnections(Collections.emptyList()));
+		saopempty.addListener(testlistener);
+
+		saopempty.start(factory);
+		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
+		verify(conn1, times(1)).send(isA(YourTurn.class));
+		Thread.sleep(DEADLINE + SAOP.TIME_MARGIN + 100);
+		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
+		verify(conn1, times(1)).send(isA(Finished.class));
+	}
+
 }
