View Javadoc

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  		// super.commitEntryLocks(tx);
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  		// super.deleteLockEntry(e, tx);
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  		// If the amount of the given entries is smaller than
98  		// the count of the selector, it cannot match.
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 				// try {
115 				if (e.canBeRead(tx)) {
116 					// super.readLockEntry(e, tx);
117 					results.add(e);
118 					if (results.size() == count) {
119 						break;
120 					}
121 				}
122 				// } catch (TransactionLockException e1) {
123 				// // skip
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 		// If the type of the template and the given entry is different, it
151 		// cannot match.
152 		if (tmpl.getEntryType() != entry.getEntryType()) {
153 			return false;
154 		}
155 
156 		// Both template and given entry are either of type AtomicEntry
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 			// If the valueClass of the template is different than the one of
164 			// the given entry, it cannot match.
165 			if (t.getValueClass() != e.getValueClass()) {
166 				return false;
167 			}
168 
169 			// Both template and given entry have the same value class.
170 			// If the value in the template is set, the entry has to have the
171 			// same value.
172 			// If the value in the template is null, the value is no criterion
173 			if (t.getValue() == null) {
174 				return true;
175 			}
176 
177 			// Since the value is a constrain, template and given entry have to
178 			// have the same value.
179 			if (t.getValue().equals(e.getValue())) {
180 				return true;
181 			}
182 		}
183 		// Both template and given entry are either of type Tuple
184 		if (tmpl.getEntryType() == EntryTypes.TUPLE) {
185 			@SuppressWarnings("unchecked")
186 			Tuple t = (Tuple) tmpl;
187 			@SuppressWarnings("unchecked")
188 			Tuple e = (Tuple) entry;
189 
190 			// If the amount of entries inside a tuple is different, it cannot
191 			// match.
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 		// Logical unreachable code
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 		// OPTIMIZE: avoid the iteration over all entries!
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 		// super.rollbackEntryLocks(tx);
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 			// we did not shift anything
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 				// TODO throw Fatal exception?
265 				throw new CannotShiftException(
266 						"Can not find an entry to shift.");
267 			}
268 			// super.deleteLockEntry(read.get(0), tx);
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 		// super.writeLockEntry(e, tx);
284 		this.entries.put(e.getId(), e);
285 	}
286 
287 }