View Javadoc

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 				// there are no reader allowed when one write is using the
228 				// coordinator.
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 				// everything is fine ... lock the coordinator.
242 				this.writeLock = tx;
243 
244 			} else {
245 				// if no write lock is set a read lock can always be
246 				// granted.
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 				// remove the read lock.
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 				// remove the write lock.
283 				this.writeLock = tx.getFather();
284 			}
285 			// this.commitEntryLocks(tx);
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 			// remove the read lock.
310 			this.readLocks.remove(tx.getId());
311 			if (this.writeLock != null && this.writeLock.equals(tx)) {
312 				// remove the write lock.
313 				this.writeLock = null;
314 			}
315 			// this.rollbackEntryLocks(tx);
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 }