source: src/main/java/geniusweb/partiesserver/repository/RunningPartiesRepo.java@ 3

Last change on this file since 3 was 1, checked in by bart, 5 years ago

Initial Release

File size: 4.0 KB
Line 
1package geniusweb.partiesserver.repository;
2
3import java.util.Collection;
4import java.util.Collections;
5import java.util.Date;
6import java.util.Map;
7import java.util.concurrent.ConcurrentHashMap;
8import java.util.logging.Level;
9
10import geniusweb.actions.PartyId;
11import tudelft.utilities.listener.DefaultListenable;
12import tudelft.utilities.logging.ReportToLogger;
13import tudelft.utilities.logging.Reporter;
14import tudelft.utilities.repository.NoResourcesNowException;
15import tudelft.utilities.repository.Repository;
16
17/**
18 * RunningPartiesRepo stores all currently running parties. Listeners are
19 * notified when a party is added or removed.
20 */
21public class RunningPartiesRepo extends DefaultListenable<PartyId>
22 implements Repository<PartyId, RunningParty> {
23 /**
24 * List of currently running parties.
25 */
26 public static final int MAX_SLOTS = 4;
27 private static final RunningPartiesRepo instance = new RunningPartiesRepo(
28 new ReportToLogger("partiesserver"));
29 private static final long MAXWAIT_MS = 600000; // 10 minutes
30 private final Reporter log;
31
32 // not static to facilitate testing.
33 private final Map<PartyId, RunningParty> runningParties = new ConcurrentHashMap<>();
34
35 /**
36 * singleton pattern. Do not call this but use {@link #instance()}. Testers
37 * can still use this (instead of {@link #instance()) to get a fresn empty
38 * runningParties map. We need singleton pattern because tomcat acts as a
39 * black box calling us from "nowhere" (it works with annotations).
40 */
41 RunningPartiesRepo(Reporter reporter) {
42 this.log = reporter;
43 }
44
45 public static RunningPartiesRepo instance() {
46 return instance;
47 }
48
49 @Override
50 public Collection<RunningParty> list() {
51 return Collections.unmodifiableCollection(runningParties.values());
52 }
53
54 @Override
55 public RunningParty get(PartyId id) {
56 return runningParties.get(id);
57 }
58
59 @Override
60 public void put(RunningParty newParty) throws NoResourcesNowException {
61 PartyId id = newParty.getID();
62 synchronized (runningParties) {
63 if (runningParties.containsKey(id)) {
64 throw new IllegalArgumentException(
65 "Party " + newParty + " already in the repository");
66 }
67 if (availableSlots() <= 0) {
68 Date date = estimateCleanupTime();
69 throw new NoResourcesNowException(
70 "There are currently no free slots to register party "
71 + newParty,
72 date);
73 }
74 runningParties.put(id, newParty);
75 }
76 notifyChange(id);
77 }
78
79 @Override
80 public void replace(RunningParty newParty) {
81 PartyId id = newParty.getID();
82 synchronized (runningParties) {
83 if (!runningParties.containsKey(id)) {
84 throw new IllegalArgumentException(
85 "Party " + newParty + " is not in the repository");
86 }
87 runningParties.put(id, newParty);
88 }
89 notifyChange(id);
90
91 }
92
93 /**
94 * @return an estimate of when the repo will be cleaned up (party gets
95 * terminated). Returns at most {@link #MAXWAIT_MS}. May return time
96 * before NOW if party is was expected to be already terminated.
97 */
98 public Date estimateCleanupTime() {
99 long now = System.currentTimeMillis();
100 Date date = new Date(now + MAXWAIT_MS);
101 synchronized (runningParties) {
102 for (RunningParty party : runningParties.values()) {
103 if (party.getEndDate().before(date)) {
104 date = party.getEndDate();
105 }
106 }
107 }
108 return date;
109 }
110
111 @Override
112 public void remove(PartyId id) {
113 synchronized (runningParties) {
114 RunningParty party = runningParties.get(id);
115 if (party == null) {
116 return; // no such party is there right now.
117 }
118 runningParties.remove(id);
119 try {
120 party.getParty().terminate();
121 } catch (Throwable e) {
122 log.log(Level.WARNING,
123 "Party " + id + " did not terminate properly", e);
124
125 }
126 }
127 notifyChange(id);
128 }
129
130 /**
131 * @return the maximum number of slots in this factory. Each slot can run
132 * one party.
133 */
134
135 public int maximumSlots() {
136 return MAX_SLOTS;
137 }
138
139 /**
140 *
141 * @return the currently available number of slots in this factory. Each
142 * slot can run one party.
143 */
144
145 public int availableSlots() {
146 synchronized (runningParties) {
147 return MAX_SLOTS - runningParties.size();
148 }
149 }
150
151}
Note: See TracBrowser for help on using the repository browser.