Changeset 24 for protocol/src/main
- Timestamp:
- 10/06/20 13:12:20 (4 years ago)
- Location:
- protocol/src/main/java/geniusweb/protocol
- Files:
-
- 1 added
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
protocol/src/main/java/geniusweb/protocol/NegoProtocol.java
r21 r24 13 13 import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory; 14 14 import geniusweb.protocol.session.SessionProtocol; 15 import geniusweb.protocol.session.SessionSettings;16 15 import geniusweb.protocol.session.SessionState; 17 16 import geniusweb.protocol.tournament.TournamentProtocol; … … 30 29 * 31 30 * A protocol is mutable because the incoming connections cause state changes. 32 * But it is recommended to push all changing properties into the state. 31 * But it is recommended to push changing properties into the state so that the 32 * complete state can be recovered and analysed. 33 33 * <p> 34 34 * Because a protocol contains an internal state, it can be used only once. 35 * <p>36 35 * <p> 37 36 * The protocol can emit a {@link CurrentState} event at any time. It should do … … 42 41 * which it can resolve received {@link Reference}s. <br> 43 42 * First call to instances <b>must be</b> 44 * {@link #start( SessionSettings, ConnectionFactory)}.43 * {@link #start(ProtocolToPartyConnFactory)}. 45 44 * 46 45 * <h2>Ensure time deadline</h2> … … 48 47 * The protocol also needs to keep an eye on the deadline and take appropriate 49 48 * actions when the deadline is reached. <br> 50 * A protocol should emit a {@link SessionEnded} or {@link TournamentEnded}51 * event when it is finished.52 49 * <p> 53 50 * All protocol implementations must ensure that the deadline is kept and that … … 73 70 * <p> 74 71 * 75 * All errors are to be handled through {@link SessionState#getError()} 76 * except for plain {@link IllegalArgumentException}s. <br> 72 * All errors are to be handled through {@link SessionState#getResult()} 73 * except for bugs that use {@link RuntimeException} like 74 * {@link IllegalArgumentException}s. <br> 77 75 * The protocol usually uses the incoming connections to keep running. It 78 76 * does not need to run in a separate thread or so. -
protocol/src/main/java/geniusweb/protocol/NegoState.java
r21 r24 11 11 12 12 /** 13 * The current state of the session/tournament. Must be serializabl;e so that it 14 * can be restarted if a crash occurs. 13 * The current state of the session/tournament. Must be (de)serializabl;e so 14 * that it can be restarted if a crash occurs. Notice that this restart 15 * functionality is not yet available. 16 * <p> 17 * In general the state contains all the information to control the flow of the 18 * negotiation: who did what, are we finished, etc. This object may be stored to 19 * record the final result as well 15 20 */ 16 21 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE) -
protocol/src/main/java/geniusweb/protocol/ProtocolException.java
r21 r24 5 5 6 6 /** 7 * thrown if a {@link Party} violates the protocols (that includes 8 * disconnecting). 7 * thrown if a Party violates the protocols (that includes disconnecting). 9 8 */ 10 9 public class ProtocolException extends Exception { -
protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConnections.java
r21 r24 49 49 50 50 /** 51 * Broadcast info to all parties 51 * Broadcast info to all parties. Notice that the broadcast immediately 52 * aborts if an error occurs and remaining parties will not receive the 53 * event. Therefore it is recommended to instead send to all parties 54 * individually to ensure all parties are handled individually. 52 55 * 53 56 * @param info the {@link Inform} to broadcast 57 * @throws IOException if the send fails. 54 58 */ 55 59 public void broadcast(Inform info) throws IOException { … … 68 72 69 73 /** 70 * @param i 74 * @param i the connection number 71 75 * @return the ith connection 72 76 */ -
protocol/src/main/java/geniusweb/protocol/session/SessionResult.java
r23 r24 67 67 68 68 /** 69 * 8return the final {@link Agreements} of the session. May be empty, not70 * null69 * @return the final {@link Agreements} of the session. May be empty, not 70 * null 71 71 */ 72 72 public Agreements getAgreements() { -
protocol/src/main/java/geniusweb/protocol/session/SessionState.java
r21 r24 18 18 * and the parties currently connected. <br> 19 19 * The state checks if transitions (Actions from the party) are following the 20 * protocol, and thus implement most of the protocol . See 21 * {@link #with(geniusweb.actions.PartyId, Action)}. <br> 22 * 23 * Use {@link #with(geniusweb.actions.PartyId, Action)} and 24 * {@link #with(geniusweb.actions.PartyId, tudelft.utilities.connection.Connection)} 25 * to create a new state <br> 26 * 20 * protocol, and thus implement most of the protocol . <br> 27 21 * 28 22 * If protocol errors occur, these should be stored in the state and the state 29 * should become {@link #isFinal( )}. Throwing should happen only in case of a30 * bug.<br>23 * should become {@link #isFinal(long)}. Throwing should happen only in case of 24 * a bug.<br> 31 25 * 32 26 * Implementations should be immutable (to ensure thread safety, testability … … 66 60 * @return the current standing agreement, or null if there is no agreement 67 61 * at this point. An agreement does not necessarily mean 68 * {@link #isFinal( )}.62 * {@link #isFinal(long)}. 69 63 */ 70 64 Agreements getAgreements(); … … 72 66 /** 73 67 * 74 * @return the {@link SessionResult}. Assumes {@link #isFinal(long)}. result 75 * may be undefined if not. 68 * @return the {@link SessionResult} which is a short report of the final 69 * outcome. Assumes {@link #isFinal(long)}. result may be undefined 70 * if not. 76 71 */ 77 72 SessionResult getResult(); -
protocol/src/main/java/geniusweb/protocol/session/amop/AMOP.java
r21 r24 28 28 import geniusweb.protocol.CurrentNegoState; 29 29 import geniusweb.protocol.ProtocolException; 30 import geniusweb.protocol.WillBeCalled;31 30 import geniusweb.protocol.partyconnection.ProtocolToPartyConn; 32 31 import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory; … … 51 50 * <h1>parameter</h1> AMOP parties can receive a parameter: minVotes containing 52 51 * a Double. If set, the AMOP protocol checks that all {@link Votes} from that 53 * party have {@link Vote#getMinPower()} > minVotes. 54 * <h1>Protocol steps</h1> The protocol tries to start all parties. If not all 55 * parties start, the parties are freed up and another attempt is done to start 56 * all parties some time later. 52 * party have {@link Vote#getMinPower()} > minVotes. 53 * <h1>Protocol steps</h1> 54 * <ol> 55 * <li>The protocol tries to start all parties. If not all parties start, the 56 * parties are freed up and another attempt is done to start all parties some 57 * time later. 57 58 * <li>the variable remainingparties = {all parties} 58 59 * <li>The session deadline clock now starts ticking. 59 60 * <li>All parties are sent their settings. 60 * <li>Loop until {@link Deadline} is reached or |remainingparties| <2:61 * <li>Loop until {@link Deadline} is reached or |remainingparties|<2: 61 62 * <ol> 62 63 * <li>protocol sends {@link YourTurn} to all remainingparties. Each party now 63 64 * must submit an {@link Offer} within {@link #PHASE_TIME} seconds. If a party 64 65 * fails to submit it is send Finished and removed from from remainingparties. 65 * <li>protocol sends a {@link Voting} containing a List <Bid> containing all66 * received {@link Bid}s. Each party must place his {@link Votes} within67 * {@link #PHASE_TIME} seconds. If a party does not submit, it is send a66 * <li>protocol sends a {@link Voting} containing a List of {@link Bid} 67 * containing all received {@link Bid}s. Each party must place his {@link Votes} 68 * within {@link #PHASE_TIME} seconds. If a party does not submit, it is send a 68 69 * {@link Finished} and removed from remainingparties. Previous votes for the 69 70 * same bid do not count. But see {@link Agreements}. 70 * <li>The protocol determines a maximum sized subset of size N >=2 of the votes71 * for bid B for which the vote conditions hold. If there is such a subset, the72 * parties that placed these votes reached an agreement. They are added to the73 * a greement set, sent the {@link Finished} info and terminated. They are74 * removed from the remainingparties.71 * <li>The protocol determines a maximum sized subset of size N≥2 of the 72 * votes for bid B for which the vote conditions hold. If there is such a 73 * subset, the parties that placed these votes reached an agreement. They are 74 * added to the agreement set, sent the {@link Finished} info and terminated. 75 * They are removed from the remainingparties. 75 76 * </ol> 76 77 * <li>Any remaining parties are sent a {@link Finished} object without … … 109 110 /** 110 111 * 111 * @param state normally the initial state coming from SAOPSettings 112 * @param state normally the initial state coming from SAOPSettings 113 * @param logger the {@link Reporter} to use 112 114 */ 113 115 public AMOP(AMOPState state, Reporter logger) { … … 218 220 * overridable factory method, used for testing. 219 221 * 220 * @param r 221 * @param delayMs 222 * @param r the {@link Runnable} that will be called 223 * @param delayMs the time after which r will be called 222 224 * @return new WillBeCalled(r,delayms) 223 225 */ -
protocol/src/main/java/geniusweb/protocol/session/amop/AMOPSettings.java
r21 r24 30 30 * protocol. But SAOP can be initialized with less, for 31 31 * use in TournamentSettings. 32 * @param deadline 33 * @param minimumVotes the minimum number of votes allowed for a bid. 32 * @param deadline the {@link Deadline} of the negotiation 34 33 */ 35 34 @JsonCreator -
protocol/src/main/java/geniusweb/protocol/session/amop/AMOPState.java
r23 r24 197 197 198 198 /** 199 * @param actor the actor that did this action. Can be used to check 200 * if action is valid. NOTICE caller has to make sure 201 * the current state is not final. MUST NOT be null. 202 * @param action the action that was proposed by actor. MUST NOT be 203 * null. 204 * @param currentTimeMs the current time in ms since 1970, see 205 * {@link System#currentTimeMillis()} 199 * @param actor the actor that did this action. Can be used to check if 200 * action is valid. NOTICE caller has to make sure the current 201 * state is not final. MUST NOT be null. 202 * @param action the action that was proposed by actor. MUST NOT be null. 206 203 * @return new SessionState with the action added as last action. 207 204 * @throws ProtocolException if actor is violating the protocol -
protocol/src/main/java/geniusweb/protocol/session/mopac/MOPAC.java
r23 r24 2 2 3 3 import java.io.IOException; 4 import java.util.Collections; 4 5 import java.util.List; 5 6 import java.util.Timer; … … 55 56 * parties are freed up and another attempt is done to start all parties some 56 57 * time later. 57 * <li>the variable remainingparties = {all parties}58 58 * <li>The session deadline clock now starts ticking. 59 59 * <li>remainingparties are sent their settings. 60 * <li>Loop until {@link Deadline} is reached or |remainingparties| <2:60 * <li>Loop until {@link Deadline} is reached or |remainingparties| ≤ 2: 61 61 * <ol> 62 62 * <li>protocol sends {@link YourTurn} to all remainingparties. Each party now 63 63 * must submit an {@link Offer} within {@link Phase#PHASE_MAXTIME} seconds. If a 64 64 * party fails to submit it is removed from from remainingparties. 65 * <li>protocol sends a {@link Voting} containing a List <Bid>containing all66 * received {@link Bid}s. Each party must place his {@link Votes} within 67 * {@link #PHASE_TIME} seconds. If a party does not submit, it is terminated and68 * removed from remainingparties. Previous votes for the same bid do not count.69 * But see {@link Agreements}. A party that misbehaves after submitting its vote70 * isremoved but it Votes remain standing.65 * <li>protocol sends a {@link Voting} containing a List of Bid containing all 66 * received {@link Bid}s. Each party must place his {@link Votes} within the 67 * provided deadline. If a party does not submit, it is terminated and removed 68 * from remainingparties. Previous votes for the same bid do not count. But see 69 * {@link Agreements}. A party that misbehaves after submitting its vote is 70 * removed but it Votes remain standing. 71 71 * <li>protocol sends to all remainingparties a OptIn containing all received 72 * votes. Each party now must submit again a {@link Votes} object within 73 * {@link #PHASE_TIME} seconds. This new Votes must equal or extend the previous74 * Votes of theparty.75 * <li>The protocol use the {@link MOPACState#getEvaluator()} to determine the76 * ... . If there is such a subset, the parties that placed these votes reached77 * an agreement. They are added to the agreement set, sent the {@link Finished}78 * info and terminated. They areremoved from the remainingparties.72 * votes. Each party now must submit again a {@link Votes} object within the 73 * deadline. This new Votes must equal or extend the previous Votes of the 74 * party. 75 * <li>The protocol uses the {@link Phase#getEvaluator()} to determine the 76 * agreements from the votes. If there are agreements, the parties that placed 77 * these votes reached an agreement. They are moved to the agreement set and 78 * removed from the remainingparties. 79 79 * </ol> 80 80 * <li>Any remaining parties are sent a {@link Finished} object without … … 114 114 private final Reporter log; 115 115 private MOPACState state = null; // mutable! 116 /** 117 * the existing party connections. we assume ownership of this so it should 118 * not be modified although connections may of course break. mutable! 119 */ 120 private ProtocolToPartyConnections connections = new ProtocolToPartyConnections( 121 Collections.emptyList()); 116 122 117 123 /** … … 124 130 /** 125 131 * 126 * @param state normally the initial state coming from SAOPSettings 132 * @param state normally the initial state coming from SAOPSettings 133 * @param logger the {@link Reporter} to use 127 134 */ 128 135 public MOPAC(MOPACState state, Reporter logger) { … … 145 152 ProtocolToPartyConnFactory connectionfactory) { 146 153 try { 147 // System.out.println("starting MOPAC");148 // we're in Phase.INIT still149 154 connect(connectionfactory); 150 setupParties();151 long now = System.currentTimeMillis();152 state = state.initPhase(now);153 startPhase(now);154 155 } catch (Throwable e) { 155 e.printStackTrace(); 156 handleError("Failed to start MOPAC session", new PartyId("BUG"), e); 157 } 156 /** We can't {@link #handleError} yet. FIXME */ 157 throw new RuntimeException("Failed to connect", e); 158 } 159 long now = System.currentTimeMillis(); 160 state = state.initPhase( 161 ProgressFactory.create(state.getSettings().getDeadline(), now), 162 now); 163 setupParties(now); 164 startPhase(now); 165 158 166 } 159 167 … … 212 220 .map(parti -> (parti.getParty().getPartyRef())) 213 221 .collect(Collectors.toList()); 214 List<ProtocolToPartyConn> connections = null;215 222 log.log(Level.INFO, "MOPAC connect " + parties); 216 while (connections == null) { 223 List<ProtocolToPartyConn> newconnections = null; 224 while (newconnections == null) { 217 225 try { 218 connections = connectionfactory.connect(parties);226 newconnections = connectionfactory.connect(parties); 219 227 } catch (NoResourcesNowException e) { 220 228 long waitms = e.getLater().getTime() … … 228 236 } 229 237 for (int i = 0; i < participants.size(); i++) { 230 state = state.with(connections.get(i), participants.get(i)); 238 ProtocolToPartyConn conn = newconnections.get(i); 239 connections = connections.with(conn); 240 state = state.with(conn.getParty(), participants.get(i)); 231 241 } 232 242 } … … 239 249 * part of the interface. 240 250 * 241 * @throws ProtocolException if a party does not follow the protocol 242 */ 243 protected synchronized void setupParties() throws ProtocolException { 244 for (ProtocolToPartyConn conn : state.getConnections()) { 245 conn.addListener(action -> actionRequest(conn, action, 246 System.currentTimeMillis())); 247 } 248 Long now = System.currentTimeMillis(); 249 state = state.with( 250 ProgressFactory.create(state.getSettings().getDeadline(), now)); 251 for (ProtocolToPartyConn connection : state.getConnections()) { 251 * @param now the current time. 252 */ 253 protected synchronized void setupParties(long now) { 254 for (ProtocolToPartyConn conn : connections) { 255 conn.addListener(action -> actionRequest(conn, action, now)); 256 } 257 for (ProtocolToPartyConn connection : connections) { 252 258 try { 253 259 sendSettings(connection); … … 257 263 } 258 264 } 259 260 265 } 261 266 … … 357 362 .getNegotiatingParties()) { 358 363 try { 359 state.getConnections().get(party).send(info);364 connections.get(party).send(info); 360 365 } catch (IOException e) { 361 handleError("Party seems to have disconnected", party, e); 362 } 363 } 364 } 365 366 /** 367 * Update state to include the given error and closes the party. 368 * 369 * @param message The message to attach to the error 370 * @param party the party where the error occured 371 * @param e the exception that occured. 372 */ 373 private void handleError(final String message, final PartyId partyid, 374 final Throwable e) { 375 if (e instanceof ProtocolException) { 376 state = state.with((ProtocolException) e); 377 } else { 378 state = state.with(new ProtocolException(message, partyid, e)); 379 } 380 log.log(Level.WARNING, 381 "MOPAC intercepted error from party " + partyid + ":" + message, 382 e); 383 } 384 385 // /** 386 // * Sets the new state. If the new state is final, the finish-up procedure is 387 // * executed. All state changes go through here to ensure we check isFinal 388 // * before any state change. 389 // * 390 // * @param newstate the new state. 391 // */ 392 // private synchronized void setState(MOPACState newstate) { 393 // long now = System.currentTimeMillis(); 394 // if (state.isFinal(now)) { 395 // endNegotiation(); 396 // return; 397 // } 398 // 399 // this.state = newstate; 400 // if (newstate.isFinal(now)) { 401 // endNegotiation(); 402 // } 403 // } 366 state = state.with(new ProtocolException( 367 "Party seems to have disconnected", party, e)); 368 } 369 } 370 } 404 371 405 372 /** … … 413 380 finished = true; 414 381 Finished info = new Finished(state.getAgreements()); 415 for (ProtocolToPartyConn conn : state.getConnections()) {382 for (ProtocolToPartyConn conn : connections) { 416 383 try { 417 384 conn.send(info); -
protocol/src/main/java/geniusweb/protocol/session/mopac/MOPACSettings.java
r21 r24 19 19 /** 20 20 * Settings for MOPAC negotiation. in MOPAC, each party may get a "power" 21 * parameter containing an natural number >=1.21 * parameter containing an natural number ≤1. 22 22 */ 23 23 public class MOPACSettings implements SessionSettings { … … 30 30 * @param participants the list of {@link PartyWithProfile} in clockwise 31 31 * order. There must be at least 2 to run the MOPAC 32 * protocol. But SAOP can be initialized with less, for 33 * use in TournamentSettings. 34 * 35 * All provided participants must 36 * 37 * @param deadline 38 * @param minimumVotes the minimum number of votes allowed for a bid. 32 * protocol. This is not tested in the constructor 33 * because this can be initialized with less, for use in 34 * TournamentSettings. 35 * @param deadline the {@link Deadline} for the negotiation 36 * @param votingeval the {@link VotingEvaluator} to use. 39 37 */ 40 38 @JsonCreator … … 90 88 91 89 @Override 92 public SessionSettings with(TeamOfPartiesAndProfiles party) {90 public MOPACSettings with(TeamOfPartiesAndProfiles party) { 93 91 if (!(party instanceof OnePartyTeam)) 94 92 throw new IllegalArgumentException( -
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 -
protocol/src/main/java/geniusweb/protocol/session/mopac/PartyStates.java
r21 r24 1 1 package geniusweb.protocol.session.mopac; 2 2 3 import java.util.Arrays;4 import java.util.Collection;5 3 import java.util.Collections; 6 4 import java.util.HashMap; … … 12 10 import java.util.stream.Collectors; 13 11 12 import com.fasterxml.jackson.annotation.JsonAutoDetect; 13 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; 14 import com.fasterxml.jackson.annotation.JsonCreator; 15 import com.fasterxml.jackson.annotation.JsonProperty; 16 14 17 import geniusweb.actions.Action; 15 18 import geniusweb.actions.EndNegotiation; … … 19 22 20 23 /** 21 * The current state of all participating parties. A party either notYetActed,22 * did action, reached an agreement, walked away or made a24 * Invariant: contains the current state of all participating parties. A party 25 * either notYetActed, did action, reached an agreement, walked away or made a 23 26 * {@link ProtocolException}. 24 27 * <p> … … 26 29 * agreements and move remaining parties back to notYetActed. 27 30 * 28 * This is not considering current time or checking actions.29 31 */ 32 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE) 30 33 public class PartyStates { 31 34 // all parties must be in exactly one state at all times. … … 35 38 private final List<PartyId> walkedAway; 36 39 private final Map<PartyId, ProtocolException> exceptions; 37 private Map<PartyId, Integer> powers; 40 private final Map<PartyId, Integer> powers; 41 42 @JsonCreator 43 protected PartyStates(@JsonProperty("notYetActed") Set<PartyId> notYetActed, 44 @JsonProperty("actions") List<Action> actions, 45 @JsonProperty("agreements") Agreements agreements, 46 @JsonProperty("walkedAway") List<PartyId> walkedAway, 47 @JsonProperty("exceptions") Map<PartyId, ProtocolException> exceptions, 48 @JsonProperty("powers") Map<PartyId, Integer> powers) { 49 this.notYetActed = notYetActed; 50 this.actions = actions; 51 this.agreements = agreements; 52 this.walkedAway = walkedAway; 53 this.exceptions = exceptions; 54 this.powers = powers; 55 } 38 56 39 57 /** … … 51 69 } 52 70 53 public PartyStates(Set<PartyId> notYetActed, List<Action> actions, 54 Agreements agreements, List<PartyId> walkedAway, 55 Map<PartyId, ProtocolException> exceptions, 56 Map<PartyId, Integer> powers) { 57 this.notYetActed = notYetActed; 58 this.actions = actions; 59 this.agreements = agreements; 60 this.walkedAway = walkedAway; 61 this.exceptions = exceptions; 62 this.powers = powers; 63 } 64 65 /** 66 * 67 * @param action 68 * @return new state with party done given action. 71 /** 72 * 73 * @param action the action done by some party. The correctness of action, 74 * particularly of {@link Action#getActor()}, must be correct. 75 * @return new state with party done given action. This just accepts any 76 * given action and is not considering number of rounds, time or 77 * whether an action is allowed. 78 * 69 79 * @throws IllegalArgumentException if party doing action already acted. 70 80 * This is just a safety check as legality … … 151 161 152 162 /** 153 *154 163 * @param actor 155 164 * @return {@link #notYetActed} with actor removed 156 */ 157 private Set<PartyId> removeParty(PartyId actor) { 158 return removeParties(new HashSet<>(Arrays.asList(actor))); 165 * @throws IllegalArgumentException if party already acted (not in 166 * {@link #notYetActed}). 167 */ 168 private Set<PartyId> removeParty(PartyId party) { 169 Set<PartyId> newActiveParties = new HashSet<>(notYetActed); 170 if (!newActiveParties.remove(party)) 171 throw new IllegalArgumentException( 172 "Party " + party + " is not active, can't be removed"); 173 return newActiveParties; 174 159 175 } 160 176 … … 169 185 public Map<PartyId, ProtocolException> getExceptions() { 170 186 return Collections.unmodifiableMap(exceptions); 171 }172 173 /**174 *175 * @param parties the parties to remove176 * @return {@link #notYetActed} without the given parties.177 */178 private Set<PartyId> removeParties(Collection<PartyId> parties) {179 Set<PartyId> newActiveParties = new HashSet<>(notYetActed);180 for (PartyId party : parties) {181 if (!newActiveParties.remove(party))182 throw new IllegalArgumentException(183 "Party " + party + " is not active, can't be removed");184 }185 return newActiveParties;186 187 } 187 188 … … 204 205 205 206 /** 206 * @param type the type of actions to extract 207 * 208 * @return all parties that walked away 209 */ 210 public List<PartyId> getWalkedAway() { 211 return walkedAway; 212 } 213 214 /** 215 * @param <T> the type of objects requested 216 * @param type the type of actions to extract. Must be of type T, needed 217 * because of java's type erasure. 218 * 207 219 * @return all actions of type done in this phase 208 220 */ … … 233 245 } 234 246 247 @Override 248 public int hashCode() { 249 final int prime = 31; 250 int result = 1; 251 result = prime * result + ((actions == null) ? 0 : actions.hashCode()); 252 result = prime * result 253 + ((agreements == null) ? 0 : agreements.hashCode()); 254 result = prime * result 255 + ((exceptions == null) ? 0 : exceptions.hashCode()); 256 result = prime * result 257 + ((notYetActed == null) ? 0 : notYetActed.hashCode()); 258 result = prime * result + ((powers == null) ? 0 : powers.hashCode()); 259 result = prime * result 260 + ((walkedAway == null) ? 0 : walkedAway.hashCode()); 261 return result; 262 } 263 264 @Override 265 public boolean equals(Object obj) { 266 if (this == obj) 267 return true; 268 if (obj == null) 269 return false; 270 if (getClass() != obj.getClass()) 271 return false; 272 PartyStates other = (PartyStates) obj; 273 if (actions == null) { 274 if (other.actions != null) 275 return false; 276 } else if (!actions.equals(other.actions)) 277 return false; 278 if (agreements == null) { 279 if (other.agreements != null) 280 return false; 281 } else if (!agreements.equals(other.agreements)) 282 return false; 283 if (exceptions == null) { 284 if (other.exceptions != null) 285 return false; 286 } else if (!exceptions.equals(other.exceptions)) 287 return false; 288 if (notYetActed == null) { 289 if (other.notYetActed != null) 290 return false; 291 } else if (!notYetActed.equals(other.notYetActed)) 292 return false; 293 if (powers == null) { 294 if (other.powers != null) 295 return false; 296 } else if (!powers.equals(other.powers)) 297 return false; 298 if (walkedAway == null) { 299 if (other.walkedAway != null) 300 return false; 301 } else if (!walkedAway.equals(other.walkedAway)) 302 return false; 303 return true; 304 } 305 235 306 } -
protocol/src/main/java/geniusweb/protocol/session/mopac/phase/DefaultPhase.java
r23 r24 1 1 package geniusweb.protocol.session.mopac.phase; 2 3 import java.util.List;4 import java.util.stream.Collectors;5 6 import com.fasterxml.jackson.annotation.JsonIgnore;7 2 8 3 import geniusweb.actions.Action; 9 4 import geniusweb.actions.PartyId; 10 import geniusweb.actions.Votes;11 5 import geniusweb.protocol.ProtocolException; 12 6 import geniusweb.protocol.session.mopac.PartyStates; … … 17 11 protected final Long deadline; 18 12 protected final PartyStates partyStates; 19 20 // don't serialize this, users don't need it..21 @JsonIgnore22 13 protected final VotingEvaluator evaluator; 23 14 24 // don't serialize this, it will cause very large file25 @JsonIgnore26 protected final Phase prevPhase;27 28 15 /** 29 * 30 * @param actions the actions done in this phase . 31 * @param prevPhase the previous phase, can be used to collect previous 32 * votes etc. 33 * @param partyStates 16 * @param partyStates the {@link PartyStates} 34 17 * @param deadline deadline for this phase, ms since 1970 18 * @param evaluator the {@link VotingEvaluator} to be used 35 19 */ 36 public DefaultPhase(P hase prevPhase, PartyStates partyStates, Long deadline,20 public DefaultPhase(PartyStates partyStates, Long deadline, 37 21 VotingEvaluator evaluator) { 38 22 this.partyStates = partyStates; 39 23 this.deadline = deadline; 40 this.prevPhase = prevPhase;41 24 this.evaluator = evaluator; 42 25 } … … 53 36 54 37 /** 55 * @return all votes done in this phase.56 */57 public List<Votes> getVotes() {58 return partyStates.getActions().stream()59 .filter(act -> act instanceof Votes).map(act -> (Votes) act)60 .collect(Collectors.toList());61 }62 63 /**64 38 * Check if actor can do given action. Basic checks: 65 39 * <ul> … … 70 44 * </ul> 71 45 * 72 * @param activeParties the currently active parties 73 * @param actor 74 * @param action 75 * @param timems 76 * @throws ProtocolException 77 * @throw ProtocolException if the action violates the protocol, or null if 78 * ok 46 * @param actor the actor that really acted 47 * @param action the action that was done 48 * @param now current time 49 * @throws ProtocolException if the action violates the protocol 79 50 */ 80 protected void checkAction(PartyId actor, Action action, long timems)51 protected void checkAction(PartyId actor, Action action, long now) 81 52 throws ProtocolException { 82 53 if (action == null) … … 86 57 "Incorrect actor info in action:" + action.getActor(), 87 58 actor); 88 if (isFinal( timems))59 if (isFinal(now)) 89 60 throw new ProtocolException("passed deadline", actor); 90 61 if (!(getAllowedActions().contains(action.getClass()))) 91 throw new ProtocolException( 92 "Action not allowed in " + this.getClass() + ":" + action, 93 actor); 62 throw new ProtocolException("Action not allowed in " 63 + this.getClass().getSimpleName() + ": " + action, actor); 94 64 if (!partyStates.getNotYetActed().contains(actor)) 95 65 throw new ProtocolException("Actor can not act anymore", actor); … … 98 68 99 69 /** 100 * @param timems current time101 70 * @return current PartyStates 102 71 */ … … 116 85 throw new IllegalArgumentException("Bug, illegal duration"); 117 86 if (!isFinal(now)) 118 throw new IllegalStateException( 119 "next must only be called when phase isFinal"); 120 if (!partyStates.getNotYetActed().isEmpty()) 121 throw new IllegalStateException("Bug. State has not been finished"); 87 throw new IllegalStateException("phase is not final"); 122 88 return checkedNext(now + duration); 123 89 } 124 90 125 91 /** 92 * As {@link #next(long, long)} but DefaultPhase already checked that 1. 93 * there is enough time for a next phase 2. current state is final 3. 126 94 * 127 * @param d eadline95 * @param dl the deadline for the next phase (ms since 1970). 128 96 * @return the next phase 129 97 */ 130 protected abstract Phase checkedNext(long d eadline);98 protected abstract Phase checkedNext(long dl); 131 99 132 100 @Override 133 101 public String toString() { 134 // don't print prev state, it will give HUGE list because it also135 // contains prevstate.....136 102 return getClass().getSimpleName() + "[" + partyStates + "," + deadline 137 103 + "," + evaluator + "]"; 138 104 } 105 106 @Override 107 public int hashCode() { 108 final int prime = 31; 109 int result = 1; 110 result = prime * result 111 + ((deadline == null) ? 0 : deadline.hashCode()); 112 result = prime * result 113 + ((evaluator == null) ? 0 : evaluator.hashCode()); 114 result = prime * result 115 + ((partyStates == null) ? 0 : partyStates.hashCode()); 116 return result; 117 } 118 119 @Override 120 public boolean equals(Object obj) { 121 if (this == obj) 122 return true; 123 if (obj == null) 124 return false; 125 if (getClass() != obj.getClass()) 126 return false; 127 DefaultPhase other = (DefaultPhase) obj; 128 if (deadline == null) { 129 if (other.deadline != null) 130 return false; 131 } else if (!deadline.equals(other.deadline)) 132 return false; 133 if (evaluator == null) { 134 if (other.evaluator != null) 135 return false; 136 } else if (!evaluator.equals(other.evaluator)) 137 return false; 138 if (partyStates == null) { 139 if (other.partyStates != null) 140 return false; 141 } else if (!partyStates.equals(other.partyStates)) 142 return false; 143 return true; 144 } 139 145 } -
protocol/src/main/java/geniusweb/protocol/session/mopac/phase/OfferPhase.java
r23 r24 4 4 import java.util.List; 5 5 import java.util.stream.Collectors; 6 7 import com.fasterxml.jackson.annotation.JsonCreator; 8 import com.fasterxml.jackson.annotation.JsonProperty; 6 9 7 10 import geniusweb.actions.Action; … … 18 21 public class OfferPhase extends DefaultPhase { 19 22 20 public OfferPhase(Phase prevPhase, PartyStates partyStates, Long deadlinems, 21 VotingEvaluator evaluator) { 22 super(prevPhase, partyStates, deadlinems, evaluator); 23 @JsonCreator 24 public OfferPhase(@JsonProperty("partyStates") PartyStates partyStates, 25 @JsonProperty("deadlinems") Long deadlinems, 26 @JsonProperty("evaluator") VotingEvaluator evaluator) { 27 super(partyStates, deadlinems, evaluator); 23 28 } 24 29 … … 30 35 return this.with(ex); 31 36 } 32 return new OfferPhase(prevPhase, partyStates.with(action), deadline, 33 evaluator); 37 return new OfferPhase(partyStates.with(action), deadline, evaluator); 34 38 } 35 39 … … 42 46 public OfferPhase with(ProtocolException e) { 43 47 System.out.println("Party kicked because of protocol exception:" + e); 44 return new OfferPhase(prevPhase, partyStates.with(e), deadline, 45 evaluator); 48 return new OfferPhase(partyStates.with(e), deadline, evaluator); 46 49 } 47 50 48 51 @Override 49 52 public Phase finish() { 50 return new OfferPhase(prevPhase, partyStates.finish(), deadline, 51 evaluator); 53 return new OfferPhase(partyStates.finish(), deadline, evaluator); 52 54 } 53 55 54 56 @Override 55 57 public VotingPhase checkedNext(long deadln) { 56 return new VotingPhase(this, partyStates.flush(), deadln, evaluator); 58 return new VotingPhase(getOffers(), partyStates.flush(), deadln, 59 evaluator); 57 60 } 58 61 59 p ublicList<Bid> getOffers() {62 protected List<Bid> getOffers() { 60 63 return partyStates.getActions(Offer.class).stream() 61 64 .map(offer -> offer.getBid()).collect(Collectors.toList()); -
protocol/src/main/java/geniusweb/protocol/session/mopac/phase/OptInPhase.java
r23 r24 5 5 import java.util.Map; 6 6 import java.util.stream.Collectors; 7 8 import com.fasterxml.jackson.annotation.JsonCreator; 9 import com.fasterxml.jackson.annotation.JsonProperty; 7 10 8 11 import geniusweb.actions.Action; … … 20 23 public class OptInPhase extends DefaultPhase { 21 24 22 protected OptInPhase(Phase prevPhase, PartyStates partyStates, 23 Long deadlinems, VotingEvaluator evaluator) { 24 super(prevPhase, partyStates, deadlinems, evaluator); 25 /** 26 * The votes received in the {@link VotingPhase} 27 */ 28 private final List<Votes> votes; 29 30 @JsonCreator 31 protected OptInPhase(@JsonProperty("votes") List<Votes> votes, 32 @JsonProperty("partyStates") PartyStates partyStates, 33 @JsonProperty("deadlinems") Long deadlinems, 34 @JsonProperty("evaluator") VotingEvaluator evaluator) { 35 super(partyStates, deadlinems, evaluator); 36 this.votes = votes; 25 37 } 26 38 27 39 @Override 28 40 public Inform getInform() { 29 return new OptIn( ((VotingPhase) prevPhase).getVotes());41 return new OptIn(votes); 30 42 } 31 43 … … 35 47 checkAction(actor, action, now); 36 48 if (action instanceof Votes) 37 checkExtends( action);49 checkExtends((Votes) action); 38 50 39 return new OptInPhase( prevPhase, partyStates.with(action), deadline,51 return new OptInPhase(votes, partyStates.with(action), deadline, 40 52 evaluator); 41 53 … … 48 60 * Check that this action extends previous action. 49 61 * 50 * @param action 51 * @param phase 62 * @param newvotes new {@link Votes} just received 52 63 * @throws ProtocolException if this action does not correctly extend 53 64 * previous vote. 54 65 */ 55 private void checkExtends(Action action) throws ProtocolException { 56 57 Votes votes = (Votes) action; 58 PartyId actor = action.getActor(); 66 private void checkExtends(Votes newvotes) throws ProtocolException { 67 PartyId actor = newvotes.getActor(); 59 68 // this actor is active so he must have voted in previous round. 60 Votes prevVotes = ((VotingPhase) prevPhase).getVotes().stream()61 .fi lter(v -> v.getActor().equals(actor)).findFirst().get();62 if (!( votes.isExtending(prevVotes)))63 throw new ProtocolException("New votes " + action69 Votes prevVotes = votes.stream().filter(v -> v.getActor().equals(actor)) 70 .findFirst().get(); 71 if (!(newvotes.isExtending(prevVotes))) 72 throw new ProtocolException("New votes " + newvotes 64 73 + " does not extend previous vote " + prevVotes, actor); 65 74 } … … 67 76 @Override 68 77 public OptInPhase with(ProtocolException e) { 69 return new OptInPhase(prevPhase, partyStates.with(e), deadline, 70 evaluator); 78 return new OptInPhase(votes, partyStates.with(e), deadline, evaluator); 71 79 } 72 80 … … 84 92 PartyStates finalStates = states.with(newAgree); 85 93 86 return new OptInPhase( prevPhase, finalStates, deadline, evaluator);94 return new OptInPhase(votes, finalStates, deadline, evaluator); 87 95 } 88 96 89 97 @Override 90 98 public OfferPhase checkedNext(long newdeadline) { 91 return new OfferPhase(this, partyStates.flush(), newdeadline, 92 evaluator); 99 return new OfferPhase(partyStates.flush(), newdeadline, evaluator); 93 100 } 94 101 -
protocol/src/main/java/geniusweb/protocol/session/mopac/phase/Phase.java
r23 r24 2 2 3 3 import java.util.List; 4 import java.util.Set;5 4 6 5 import com.fasterxml.jackson.annotation.JsonAutoDetect; 7 6 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; 7 import com.fasterxml.jackson.annotation.JsonSubTypes; 8 import com.fasterxml.jackson.annotation.JsonTypeInfo; 8 9 9 10 import geniusweb.actions.Action; … … 17 18 * A Phase is a part of the round structure. In each round parties have to take 18 19 * multiple actions. Each action is part of a phase. 19 * 20 * 21 * Invariant: A phase object handles negotiation events, ensuring that the 22 * events are handled according to the possible actions in this phase. A phase 23 * object must always remain in a consistent state. It does so by modifying the 24 * contained {@link PartyStates} as needed. 25 * <p> 26 * The standard exception handling is assumed: unchecked exceptions are thrown 27 * only if there is a bug in the protocol. Because none of the functions in this 28 * interface throws, any error must be either ignored or the party must be 29 * kicked. 20 30 */ 21 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE) 31 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) 32 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE) 33 @JsonSubTypes({ @JsonSubTypes.Type(value = OfferPhase.class), 34 @JsonSubTypes.Type(value = OptInPhase.class), 35 @JsonSubTypes.Type(value = VotingPhase.class) }) 22 36 public interface Phase { 23 37 public static final Long PHASE_MAXTIME = 30000l; // 30sec … … 28 42 * handled by updating the PartyStates 29 43 * 30 * @param prevPhases the list of all previous phases31 * @param actor the real actor32 * @param action the action submitted by actor, which this phase can33 * reallyhandle.34 * @param now 44 * @param actor the real actor (may differ from the actor contained in the 45 * action) 46 * @param action the action submitted by actor, which this phase can really 47 * handle. 48 * @param now the current time 35 49 * @return new VotingPhase 36 50 */ … … 73 87 * after {@link #finish()} 74 88 * 75 * @param now the curren time76 * @param duration the max duration of the next phase. Must be between89 * @param now the current time 90 * @param duration the max duration (ms) of the next phase. Must be between 77 91 * {@link #PHASE_MINTIME} and {@link #PHASE_MAXTIME}. Also 78 92 * make sure that now+duration is at most at the total … … 83 97 84 98 /** 85 * Get the voting evaluator 86 * 87 * @return 99 * @return the voting evaluator 88 100 */ 89 101 public VotingEvaluator getEvaluator(); … … 97 109 98 110 /** 99 * @param now the current time100 *101 111 * @return the party states. Notice that someone must call 102 * {@link PartyStates#finish( Set)} if passed the deadline.112 * {@link PartyStates#finish()} if passed the deadline. 103 113 */ 104 114 public PartyStates getPartyStates(); -
protocol/src/main/java/geniusweb/protocol/session/mopac/phase/VotingPhase.java
r23 r24 3 3 import java.util.Arrays; 4 4 import java.util.List; 5 import java.util.stream.Collectors; 6 7 import com.fasterxml.jackson.annotation.JsonCreator; 8 import com.fasterxml.jackson.annotation.JsonProperty; 5 9 6 10 import geniusweb.actions.Action; … … 10 14 import geniusweb.inform.Inform; 11 15 import geniusweb.inform.Voting; 16 import geniusweb.issuevalue.Bid; 12 17 import geniusweb.protocol.ProtocolException; 13 18 import geniusweb.protocol.session.mopac.PartyStates; … … 16 21 public class VotingPhase extends DefaultPhase { 17 22 18 VotingPhase(Phase prevPhase, PartyStates partyStates, Long deadlinems, 19 VotingEvaluator evaluator) { 20 super(prevPhase, partyStates, deadlinems, evaluator); 23 /** 24 * the offers received in the {@link OfferPhase} 25 */ 26 private final List<Bid> offers; 27 28 @JsonCreator 29 protected VotingPhase(@JsonProperty("offers") List<Bid> offers, 30 @JsonProperty("partyStates") PartyStates partyStates, 31 @JsonProperty("deadlinems") Long deadlinems, 32 @JsonProperty("evaluator") VotingEvaluator evaluator) { 33 super(partyStates, deadlinems, evaluator); 34 this.offers = offers; 21 35 } 22 36 … … 28 42 return this.with(ex); 29 43 } 30 return new VotingPhase( prevPhase, partyStates.with(action), deadline,44 return new VotingPhase(offers, partyStates.with(action), deadline, 31 45 evaluator); 32 46 } … … 34 48 @Override 35 49 public Inform getInform() { 36 return new Voting(((OfferPhase) prevPhase).getOffers(), 37 partyStates.getPowers()); 50 return new Voting(offers, partyStates.getPowers()); 38 51 } 39 52 40 53 @Override 41 54 public VotingPhase with(ProtocolException e) { 42 return new VotingPhase( prevPhase, partyStates.with(e), deadline,55 return new VotingPhase(offers, partyStates.with(e), deadline, 43 56 evaluator); 44 57 } … … 46 59 @Override 47 60 public VotingPhase finish() { 48 return new VotingPhase( prevPhase, partyStates.finish(), deadline,61 return new VotingPhase(offers, partyStates.finish(), deadline, 49 62 evaluator); 50 63 } … … 52 65 @Override 53 66 protected Phase checkedNext(long deadln) { 54 return new OptInPhase(this, partyStates.flush(), deadln, evaluator); 67 return new OptInPhase(getVotes(), partyStates.flush(), deadln, 68 evaluator); 55 69 } 56 70 … … 60 74 } 61 75 76 /** 77 * @return all votes done in this phase. 78 */ 79 public List<Votes> getVotes() { 80 return partyStates.getActions().stream() 81 .filter(act -> act instanceof Votes).map(act -> (Votes) act) 82 .collect(Collectors.toList()); 83 } 84 62 85 } -
protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java
r21 r24 38 38 39 39 /** 40 * 41 * All parties are first sent the {@link SessionSettings}. Only parties 42 * specified initially in the settings do participate. 40 * The protocol runs as follows 43 41 * <ol> 44 * The protocol tries to start all parties. If not all parties start, the42 * <li>The protocol tries to start all parties. If not all parties start, the 45 43 * parties are freed up and another attempt is done to start all parties some 46 44 * time later. 45 * <li>All parties are sent the {@link SessionSettings}. Only parties specified 46 * initially in the settings do participate. 47 47 * <li>The session deadline clock now starts ticking. 48 48 * <li>All parties are sent their settings. … … 61 61 * the protocol. 62 62 * <p> 63 * Thread safe: all entrypoints are synhronized.63 * Thread safe: all entry points are synchronized. 64 64 */ 65 65 public class SAOP extends DefaultListenable<ProtocolEvent> … … 79 79 /** 80 80 * 81 * @param state normally the initial state coming from SAOPSettings 81 * @param state normally the initial state coming from SAOPSettings 82 * @param logger the Reporter to log to 82 83 */ 83 84 public SAOP(SAOPState state, Reporter logger) { -
protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java
r21 r24 27 27 * protocol. But SAOP can be initialized with less, for 28 28 * use in TournamentSettings. 29 * @param deadline 29 * @param deadline the deadline of the negotiation 30 30 */ 31 31 @JsonCreator -
protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java
r23 r24 33 33 /** 34 34 * 35 * @param actions 35 * @param actions the actions done by the parties 36 36 * @param conns the existing party connections. we assume ownership 37 37 * of this so it should not be modified although … … 88 88 /** 89 89 * 90 * @param e the error that occured 91 * @param currentTimeMs the current time in ms since 1970, see 92 * {@link System#currentTimeMillis()} 90 * @param e the error that occured 93 91 * @return a new state with the error set. 94 92 */ … … 160 158 161 159 /** 162 * @param actor the actor that did this action. Can be used to check 163 * if action is valid. NOTICE caller has to make sure 164 * the current state is not final. 165 * @param action the action that was proposed by actor. 166 * @param currentTimeMs the current time in ms since 1970, see 167 * {@link System#currentTimeMillis()} 168 * @return new SessionState with the action added as last action. 160 * @param actor the actor that did this action. Can be used to check if 161 * action is valid. NOTICE caller has to make sure the current 162 * state is not final. 163 * @param action the action that was proposed by actor. 164 * @return new SAOPState with the action added as last action. 169 165 */ 170 166 -
protocol/src/main/java/geniusweb/protocol/session/shaop/BareSHAOPState.java
r23 r24 44 44 /** 45 45 * 46 * @param actions value for actions done so far. null equals to empty47 * list48 * @param conns the currently existing connections. Can be empty/null.49 * Each connection represents another party. Normally the50 * connections are in the order SHAOP1,COB1,SHAOP2,COB2,..51 * so 2 parties for each team. The protocol should check52 * this.53 * @param progr the {@link Progress} that governs this session. Can be54 * null if session did not yet start.55 * @param settings the settings used for the session56 * @param e the exception that occured, usually null. All errors57 * occuring due to faulty {@link Action}s translate to58 * {@link ProtocolException}s. All errors in our own code59 * are bugs (not ProtocolExceptions) and should result in60 * a throw.61 * @param teamNr the teamnr (0,1,2..) that has the turn. 2* gives index62 * {@link #connections} and settings63 * @param partyNrs a map for each known PartyId to a number. The number is64 * the index in both {@link SHAOPSettings#getTeams()} and65 * in {@link #connections}. null is empyt map.66 * @param totalSpent total accumulated elicitation costs so far. only SHAOP67 * parties accumulate costs. null = emptymap46 * @param actions value for actions done so far. null equals to empty list 47 * @param conns the currently existing connections. Can be empty/null. 48 * Each connection represents another party. Normally the 49 * connections are in the order SHAOP1,COB1,SHAOP2,COB2,.. 50 * so 2 parties for each team. The protocol should check 51 * this. 52 * @param progr the {@link Progress} that governs this session. Can be 53 * null if session did not yet start. 54 * @param settings the settings used for the session 55 * @param e the exception that occured, usually null. All errors 56 * occuring due to faulty {@link Action}s translate to 57 * {@link ProtocolException}s. All errors in our own code 58 * are bugs (not ProtocolExceptions) and should result in a 59 * throw. 60 * @param teamNr the teamnr (0,1,2..) that has the turn. 2* gives index 61 * {@link #connections} and settings 62 * @param partyNrs a map for each known PartyId to a number. The number is 63 * the index in both {@link SHAOPSettings#getTeams()} and in 64 * {@link #connections}. null is empyt map. 65 * @param spent total accumulated elicitation costs so far for each 66 * party. only SHAOP parties accumulate costs. null = empty 67 * map 68 68 */ 69 69 @JsonCreator -
protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOP.java
r21 r24 85 85 /** 86 86 * 87 * @param state normally the initial state coming from SAOPSettings 87 * @param state normally the initial state coming from SAOPSettings 88 * @param logger the {@link Reporter} to use 88 89 */ 89 90 public SHAOP(SHAOPState state, Reporter logger) { -
protocol/src/main/java/geniusweb/protocol/session/shaop/SHAOPState.java
r21 r24 38 38 * see {@link BareSHAOPState}. 39 39 */ 40 /** 41 * 42 * @param actions see 43 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 44 * @param conns see 45 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 46 * @param progress see 47 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 48 * @param settings see 49 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 50 * @param e see 51 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 52 * @param teamNr see 53 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 54 * @param partytNumbers see 55 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 56 * @param spent see 57 * {@link BareSHAOPState#BareSHAOPState(List, ProtocolToPartyConnections, Progress, SHAOPSettings, ProtocolException, int, Map, Map)}. 58 */ 40 59 @JsonCreator 41 60 public SHAOPState(@JsonProperty("actions") List<Action> actions, … … 72 91 /** 73 92 * 74 * @param party 75 * @return true iff party is a SHAOP party .93 * @param party the {@link PartyId} to test 94 * @return true iff party is a SHAOP party (not a COB party). 76 95 */ 77 96 public boolean isShaopParty(PartyId party) { … … 81 100 /** 82 101 * 83 * @return the team leader {@link PartyId}s .102 * @return the team leader {@link PartyId}s which are the SHAOP parties. 84 103 */ 85 104 private Set<PartyId> getLeaders() { … … 149 168 /** 150 169 * 151 * @param e the error that occured 152 * @param currentTimeMs the current time in ms since 1970, see 153 * {@link System#currentTimeMillis()} 170 * @param e the error that occured 154 171 * @return a new state with the error set. 155 172 */ … … 201 218 202 219 /** 203 * @param actor the actor that did this action. Can be used to check 204 * if action is valid. NOTICE caller has to make sure 205 * the current state is not final. 206 * @param action the action that was proposed by actor. 207 * @param currentTimeMs the current time in ms since 1970, see 208 * {@link System#currentTimeMillis()} 220 * @param actor the actor that did this action. Can be used to check if 221 * action is valid. NOTICE caller has to make sure the current 222 * state is not final. 223 * @param action the action that was proposed by actor. 209 224 * @return new SessionState with the action added as last action. 210 225 */ -
protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java
r20 r24 34 34 /** 35 35 * 36 * @param state 36 * @param state the {@link AllPermutationsState} 37 37 * @param logger used for all logging, about the tournament, and the created 38 38 * the session and protocols. … … 81 81 long now = System.currentTimeMillis(); 82 82 if (sessionstate.isFinal(now)) { 83 // List<TeamOfPartiesAndProfiles> participants =84 // sessionstate.getSettings().getParticipants()85 83 SessionResult result = sessionstate.getResult(); 86 84 state = state.with(result); -
protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettings.java
r21 r24 69 69 /** 70 70 * 71 * @param teams a list of {@link Team}s. Must contain at least 72 * {@link #teamsPerSession} elements. The 73 * <teamsize> must match the protocol: (SAOP:1, 74 * SHAOP:2) 75 * @param reuseTeams if true, we use PermutationsWithReturn, if false 76 * we use PermutationsWithoutReturn to create the 77 * teams. 78 * @param plists list of available {@link ProfileList}s to be 79 * permutated over the teams. Each 80 * {@link ProfileList} must contain <teamsize> 81 * elements. 82 * @param teamsPerSession number of parties per session, must be at least 83 * 2. 84 * @param sesettings The generic {@link SessionSetting}. 85 * {@link SessionSettings#with(PartyWithProfile)} 86 * will be used to add the required 87 * {@link PartyWithProfile}s 88 * @param numberTournaments the number of times the tournament should be 89 * run. 71 * @param teams a list of {@link Team}s. Must contain at least 72 * {@link #teamsPerSession} elements. The 73 * {@link #teamsPerSession} must match the protocol: 74 * (SAOP:1, SHAOP:2) 75 * @param reuseTeams if true, we use PermutationsWithReturn, if false 76 * we use PermutationsWithoutReturn to create the 77 * teams. 78 * @param plists list of available {@link ProfileList}s to be 79 * permutated over the teams. Each 80 * {@link ProfileList} must contain 81 * {@link #teamsPerSession} elements. 82 * @param teamsPerSession number of parties per session, must be at least 2. 83 * @param sesettings The generic {@link SessionSettings}. 84 * {@link SessionSettings#with(TeamOfPartiesAndProfiles)} 85 * will be used to add the required 86 * {@link TeamOfPartiesAndProfiles}s 87 * @param nTournaments the number of times the tournament should be run. 90 88 */ 91 89 @JsonCreator
Note:
See TracChangeset
for help on using the changeset viewer.