1 package org.xvsm.interfaces;
2
3 import java.io.Serializable;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.Properties;
7 import java.util.TreeMap;
8
9 import org.apache.log4j.Logger;
10 import org.xvsm.core.ContainerRef;
11 import org.xvsm.core.Entry;
12 import org.xvsm.internal.exceptions.CannotShiftException;
13 import org.xvsm.internal.exceptions.ContainerFullException;
14 import org.xvsm.internal.exceptions.CountNotMetException;
15 import org.xvsm.internal.exceptions.TransactionLockException;
16 import org.xvsm.selectors.Selector;
17 import org.xvsm.transactions.Transaction;
18
19 /***
20 * @author Christian Schreiber, Michael Proestler
21 *
22 */
23 public abstract class ICoordinator implements Serializable {
24
25 /***
26 * The logger.
27 */
28 private static Logger logger = Logger.getLogger(ICoordinator.class);
29
30 /***
31 * The ContainerRef of the container.
32 */
33 private ContainerRef cref;
34
35 /***
36 * A lock object used for synchronisation.
37 */
38 private Boolean lockObject = false;
39
40 /***
41 * The current Transaction using this Coordinator.
42 */
43 private Transaction writeLock;
44
45 /***
46 * The Transactions that have readLocks on that Coordinator.
47 */
48 private TreeMap<String, Transaction> readLocks = new TreeMap<String, Transaction>();
49
50 /***
51 * The properties of this coordinator.
52 */
53 protected Properties properties = new Properties();
54
55 /***
56 * Tries to write the given Entry.
57 *
58 * Otherwise {@link ContainerFullException} can be raised.
59 *
60 * @param e
61 * The {@link Entry} that will be written.
62 * @param s
63 * the Selector used for writing.
64 * @param tx
65 * A Transaction under which the operation executes
66 * @throws ContainerFullException
67 * thrown when the entry can not be written because there is no
68 * free place for it (e.g. full bounded container, vector
69 * position already used, key already present).
70 * @throws TransactionLockException
71 * thrown if a lock can not be aquired because another
72 * transaction uses it.
73 */
74 public abstract void write(Entry e, Transaction tx, Selector s)
75 throws ContainerFullException, TransactionLockException;
76
77 /***
78 * Writes the Entry. If there is no place left, another Entry will be
79 * deleted (shifted).
80 *
81 * @param e
82 * The {@link Entry} that will be written.
83 * @param s
84 * the Selector used for writing.
85 * @param tx
86 * A Transaction under which the operation executes
87 * @return The shifted {@link Entry} of <code>null</code> if no entry has
88 * been shifted.
89 * @throws CannotShiftException
90 * thrown if the coordinator can not decide which entry has to
91 * be shifted.
92 * @throws TransactionLockException
93 * thrown if a lock can not be aquired because another
94 * transaction uses it.
95 */
96 public abstract Entry shift(Entry e, Transaction tx, Selector s)
97 throws TransactionLockException, CannotShiftException;
98
99 /***
100 * Read {@link Entry}s that match with the Selector.
101 *
102 * @param selector
103 * The Selector that must match.
104 * @param tx
105 * A Transaction under which the operation executes
106 * @param entries
107 * A {@link List} of {@link Entry}s to operate on. Null if it
108 * should operates on all known entries.
109 * @throws CountNotMetException
110 * thrown if there are not enough entries to fulfill the count
111 * of the selector.
112 * @throws TransactionLockException
113 * thrown if a lock can not be aquired because another
114 * transaction uses it.
115 * @return a List of all matching entries.
116 */
117 public abstract List<Entry> read(Transaction tx, Selector selector,
118 List<Entry> entries) throws TransactionLockException,
119 CountNotMetException;
120
121 /***
122 * Deletes one specific entry.
123 *
124 * @param tx
125 * A Transaction under which the operation executes
126 * @param e
127 * The entry to delete.
128 * @throws TransactionLockException
129 * thrown if a lock can not be aquired because another
130 * transaction uses it.
131 */
132 public abstract void delete(Transaction tx, Entry e)
133 throws TransactionLockException;
134
135 /***
136 * Sets the maximal containersize in the coordinator. Can be used to
137 * optimize internal structures, and is needed for shift decisions.
138 *
139 * @param maxSize
140 * the maximal size of entries in the coordinator.
141 */
142 public abstract void setMaxContainerSize(int maxSize);
143
144 /***
145 * Returns the default {@link Selector} for this Coordinator.
146 *
147 * @return the default Selector for this Coordinator.
148 */
149 public abstract Class<? extends Selector> getDefaultSelector();
150
151 /***
152 * Commits an existing {@link Transaction} for this container.
153 *
154 * @param tx
155 * The {@link Transaction} that should be commited.
156 * @throws TransactionLockException
157 * thrown if a lock can not be aquired.
158 */
159 public abstract void commit(Transaction tx) throws TransactionLockException;
160
161 /***
162 * Commits an existing {@link Transaction} for this container.
163 *
164 * @param tx
165 * The {@link Transaction} that should be commited.
166 * @throws TransactionLockException
167 * thrown if a lock can not be aquired.
168 */
169 public abstract void commitSubTransaction(Transaction tx)
170 throws TransactionLockException;
171
172 /***
173 * Does a rollback on this {@link Transaction}.
174 *
175 * @param tx
176 * The {@link Transaction} that should perform a rollback.
177 * @throws TransactionLockException
178 * thrown if a lock can not be aquired.
179 */
180 public abstract void rollback(Transaction tx)
181 throws TransactionLockException;
182
183 /***
184 * @return the cref
185 */
186 public ContainerRef getCref() {
187 return cref;
188 }
189
190 /***
191 * @param cref
192 * the cref to set
193 */
194 public void setCref(ContainerRef cref) {
195 this.cref = cref;
196 }
197
198 /***
199 * Aquires the read or write lock for this coordinator.
200 *
201 * @param write
202 * if <code>true</code> a writelock will be aquired. This means
203 * no readLock is allowed to be set. if <code>false</code> a
204 * readlock will be aquired,
205 * @param tx
206 * the transaction which needs the lock
207 * @throws TransactionLockException
208 * thrown if the lock can not be required.
209 */
210 protected void aquireLock(boolean write, Transaction tx)
211 throws TransactionLockException {
212 if (logger.isDebugEnabled()) {
213 logger.debug("auireLock(" + write + ", " + tx + ")");
214 }
215 synchronized (this.lockObject) {
216 if (this.writeLock != null) {
217 if (!this.writeLock.isAncestorOf(tx)) {
218 if (logger.isDebugEnabled()) {
219 logger.debug("aquireLock() the Coordinator ("
220 + this.getClass() + ") has a write lock: "
221 + this.writeLock);
222 }
223 throw new TransactionLockException(this.writeLock);
224 }
225 }
226 if (write) {
227
228
229 if (this.readLocks.size() != 0) {
230 Transaction readLock;
231 Iterator<Transaction> iter = this.readLocks.values()
232 .iterator();
233 while (iter.hasNext()) {
234 readLock = iter.next();
235 if (!readLock.isAncestorOf(tx)) {
236 throw new TransactionLockException(readLock);
237 }
238 }
239 this.readLocks.remove(tx.getId());
240 }
241
242 this.writeLock = tx;
243
244 } else {
245
246
247 if (tx != null && tx.getId() != null) {
248 this.readLocks.put(tx.getId(), tx);
249 }
250 }
251 }
252 if (logger.isDebugEnabled()) {
253 logger.debug("auireLock() lock aquired for coordinator "
254 + this.getClass());
255 }
256 }
257
258 /***
259 * Updates the locks of this coordinator.<br>
260 * All locks which are set will be set to the father transaction or null if
261 * there is no father.<br>
262 * This method calls {@link ICoordinator#commitEntryLocks(Transaction)}.
263 *
264 * @param tx
265 * the transaction to commit.
266 * @throws TransactionLockException
267 * thrown if the lock can not be aquired.
268 */
269 protected void commitLocks(Transaction tx) throws TransactionLockException {
270 if (logger.isDebugEnabled()) {
271 logger.debug("commitLocks(" + tx + ")");
272 }
273 synchronized (this.lockObject) {
274 if (this.readLocks.get(tx.getId()) != null) {
275
276 this.readLocks.remove(tx.getId());
277 if (tx.getFather() != null) {
278 this.readLocks.put(tx.getFather().getId(), tx.getFather());
279 }
280 }
281 if (this.writeLock != null && this.writeLock.equals(tx)) {
282
283 this.writeLock = tx.getFather();
284 }
285
286 }
287 if (logger.isDebugEnabled()) {
288 logger.debug("commitLocks() transaction commited) for coordinator "
289 + this.getClass());
290 }
291 }
292
293 /***
294 * Updates the locks of this coordinator.<br>
295 * All locks will be set to <code>null</code>.<br>
296 * This method calls {@link ICoordinator#rollbackEntryLocks(Transaction)}.
297 *
298 * @param tx
299 * the transaction to rollback.
300 * @throws TransactionLockException
301 * thrown if the lock can not be aquired.
302 */
303 protected void rollbackLocks(Transaction tx)
304 throws TransactionLockException {
305 if (logger.isDebugEnabled()) {
306 logger.debug("rollbackLocks(" + tx + ")");
307 }
308 synchronized (this.lockObject) {
309
310 this.readLocks.remove(tx.getId());
311 if (this.writeLock != null && this.writeLock.equals(tx)) {
312
313 this.writeLock = null;
314 }
315
316 }
317 if (logger.isDebugEnabled()) {
318 logger.debug("rollbackLocks() locks released for coordinator "
319 + this.getClass());
320 }
321 }
322
323 public Properties getProperties() {
324 return this.properties;
325 }
326
327 public void setProperties(Properties properties) {
328 this.properties = properties;
329 }
330 }