source: protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java

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

Fixed small issues in domaineditor.

File size: 9.2 KB
Line 
1package geniusweb.protocol.session;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.LinkedList;
8import java.util.List;
9import java.util.Map;
10
11import geniusweb.actions.Action;
12import geniusweb.actions.PartyId;
13import geniusweb.progress.Progress;
14import geniusweb.protocol.ProtocolException;
15import geniusweb.references.PartyWithProfile;
16
17/**
18 *
19 */
20/**
21 *
22 * The default current state of the session. immutable.
23 *
24 * @param <P> the actual SessionState object
25 * @param <S> the actual SessionSettings object
26 */
27public abstract class DefaultSessionState<P extends DefaultSessionState<P, S>, S extends SessionSettings>
28 implements SessionState {
29 private final List<Action> actions;
30
31 private final List<PartyId> connections;
32
33 private final Progress progress;
34
35 private final S settings;
36
37 private final ProtocolException error;
38
39 private final Map<PartyId, PartyWithProfile> partyprofiles;
40
41 /**
42 *
43 * @param actions value for actions done so far. null equals to empty
44 * list
45 * @param conns the currently existing connections. Can be empty. If
46 * null it is assumed to be empty. Each connection
47 * represents another party. Normally there is exactly
48 * 1 connection for every party. The protocol should
49 * check this.
50 * @param progr the {@link Progress} that governs this session. Can
51 * be null if session did not yet start.
52 * @param settings the settings used for the session
53 * @param partyprofiles map with the {@link PartyWithProfile} for connected
54 * parties. null is equivalent to an empty map.
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
58 * code are bugs (not ProtocolExceptions) and should
59 * result in a throw and terminate the session.
60 */
61 public DefaultSessionState(List<Action> actions, List<PartyId> conns,
62 Progress progr, S settings,
63 Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
64 if (partyprofiles == null) {
65 this.partyprofiles = Collections.emptyMap();
66 } else {
67 this.partyprofiles = new HashMap<>(partyprofiles);
68 }
69 if (conns == null) {
70 this.connections = Collections.emptyList();
71 } else {
72 this.connections = new LinkedList<>(conns);
73 }
74 if (actions == null) {
75 this.actions = new LinkedList<>();
76 } else {
77 this.actions = new LinkedList<>(actions);
78 }
79
80 if (connections.size() != new HashSet<PartyId>(connections).size()) {
81 throw new IllegalArgumentException(
82 "There can not be multiple connections for a party:"
83 + connections);
84 }
85 if (settings == null)
86 throw new IllegalArgumentException("Settings must be not null");
87 this.progress = progr;
88 this.settings = settings;
89 this.error = e;
90 }
91
92 /**
93 * Construct a new session state, where the DefaultSessionState changes
94 * while the rest of the state remains unchanged. Notice the return type P.
95 *
96 * @param actions1 the new {@link Action}s
97 * @param conns the new connected {@link PartyId}s
98 * @param progress1 the new {@link Progress}
99 * @param settings1 the new {@link SessionSettings}. Normally this is
100 * constant during a session.
101 * @param partyprofiles1 the new {@link PartyWithProfile}s for all parties.
102 * Normally this remains constant during a session.
103 * @param e an error that occured that caused the session to
104 * reach its terminated/final state. If an error does
105 * not cause termination, only a warning should be
106 * logged.
107 * @return the new state of the derived sessionstate.
108 */
109 abstract public P with(List<Action> actions1, List<PartyId> conns,
110 Progress progress1, S settings1,
111 Map<PartyId, PartyWithProfile> partyprofiles1, ProtocolException e);
112
113 /**
114 * @return existing connections.
115 */
116 public List<PartyId> getConnections() {
117 return Collections.unmodifiableList(connections);
118 }
119
120 /**
121 * @return map with {@link PartyWithProfile} for the parties. May be an
122 * incomplete map, as more parties with their profiles may be set
123 * only later.
124 */
125 public Map<PartyId, PartyWithProfile> getPartyProfiles() {
126 return Collections.unmodifiableMap(partyprofiles);
127 }
128
129 /**
130 *
131 * @return unmodifyable list of actions done so far.
132 */
133 @Override
134 public List<Action> getActions() {
135 return Collections.unmodifiableList(actions);
136 }
137
138 @Override
139 public Progress getProgress() {
140 return progress;
141 }
142
143 @Override
144 public S getSettings() {
145 return settings;
146 }
147
148 @Override
149 public boolean isFinal(long currentTimeMs) {
150 return error != null
151 || (progress != null && progress.isPastDeadline(currentTimeMs));
152 }
153
154 public ProtocolException getError() {
155 return error;
156 }
157
158 @Override
159 public String toString() {
160 return this.getClass().getSimpleName() + "[" + actions + ","
161 + connections + "," + progress + "," + settings + "," + error;
162 }
163
164 public P withDeadlineReached() {
165 return with(actions, connections, progress, settings, partyprofiles,
166 error);
167 }
168
169 public P withoutParty(PartyId party) {
170 List<PartyId> newconn = new ArrayList<>(connections);
171 newconn.remove(party);
172 return with(actions, newconn, progress, settings, partyprofiles, error);
173 }
174
175 /**
176 *
177 * @param e the error that occured
178 * @return a new state with the error set/updated.
179 */
180 public P with(ProtocolException e) {
181 return with(actions, connections, progress, settings, partyprofiles, e);
182 }
183
184 public P with(PartyId connection, PartyWithProfile partyprofile) {
185 List<PartyId> newconns = new ArrayList<>(getConnections());
186 newconns.add(connection);
187 Map<PartyId, PartyWithProfile> newprofiles = new HashMap<>(
188 getPartyProfiles());
189 newprofiles.put(connection, partyprofile);
190 return with(getActions(), newconns, getProgress(), getSettings(),
191 newprofiles, null);
192 }
193
194 /**
195 * Sets the new progress for this session.
196 *
197 * @param newprogress the new progress
198 * @return new SAOPState with the progress set to new value
199 */
200 public P with(Progress newprogress) {
201 if (newprogress == null) {
202 throw new IllegalArgumentException("newprogress must be not null");
203 }
204 return with(actions, connections, newprogress, settings, partyprofiles,
205 error);
206 }
207
208 /**
209 * @param actor the actor that did this action. Can be used to check if
210 * action is valid. NOTICE caller has to make sure the current
211 * state is not final.
212 * @param action the action that was proposed by actor.
213 * @return new SAOPState with the action added as last action.
214 */
215
216 public P with(PartyId actor, Action action) {
217 String msg = checkAction(actor, action);
218 if (msg != null)
219 throw new IllegalArgumentException(msg);
220
221 List<Action> newactions = new LinkedList<>(getActions());
222 newactions.add(action);
223 return with(newactions, connections, progress, settings, partyprofiles,
224 error);
225 }
226
227 /**
228 *
229 * @param actor the known real actor that did this action
230 * @param action an {@link Action}
231 * @return null if action seems ok, or message explaining why not.
232 */
233 public String checkAction(PartyId actor, Action action) {
234 if (actor == null) { // this is a bug
235 return "actor must not be null";
236 }
237 if (action == null) {
238 return "action is null";
239 }
240 if (!actor.equals(action.getActor()))
241 return "act contains wrong credentials: " + action;
242 return null;
243 }
244
245 @Override
246 public int hashCode() {
247 final int prime = 31;
248 int result = 1;
249 result = prime * result + ((actions == null) ? 0 : actions.hashCode());
250 result = prime * result
251 + ((connections == null) ? 0 : connections.hashCode());
252 result = prime * result + ((error == null) ? 0 : error.hashCode());
253 result = prime * result
254 + ((partyprofiles == null) ? 0 : partyprofiles.hashCode());
255 result = prime * result
256 + ((progress == null) ? 0 : progress.hashCode());
257 result = prime * result
258 + ((settings == null) ? 0 : settings.hashCode());
259 return result;
260 }
261
262 @Override
263 public boolean equals(Object obj) {
264 if (this == obj)
265 return true;
266 if (obj == null)
267 return false;
268 if (getClass() != obj.getClass())
269 return false;
270 DefaultSessionState other = (DefaultSessionState) obj;
271 if (actions == null) {
272 if (other.actions != null)
273 return false;
274 } else if (!actions.equals(other.actions))
275 return false;
276 if (connections == null) {
277 if (other.connections != null)
278 return false;
279 } else if (!connections.equals(other.connections))
280 return false;
281 if (error == null) {
282 if (other.error != null)
283 return false;
284 } else if (!error.equals(other.error))
285 return false;
286 if (partyprofiles == null) {
287 if (other.partyprofiles != null)
288 return false;
289 } else if (!partyprofiles.equals(other.partyprofiles))
290 return false;
291 if (progress == null) {
292 if (other.progress != null)
293 return false;
294 } else if (!progress.equals(other.progress))
295 return false;
296 if (settings == null) {
297 if (other.settings != null)
298 return false;
299 } else if (!settings.equals(other.settings))
300 return false;
301 return true;
302 }
303
304}
Note: See TracBrowser for help on using the repository browser.