source: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.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: 5.9 KB
Line 
1package geniusweb.protocol.session.saop;
2
3import java.util.Arrays;
4import java.util.Collections;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Map;
8
9import com.fasterxml.jackson.annotation.JsonCreator;
10import com.fasterxml.jackson.annotation.JsonProperty;
11
12import geniusweb.actions.Accept;
13import geniusweb.actions.Action;
14import geniusweb.actions.EndNegotiation;
15import geniusweb.actions.Offer;
16import geniusweb.actions.PartyId;
17import geniusweb.inform.Agreements;
18import geniusweb.issuevalue.Bid;
19import geniusweb.progress.Progress;
20import geniusweb.progress.ProgressRounds;
21import geniusweb.protocol.ProtocolException;
22import geniusweb.protocol.session.DefaultSessionState;
23import geniusweb.protocol.session.SessionResult;
24import geniusweb.references.PartyWithProfile;
25
26/**
27 * Immutable.
28 */
29public class SAOPState extends DefaultSessionState<SAOPState, SAOPSettings> {
30
31 /**
32 *
33 * @param actions the actions done by the parties
34 * @param connections the existing party connections. If null, default
35 * empty list is used. Can be less than 2 parties in
36 * the first phases of the setup or after parties
37 * disconnected.
38 * @param progress the {@link Progress} line. can be null
39 * @param settings the {@link SAOPSettings}
40 * @param partyprofiles map with the {@link PartyWithProfile} for connected
41 * parties. null is equivalent to an empty map.
42 * @param error the {@link ProtocolException}, or null if none
43 * occurred.
44 */
45 @JsonCreator
46 public SAOPState(@JsonProperty("actions") List<Action> actions,
47 @JsonProperty("connections") List<PartyId> connections,
48 @JsonProperty("progress") Progress progress,
49 @JsonProperty("settings") SAOPSettings settings,
50 @JsonProperty("partyprofiles") Map<PartyId, PartyWithProfile> partyprofiles,
51 @JsonProperty("error") ProtocolException error) {
52 super(actions, connections, progress, settings, partyprofiles, error);
53 }
54
55 @Override
56 public SAOPState with(List<Action> actions, List<PartyId> conns,
57 Progress progr, SAOPSettings settings,
58 Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
59 return new SAOPState(actions, conns, progr, settings, partyprofiles, e);
60 }
61
62 /**
63 * Creates the initial state from the given settings and progress=null
64 *
65 * @param settings the {@link SAOPSettings}
66 */
67 public SAOPState(SAOPSettings settings) {
68 this(Collections.emptyList(), Collections.emptyList(), null, settings,
69 null, null);
70
71 }
72
73 @Override
74 public Agreements getAgreements() {
75 Agreements agree = new Agreements();
76 List<Action> acts = getActions();
77 int nparticipants = getConnections().size();
78 if (nparticipants < 2 || acts.size() < nparticipants) {
79 return agree;
80 }
81 Action offer = acts.get(acts.size() - nparticipants);
82 if (!(offer instanceof Offer))
83 return agree;
84 Bid bid = ((Offer) offer).getBid();
85
86 // check that the last n-1 are accepts.
87 boolean allaccept = acts.stream().skip(acts.size() - nparticipants + 1)
88 .allMatch(act -> act instanceof Accept
89 && bid.equals(((Accept) act).getBid()));
90 if (allaccept)
91 agree = agree
92 .with(new Agreements(bid, new HashSet<>(getParties())));
93 return agree;
94 }
95
96 /**
97 *
98 * @return all currently connected parties.
99 */
100 public List<PartyId> getParties() {
101 return getConnections();
102 }
103
104 @Override
105 public boolean isFinal(long currentTimeMs) {
106 List<Action> acts = getActions();
107 return super.isFinal(currentTimeMs)
108 || !getAgreements().getMap().isEmpty() || (!acts.isEmpty()
109 && acts.get(acts.size() - 1) instanceof EndNegotiation);
110 }
111
112 @Override
113 public SAOPState with(PartyId actor, Action action) {
114 return super.with(actor, action).with(advanceProgress());
115 }
116
117 @Override
118 public String checkAction(PartyId actor, Action action) {
119 String msg = super.checkAction(actor, action);
120 if (msg != null)
121 return msg;
122
123 if (!actor.equals(getNextActor()))
124 return "Party does not have the turn ";
125
126 // check protocol is followed for specific actions
127 if (action instanceof Accept) {
128 Bid bid = getLastBid();
129 if (bid == null)
130 return "Accept without a recent offer";
131
132 if (!bid.equals(((Accept) action).getBid()))
133 return "Party accepts a bid differing from the last offer ="
134 + bid + ", action=" + action + ")";
135 return null;
136 } else if (action instanceof Offer) {
137 return null;
138 } else if (action instanceof EndNegotiation) {
139 return null;
140 }
141 return "Action " + action + " is not allowed in SAOP";
142 }
143
144 /**
145 * Check up to nparticipants-1 steps back if there was an offer.
146 *
147 * @return Bid from the most recent offer, or null if no such offer
148 */
149 private Bid getLastBid() {
150 int nparticipants = getConnections().size();
151 List<Action> acts = getActions();
152 for (int n = acts.size() - 1; n > acts.size() - nparticipants
153 && n >= 0; n--) {
154 Action action = acts.get(n);
155 if (action instanceof Offer) {
156 return ((Offer) action).getBid();
157 }
158 }
159 return null;
160
161 }
162
163 /**
164 *
165 * @return the next actor in the current state. Assumes 1 action per actor
166 * every time. NOTE if party disconnects this would jump wildly but
167 * nego stops then anyway
168 */
169 protected PartyId getNextActor() {
170 return getConnections()
171 .get(getActions().size() % getConnections().size());
172 }
173
174 /**
175 * @return new progress state
176 */
177 public Progress advanceProgress() {
178 Progress newprogress = getProgress();
179 if (newprogress instanceof ProgressRounds && isLastActor()) {
180 newprogress = ((ProgressRounds) newprogress).advance();
181 }
182 return newprogress;
183 }
184
185 /**
186 * @return true if the current actor is the last actor in the list
187 */
188 private boolean isLastActor() {
189 int nparticipants = getConnections().size();
190 return getActions().size() % nparticipants == nparticipants - 1;
191 }
192
193 @Override
194 public List<SessionResult> getResults() {
195 return Arrays.asList(new SessionResult(getPartyProfiles(),
196 getAgreements(), Collections.emptyMap(), getError()));
197 }
198
199}
Note: See TracBrowser for help on using the repository browser.