1 package org.xvsm.coordinators;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.xvsm.core.AtomicEntry;
9 import org.xvsm.core.Entry;
10 import org.xvsm.core.Tuple;
11 import org.xvsm.core.Entry.EntryTypes;
12 import org.xvsm.interfaces.IImplicitCoordinator;
13 import org.xvsm.interfaces.container.IContainer;
14 import org.xvsm.internal.exceptions.CannotShiftException;
15 import org.xvsm.internal.exceptions.ContainerFullException;
16 import org.xvsm.internal.exceptions.CountNotMetException;
17 import org.xvsm.internal.exceptions.TransactionLockException;
18 import org.xvsm.selectors.LindaSelector;
19 import org.xvsm.selectors.Selector;
20 import org.xvsm.transactions.Transaction;
21
22 /***
23 * @author Christian Schreiber, Michael Proestler
24 *
25 */
26 public class LindaCoordinator extends IImplicitCoordinator {
27
28 /***
29 * The SerialVersionUID of this Class.
30 */
31 private static final long serialVersionUID = 3867508050161659712L;
32
33 /***
34 * The maximum size of the container where this LindaCoordinator belongs to.
35 */
36 private int maxSize = 0;
37
38 /***
39 * Contains all entries.
40 */
41 private Map<String, Entry> entries = new HashMap<String, Entry>();
42
43 /***
44 * Entries which have been deleted.
45 */
46 private Map<Transaction, List<Entry>> deleted = new HashMap<Transaction, List<Entry>>();
47
48 /***
49 * {@inheritDoc}.
50 */
51 public void commit(Transaction tx) throws TransactionLockException {
52 deleted.remove(tx);
53
54 }
55
56 /***
57 * {@inheritDoc}
58 */
59 @Override
60 public void commitSubTransaction(Transaction tx) {
61 List<Entry> entries = this.deleted.get(tx);
62 if (entries != null) {
63 this.deleted.put(tx.getFather(), entries);
64 }
65 }
66
67 /***
68 * {@inheritDoc}.
69 */
70 public void delete(Transaction tx, Entry e) throws TransactionLockException {
71 List<Entry> dentries = this.deleted.get(tx);
72 if (dentries == null) {
73 dentries = new ArrayList<Entry>();
74 this.deleted.put(tx, dentries);
75 }
76 dentries.add(e);
77
78 this.entries.remove(e.getId());
79 }
80
81 /***
82 * {@inheritDoc}.
83 */
84 public Class<? extends Selector> getDefaultSelector() {
85 return LindaSelector.class;
86 }
87
88 /***
89 * {@inheritDoc}.
90 */
91 public List<Entry> read(Transaction tx, Selector selector,
92 List<Entry> centries) throws TransactionLockException,
93 CountNotMetException {
94 int count = selector.getCount();
95 LindaSelector ls = (LindaSelector) selector;
96
97
98
99 List<Entry> allEntries = null;
100 if (centries == null) {
101 allEntries = new ArrayList<Entry>(this.entries.values());
102 } else {
103 allEntries = centries;
104 }
105 if (allEntries.size() < count) {
106 throw new CountNotMetException(
107 "There are not enoug matching entries.");
108 }
109
110 List<Entry> results = new ArrayList<Entry>();
111
112 for (Entry e : allEntries) {
113 if (this.matches(e, ls.getTemplate())) {
114
115 if (e.canBeRead(tx)) {
116
117 results.add(e);
118 if (results.size() == count) {
119 break;
120 }
121 }
122
123
124
125 }
126 }
127
128 if (count != Selector.CNT_ALL && results.size() < count) {
129 throw new CountNotMetException(
130 "There are not enoug matching entries.");
131 }
132
133 return results;
134 }
135
136 /***
137 * Tries to match the private template entry against the given one.
138 *
139 * @param entry
140 * the entry against which the template tries to match.
141 * @param tmpl
142 * the template on which the match is performed.
143 * @return true if the template matches, false if not.
144 */
145 private boolean matches(Entry entry, Entry tmpl) {
146 if (tmpl == null || tmpl.getEntryType() == null) {
147 return true;
148 }
149
150
151
152 if (tmpl.getEntryType() != entry.getEntryType()) {
153 return false;
154 }
155
156
157 if (tmpl.getEntryType() == EntryTypes.ATOMICENTRY) {
158 @SuppressWarnings("unchecked")
159 AtomicEntry<Object> t = (AtomicEntry<Object>) tmpl;
160 @SuppressWarnings("unchecked")
161 AtomicEntry<Object> e = (AtomicEntry<Object>) entry;
162
163
164
165 if (t.getValueClass() != e.getValueClass()) {
166 return false;
167 }
168
169
170
171
172
173 if (t.getValue() == null) {
174 return true;
175 }
176
177
178
179 if (t.getValue().equals(e.getValue())) {
180 return true;
181 }
182 }
183
184 if (tmpl.getEntryType() == EntryTypes.TUPLE) {
185 @SuppressWarnings("unchecked")
186 Tuple t = (Tuple) tmpl;
187 @SuppressWarnings("unchecked")
188 Tuple e = (Tuple) entry;
189
190
191
192 if (t.size() != e.size()) {
193 return false;
194 }
195
196 boolean matches = true;
197 for (int i = 0; i < t.size(); i++) {
198 matches = this.matches(e.getEntryAt(i), t.getEntryAt(i));
199 if (!matches) {
200 return false;
201 }
202 }
203 return true;
204 }
205
206
207 return false;
208 }
209
210 /***
211 * {@inheritDoc}.
212 */
213 public void rollback(Transaction tx) throws TransactionLockException {
214 List<Entry> dentries = this.deleted.get(tx);
215 if (dentries != null) {
216 for (Entry e : dentries) {
217 this.entries.put(e.getId(), e);
218 }
219 }
220
221 for (Entry e : new ArrayList<Entry>(this.entries.values())) {
222 e.removeReadLock(tx);
223 if (e.removeOnRollback(tx)) {
224 this.entries.remove(e.getId());
225 }
226 }
227
228 this.deleted.remove(tx);
229
230 }
231
232 /***
233 * {@inheritDoc}.
234 */
235 public void setMaxContainerSize(int max) {
236 this.maxSize = max;
237 }
238
239 /***
240 * {@inheritDoc}.
241 */
242 public Entry shift(Entry e, Transaction tx, Selector s)
243 throws TransactionLockException, CannotShiftException {
244 try {
245 this.write(e, tx, s);
246
247 return null;
248 } catch (ContainerFullException e1) {
249 List<Entry> read;
250 try {
251 read = this.read(tx, s, null);
252 } catch (CountNotMetException e2) {
253 throw new CannotShiftException(
254 "Can not find an entry to shift.");
255 }
256 if (read == null || read.size() < 1) {
257 throw new CannotShiftException(
258 "Can not find an entry to shift.");
259 }
260 this.delete(tx, read.get(0));
261 try {
262 this.write(e, tx, s);
263 } catch (ContainerFullException e2) {
264
265 throw new CannotShiftException(
266 "Can not find an entry to shift.");
267 }
268
269 return read.get(0);
270 }
271
272 }
273
274 /***
275 * {@inheritDoc}.
276 */
277 public void write(Entry e, Transaction tx, Selector s)
278 throws ContainerFullException, TransactionLockException {
279 if (this.maxSize != IContainer.INFINITE_SIZE
280 && this.entries.size() >= this.maxSize) {
281 throw new ContainerFullException();
282 }
283
284 this.entries.put(e.getId(), e);
285 }
286
287 }