- Timestamp:
- 10/06/20 13:12:20 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocol/src/main/java/geniusweb/protocol/session/mopac/MOPACState.java
r23 r24 17 17 import geniusweb.progress.Progress; 18 18 import geniusweb.progress.ProgressRounds; 19 import geniusweb.protocol.NegoProtocol; 19 20 import geniusweb.protocol.ProtocolException; 20 import geniusweb.protocol.partyconnection.ProtocolToPartyConn;21 import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;22 21 import geniusweb.protocol.session.SessionResult; 23 22 import geniusweb.protocol.session.SessionState; … … 27 26 import geniusweb.protocol.session.saop.SAOPSettings; 28 27 import geniusweb.references.PartyWithProfile; 29 import geniusweb.voting.VotingEvaluator; 30 28 29 /** 30 * Keeps track of the current {@link Phase}. Adds initializing stuff and 31 * time/deadline checking. This state does not contain connections, this assumes 32 * that someone else handles (i.e. {@link NegoProtocol} that and the connections 33 * with the parties and that negotiation events are just pumped in from there. 34 * <p> 35 * This object is a bit tricky. It has two states 36 * <ol> 37 * <li>The initial state, where phase=null and connections are being made to all 38 * parties. At this point, problems can not be handled nicely yet because there 39 * are no PartyId's for problematic parties 40 * <li>The working state, where all parties are connected and all problems can 41 * be connected to an offending party. 42 * </ol> 43 */ 31 44 public class MOPACState implements SessionState { 32 45 33 private final Phase phase; 46 private final Phase phase; // maybe null while initializing 34 47 private final MOPACSettings settings; 35 48 private final Map<PartyId, PartyWithProfile> partyprofiles; 36 private final ProtocolToPartyConnections connections;37 49 private final List<Action> actions; 38 50 private final Progress progress; … … 44 56 */ 45 57 public MOPACState(MOPACSettings settings) { 46 this(null, Arrays.asList(), 47 new ProtocolToPartyConnections(Collections.emptyList()), null, 48 settings, Collections.emptyMap()); 58 this(null, Arrays.asList(), null, settings, Collections.emptyMap()); 49 59 50 60 } … … 54 64 * set something only after we have connections. 55 65 * @param actions the legal actions that have been done in the 56 * negotiation. A new-sub-list is added for each phase 57 * change. It is assumed that the last element of the 58 * list is the list with actions taken in the current 59 * phase. first action in first list is the oldest. 60 * This MUST NOT contain illegal actions. Parties doing 61 * illegal actions are killed and the offending action 62 * ends up in the stacktrace. Previous actions of 63 * crashed parties remain standing and valid. 64 * @param conns the existing party connections. we assume ownership 65 * of this so it should not be modified although 66 * connections may of course break. 66 * negotiation. {@link PartyStates#getActions()} is 67 * called to collect the actions after the phase is 68 * finished.first action in list is the oldest. This 69 * will not contain actions that immediately led to an 70 * agreement, because {@link PartyStates} removes the 71 * actions that led to an agreement. This MUST NOT 72 * contain illegal actions. Parties doing illegal 73 * actions are killed and the offending action ends up 74 * in the stacktrace. Previous actions of crashed 75 * parties remain standing and valid. 67 76 * @param progress the {@link Progress} line. can be null if not yet 68 * known. This happens because during setup we first 69 * add all connections, and only when we have that we 70 * set the correct deadline. 77 * known. null happens because during initialization 78 * phase the protocol first add all connections. During 79 * this time, parties may already enter the 80 * failed/exception state. 71 81 * @param settings the {@link SAOPSettings} 72 82 * @param partyprofiles map with the {@link PartyWithProfile} for connected 73 83 * parties. null is equivalent to an empty map. 74 * @param evaluator the {@link VotingEvaluator}75 84 */ 76 85 @JsonCreator 77 86 protected MOPACState(@JsonProperty("phase") Phase phase, 78 87 @JsonProperty("actions") List<Action> actions, 79 @JsonProperty("connections") ProtocolToPartyConnections conns,80 88 @JsonProperty("progress") Progress progress, 81 89 @JsonProperty("settings") MOPACSettings settings, … … 83 91 this.phase = phase; 84 92 this.actions = actions; 85 this.connections = conns;86 93 this.progress = progress; 87 94 this.settings = settings; … … 90 97 91 98 /** 92 * Can be called after all connections are initialized. 93 * 94 * @param now current time ms since 1970 95 * 96 * @return state with the initial partystates set. 97 */ 98 public MOPACState initPhase(long now) { 99 PartyStates partyStates = new PartyStates(getPowers()); 100 Phase firstPhase = new OfferPhase(null, partyStates, 101 now + getAvailablePhaseTime(now), 102 settings.getVotingEvaluation()); 103 return new MOPACState(firstPhase, actions, connections, progress, 104 settings, partyprofiles); 105 } 106 107 @Override 108 public List<Action> getActions() { 109 return Collections.unmodifiableList(actions); 110 } 111 112 @Override 113 public Progress getProgress() { 114 return progress; 115 } 116 117 public Map<PartyId, PartyWithProfile> getPartyProfiles() { 118 return Collections.unmodifiableMap(partyprofiles); 119 } 120 121 /** 122 * @return all current/remaining active party connections. Finished/crashed 123 * parties should be removed immediately. 124 */ 125 public ProtocolToPartyConnections getConnections() { 126 return connections; 127 } 128 129 /** 130 * @param now current time ms since 1970 131 * @return the max possible duration in ms of the NEXT phase. Maybe 0 or 132 * negative if past deadline. 133 */ 134 private Long getAvailablePhaseTime(long now) { 135 // explicit check, to check also the round counts. 136 if (incrementProgress().isPastDeadline(now + Phase.PHASE_MINTIME)) 137 return 0l; 138 return Math.min(progress.getTerminationTime().getTime() - now, 139 Phase.PHASE_MAXTIME); 140 } 141 142 /** 143 * 144 * @param connection the new {@link ProtocolToPartyConn} 145 * @param partyprofile the {@link PartyWithProfile} that is associated with 146 * this state 147 * @return new {@link MOPACState} with the new connection added. This call 148 * ignores the progress (does not check isFinal) because we uses 149 * this during the setup where the deadline is not yet relevant. 150 */ 151 protected MOPACState with(ProtocolToPartyConn connection, 152 PartyWithProfile partyprofile) { 153 if (phase != null) 154 throw new IllegalStateException( 155 "Adding connections only allowed while initializing"); 156 157 ProtocolToPartyConnections newconns = getConnections().with(connection); 158 Map<PartyId, PartyWithProfile> newprofiles = new HashMap<>( 159 partyprofiles); 160 newprofiles.put(connection.getParty(), partyprofile); 161 return new MOPACState(null, actions, newconns, progress, settings, 162 newprofiles); 163 } 164 165 /** 166 * @param id the {@link PartyId} of the party that failed. 167 * @param e the {@link ProtocolException} that occurred in the party 168 * @return a new state with the error set. 169 */ 170 public MOPACState with(ProtocolException e) { 171 return new MOPACState(phase.with(e), actions, connections, progress, 172 settings, partyprofiles); 173 } 174 175 /** 176 * Sets the progress for this session. Can be set only if progress=null. 177 * Should be set in INIT phase. 178 * 179 * @param newprogress the new progress 180 * @return new {@link MOPACState} with the progress set 181 */ 182 public MOPACState with(Progress newprogress) { 99 * Sets the progress for this session and initial phase. Must be called 100 * after all parties have been connected with 101 * {@link #with(PartyId, PartyWithProfile)}. 102 * 103 * @param newprogress the initial {@link Progress} typically matching the 104 * settings deadline object 105 * @param now current time ms since 1970 106 * 107 * @return state with the initial partystates , progress set. 108 */ 109 public MOPACState initPhase(Progress newprogress, long now) { 183 110 if (progress != null || newprogress == null || phase != null) { 184 111 throw new IllegalArgumentException( 185 112 "progress must be null, newprogress must be not null and phase must be INIT"); 186 113 } 187 return new MOPACState(phase, actions, connections, newprogress, 188 getSettings(), partyprofiles); 114 115 PartyStates partyStates = new PartyStates(getPowers()); 116 Phase firstPhase = new OfferPhase(partyStates, 117 now + getAvailablePhaseTime(newprogress, now), 118 settings.getVotingEvaluation()); 119 return new MOPACState(firstPhase, actions, newprogress, settings, 120 partyprofiles); 121 } 122 123 @Override 124 public List<Action> getActions() { 125 return Collections.unmodifiableList(actions); 126 } 127 128 @Override 129 public Progress getProgress() { 130 return progress; 131 } 132 133 @Override 134 public Agreements getAgreements() { 135 return phase.getPartyStates().getAgreements(); 136 } 137 138 @Override 139 public MOPACSettings getSettings() { 140 return settings; 141 } 142 143 public Map<PartyId, PartyWithProfile> getPartyProfiles() { 144 return Collections.unmodifiableMap(partyprofiles); 145 } 146 147 @Override 148 public boolean isFinal(long now) { 149 return phase != null && phase.isFinal(now) && !isNewPhasePossible(now); 150 } 151 152 @Override 153 public SessionResult getResult() { 154 return new SessionResult(partyprofiles, getAgreements(), 155 Collections.emptyMap(), null); 156 } 157 158 /** 159 * @param progress the Progress that needs to be checked 160 * @param now current time ms since 1970 161 * @return the max possible duration in ms of a phase considering the 162 * progress. 163 */ 164 private static Long getAvailablePhaseTime(Progress aprogress, long now) { 165 return Math.min(aprogress.getTerminationTime().getTime() - now, 166 Phase.PHASE_MAXTIME); 167 } 168 169 /** 170 * @param id the new {@link PartyId} 171 * @param partyprofile the {@link PartyWithProfile} that is associated with 172 * this state 173 * @return new {@link MOPACState} with the new party added. This call 174 * ignores the progress (does not check isFinal) because we uses 175 * this during the setup where the deadline is not yet relevant. 176 */ 177 protected MOPACState with(PartyId id, PartyWithProfile partyprofile) { 178 if (phase != null) 179 throw new IllegalStateException( 180 "Adding connections only allowed while initializing"); 181 182 Map<PartyId, PartyWithProfile> newprofiles = new HashMap<>( 183 partyprofiles); 184 newprofiles.put(id, partyprofile); 185 return new MOPACState(null, actions, progress, settings, newprofiles); 186 } 187 188 /** 189 * @param e the {@link ProtocolException} that occured 190 * @return a new state with the error set. You MUST have called 191 * {@link #initPhase(Progress, long)} before using this 192 */ 193 public MOPACState with(ProtocolException e) { 194 return new MOPACState(phase.with(e), actions, progress, settings, 195 partyprofiles); 189 196 } 190 197 … … 202 209 Math.min(remainingNegoTime, Phase.PHASE_MAXTIME)); 203 210 204 return new MOPACState(newphase, actions, connections, 205 incrementProgress(), getSettings(), partyprofiles); 206 } 207 208 /** 209 * 210 * @return the next progress. Progress round advances if phase is 211 * {@link OptIn}. 212 */ 213 private Progress incrementProgress() { 214 if (progress instanceof ProgressRounds && phase instanceof OptInPhase) 215 return ((ProgressRounds) progress).advance(); 216 return progress; 217 } 218 219 @Override 220 public boolean isFinal(long now) { 221 return phase != null && phase.isFinal(now) && !isNewPhasePossible(now); 211 return new MOPACState(newphase, actions, increment(progress, phase), 212 getSettings(), partyprofiles); 222 213 } 223 214 … … 225 216 * When this is called, all parties should have acted. 226 217 * 227 * @param now 228 * @return 218 * @param now current time 219 * @return true if there are still >2 parties active and we have enough 220 * time for a new phase. 229 221 */ 230 222 public boolean isNewPhasePossible(long now) { 231 223 // System.out.println("phase=" + phase); 232 boolean a = phase.getPartyStates().getNegotiatingParties().size() >= 2 233 && getAvailablePhaseTime(now) > Phase.PHASE_MINTIME; 234 // System.out.println("newstate possible:" + a); 235 return a; 236 } 237 238 @Override 239 public Agreements getAgreements() { 240 return phase.getPartyStates().getAgreements(); 241 } 242 243 @Override 244 public MOPACSettings getSettings() { 245 return settings; 224 Progress newprogress = increment(progress, phase); 225 if (newprogress.isPastDeadline(now + Phase.PHASE_MINTIME)) 226 return false; 227 228 return phase.getPartyStates().getNegotiatingParties().size() >= 2 229 && getAvailablePhaseTime(newprogress, 230 now) > Phase.PHASE_MINTIME; 246 231 } 247 232 … … 261 246 * @param now the current time in ms since 1970, see 262 247 * {@link System#currentTimeMillis()} 248 * @return new {@link MOPACState} with the action checked and registered. If 249 * the action is not allowed, the new state may be that the actor is 250 * in the exception list. 263 251 */ 264 252 265 253 public MOPACState with(PartyId actor, Action action, long now) { 266 return new MOPACState(phase.with(actor, action, now), actions, 267 connections, progress, settings, partyprofiles); 268 } 269 270 @Override 271 public SessionResult getResult() { 272 return new SessionResult(partyprofiles, getAgreements(), 273 Collections.emptyMap(), null); 254 return new MOPACState(phase.with(actor, action, now), actions, progress, 255 settings, partyprofiles); 256 } 257 258 /** 259 * @param aprogress the progress that might need to be advanced 260 * @param aphase the phase 261 * @return the next progress. Progress round advances if phase is 262 * {@link OptIn}. 263 */ 264 private static Progress increment(Progress aprogress, Phase aphase) { 265 if (aprogress instanceof ProgressRounds && aphase instanceof OptInPhase) 266 return ((ProgressRounds) aprogress).advance(); 267 return aprogress; 274 268 } 275 269 … … 294 288 public String toString() { 295 289 return "MOPACState[" + phase + "," + settings + "," + partyprofiles 296 + "," + connections + "," + progress + ","+ "]";290 + "," + progress + "]"; 297 291 } 298 292 … … 306 300 LinkedList<Action> newactions = new LinkedList<Action>(actions); 307 301 newactions.addAll(newphase.getPartyStates().getActions()); 308 return new MOPACState(newphase, newactions, connections, progress, 309 settings, partyprofiles); 302 return new MOPACState(newphase, newactions, progress, settings, 303 partyprofiles); 304 } 305 306 @Override 307 public int hashCode() { 308 final int prime = 31; 309 int result = 1; 310 result = prime * result + ((actions == null) ? 0 : actions.hashCode()); 311 result = prime * result 312 + ((partyprofiles == null) ? 0 : partyprofiles.hashCode()); 313 result = prime * result + ((phase == null) ? 0 : phase.hashCode()); 314 result = prime * result 315 + ((progress == null) ? 0 : progress.hashCode()); 316 result = prime * result 317 + ((settings == null) ? 0 : settings.hashCode()); 318 return result; 319 } 320 321 @Override 322 public boolean equals(Object obj) { 323 if (this == obj) 324 return true; 325 if (obj == null) 326 return false; 327 if (getClass() != obj.getClass()) 328 return false; 329 MOPACState other = (MOPACState) obj; 330 if (actions == null) { 331 if (other.actions != null) 332 return false; 333 } else if (!actions.equals(other.actions)) 334 return false; 335 if (partyprofiles == null) { 336 if (other.partyprofiles != null) 337 return false; 338 } else if (!partyprofiles.equals(other.partyprofiles)) 339 return false; 340 if (phase == null) { 341 if (other.phase != null) 342 return false; 343 } else if (!phase.equals(other.phase)) 344 return false; 345 if (progress == null) { 346 if (other.progress != null) 347 return false; 348 } else if (!progress.equals(other.progress)) 349 return false; 350 if (settings == null) { 351 if (other.settings != null) 352 return false; 353 } else if (!settings.equals(other.settings)) 354 return false; 355 return true; 310 356 } 311 357
Note:
See TracChangeset
for help on using the changeset viewer.