source: protocol/src/main/java/geniusweb/protocol/session/mopac/PartyStates.java@ 52

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

File size: 9.7 KB
Line 
1package geniusweb.protocol.session.mopac;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.LinkedList;
8import java.util.List;
9import java.util.Map;
10import java.util.Set;
11import java.util.stream.Collectors;
12
13import com.fasterxml.jackson.annotation.JsonAutoDetect;
14import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
15import com.fasterxml.jackson.annotation.JsonCreator;
16import com.fasterxml.jackson.annotation.JsonProperty;
17
18import geniusweb.actions.Action;
19import geniusweb.actions.EndNegotiation;
20import geniusweb.actions.PartyId;
21import geniusweb.inform.Agreements;
22import geniusweb.protocol.ProtocolException;
23
24/**
25 * Invariant: contains the current state of all participating parties. A party
26 * either notYetActed, did action, reached an agreement, walked away or made a
27 * {@link ProtocolException}.
28 * <p>
29 * After a phase completes, the actions are filtered/handled to collect
30 * agreements and move remaining parties back to notYetActed.
31 *
32 */
33@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
34public class PartyStates {
35 // all parties must be in exactly one state at all times.
36 private final Set<PartyId> notYetActed;
37 private final List<Action> actions; // chrono order
38 private final Agreements agreements;
39 private final List<PartyId> walkedAway;
40 private final Map<PartyId, ProtocolException> exceptions;
41 private final Map<PartyId, Integer> powers;
42
43 @JsonCreator
44 protected PartyStates(@JsonProperty("powers") Map<PartyId, Integer> powers,
45 @JsonProperty("notYetActed") Set<PartyId> notYetActed,
46 @JsonProperty("actions") List<Action> actions,
47 @JsonProperty("agreements") Agreements agreements,
48 @JsonProperty("walkedAway") List<PartyId> walkedAway,
49 @JsonProperty("exceptions") Map<PartyId, ProtocolException> exceptions) {
50 this.notYetActed = new HashSet<>(notYetActed);
51 this.actions = new ArrayList<>(actions);
52 this.agreements = agreements;
53 this.walkedAway = new ArrayList<>(walkedAway);
54 this.exceptions = exceptions;
55 this.powers = new HashMap<>(powers);
56 }
57
58 /**
59 * Initial constructor.
60 *
61 * @param powers the powers of all parties.
62 */
63 public PartyStates(Map<PartyId, Integer> powers) {
64 this(powers, new HashSet<>(powers.keySet()), Collections.emptyList(),
65 new Agreements(), Collections.emptyList(),
66 Collections.emptyMap());
67 }
68
69 /**
70 *
71 * @param action the action done by some party. The correctness of action,
72 * particularly of {@link Action#getActor()}, must be correct.
73 * @return new state with party done given action. This just accepts any
74 * given action and is not considering number of rounds, time or
75 * whether an action is allowed.
76 *
77 * @throws IllegalArgumentException if party doing action already acted.
78 * This is just a safety check as legality
79 * of actions should be checked before
80 * calling this.
81 */
82 public PartyStates with(Action action) {
83 if (!(notYetActed.contains(action.getActor())))
84 throw new IllegalArgumentException(
85 "actor already acted: " + action);
86 if (action instanceof EndNegotiation)
87 return withWalkAway(action.getActor());
88 List<Action> newActions = new LinkedList<Action>(actions);
89 newActions.add(action);
90 return new PartyStates(powers, removeParty(action.getActor()),
91 newActions, agreements, walkedAway, exceptions);
92 }
93
94 /**
95 *
96 * @param newAgree a new agreements to be merged with existing agreements.
97 * The parties in the agreement must have acted and thus in
98 * actions.
99 * @return new PartyStates with agreeing parties removed from actions and
100 * added to Agreements.
101 */
102 public PartyStates with(Agreements newAgree) {
103 Set<PartyId> parties = newAgree.getMap().keySet();
104 List<Action> newActions = actions.stream()
105 .filter(act -> !(parties.contains(act.getActor())))
106 .collect(Collectors.toList());
107 return new PartyStates(powers, notYetActed, newActions,
108 agreements.with(newAgree), walkedAway, exceptions);
109 }
110
111 public PartyStates withWalkAway(PartyId actor) {
112 if (!(notYetActed.contains(actor)))
113 throw new IllegalArgumentException("actor already acted: " + actor);
114 LinkedList<PartyId> newWalkAway = new LinkedList<>(walkedAway);
115 newWalkAway.add(actor);
116 return new PartyStates(powers, removeParty(actor), actions, agreements,
117 newWalkAway, exceptions);
118 }
119
120 /**
121 * Move party from active to exceptions.
122 *
123 * @param e the exception that the party caused
124 * @return new PartyStates with party that caused the exception in the
125 * exceptions list and removed from the active list. Nothing happens
126 * if party is not active.
127 */
128 public PartyStates with(ProtocolException e) {
129 if (!notYetActed.contains(e.getParty())) {
130 // complex case. Party did valid action but now is messing around.
131 // Easiest seems to completely ignore it. CHECK.
132 return this;
133 }
134 Map<PartyId, ProtocolException> newExc = new HashMap<>(exceptions);
135 newExc.put(e.getParty(), e);
136 return new PartyStates(powers, removeParty(e.getParty()), actions,
137 agreements, walkedAway, newExc);
138 }
139
140 /**
141 *
142 * @return parties that have not yet acted
143 */
144 public Set<PartyId> getNotYetActed() {
145 return notYetActed;
146 }
147
148 /**
149 *
150 * @return parties that are still in the negotiation. These are the parties
151 * that not yet acted plus the ones that did an action.
152 */
153 public Set<PartyId> getNegotiatingParties() {
154 Set<PartyId> parties = actions.stream().map(act -> act.getActor())
155 .collect(Collectors.toSet());
156 parties.addAll(notYetActed);
157 return parties;
158 }
159
160 /**
161 * @param actor
162 * @return {@link #notYetActed} with actor removed
163 * @throws IllegalArgumentException if party already acted (not in
164 * {@link #notYetActed}).
165 */
166 private Set<PartyId> removeParty(PartyId party) {
167 Set<PartyId> newActiveParties = new HashSet<>(notYetActed);
168 if (!newActiveParties.remove(party))
169 throw new IllegalArgumentException(
170 "Party " + party + " is not active, can't be removed");
171 return newActiveParties;
172
173 }
174
175 public Agreements getAgreements() {
176 return agreements;
177 }
178
179 public Map<PartyId, Integer> getPowers() {
180 return Collections.unmodifiableMap(powers);
181 }
182
183 public Map<PartyId, ProtocolException> getExceptions() {
184 return Collections.unmodifiableMap(exceptions);
185 }
186
187 /**
188 * @return new state where all {@link #notYetActed} are moved to the
189 * exceptions list.
190 */
191 public PartyStates finish() {
192 PartyStates newstate = this;
193 for (PartyId party : notYetActed) {
194 newstate = newstate
195 .with(new ProtocolException("Party did not act", party));
196 }
197 return newstate;
198 }
199
200 public List<Action> getActions() {
201 return Collections.unmodifiableList(actions);
202 }
203
204 /**
205 *
206 * @return all parties that walked away
207 */
208 public List<PartyId> getWalkedAway() {
209 return Collections.unmodifiableList(walkedAway);
210 }
211
212 /**
213 * @param <T> the type of objects requested
214 * @param type the type of actions to extract. Must be of type T, needed
215 * because of java's type erasure.
216 *
217 * @return all actions of requested type in this phase
218 */
219 public <T extends Action> List<T> getActions(Class<T> type) {
220 return actions.stream().filter(act -> type.isInstance(act))
221 .map(act -> (T) act).collect(Collectors.toList());
222 }
223
224 @Override
225 public String toString() {
226 return "PartyStates[" + notYetActed + "," + actions + "," + agreements
227 + "," + walkedAway + "," + exceptions + "]";
228 }
229
230 /**
231 *
232 * @return states with all parties that are in {@link #actions} moved back
233 * to {@link #notYetActed}. This state is then ready for a next
234 * phase.
235 * @throws IllegalStateException if {@link #notYetActed} is not empty
236 */
237 public PartyStates flush() {
238 if (!notYetActed.isEmpty())
239 throw new IllegalStateException(
240 "Some parties did not yet act:" + notYetActed);
241 return new PartyStates(powers, getNegotiatingParties(),
242 Collections.emptyList(), agreements, walkedAway, exceptions);
243 }
244
245 @Override
246 public int hashCode() {
247 final int prime = 31;
248 int result = 1;
249 result = prime * result + ((actions == null) ? 0 : actions.hashCode());
250 result = prime * result
251 + ((agreements == null) ? 0 : agreements.hashCode());
252 result = prime * result
253 + ((exceptions == null) ? 0 : exceptions.hashCode());
254 result = prime * result
255 + ((notYetActed == null) ? 0 : notYetActed.hashCode());
256 result = prime * result + ((powers == null) ? 0 : powers.hashCode());
257 result = prime * result
258 + ((walkedAway == null) ? 0 : walkedAway.hashCode());
259 return result;
260 }
261
262 @Override
263 public boolean equals(Object obj) {
264 if (this == obj)
265 return true;
266 if (obj == null)
267 return false;
268 if (getClass() != obj.getClass())
269 return false;
270 PartyStates other = (PartyStates) obj;
271 if (actions == null) {
272 if (other.actions != null)
273 return false;
274 } else if (!actions.equals(other.actions))
275 return false;
276 if (agreements == null) {
277 if (other.agreements != null)
278 return false;
279 } else if (!agreements.equals(other.agreements))
280 return false;
281 if (exceptions == null) {
282 if (other.exceptions != null)
283 return false;
284 } else if (!exceptions.equals(other.exceptions))
285 return false;
286 if (notYetActed == null) {
287 if (other.notYetActed != null)
288 return false;
289 } else if (!notYetActed.equals(other.notYetActed))
290 return false;
291 if (powers == null) {
292 if (other.powers != null)
293 return false;
294 } else if (!powers.equals(other.powers))
295 return false;
296 if (walkedAway == null) {
297 if (other.walkedAway != null)
298 return false;
299 } else if (!walkedAway.equals(other.walkedAway))
300 return false;
301 return true;
302 }
303
304}
Note: See TracBrowser for help on using the repository browser.