[1285] | 1 | // Copyright 2012 Georg-August-Universität Göttingen, Germany |
---|
| 2 | // |
---|
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
---|
| 4 | // you may not use this file except in compliance with the License. |
---|
| 5 | // You may obtain a copy of the License at |
---|
| 6 | // |
---|
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 8 | // |
---|
| 9 | // Unless required by applicable law or agreed to in writing, software |
---|
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 12 | // See the License for the specific language governing permissions and |
---|
| 13 | // limitations under the License. |
---|
| 14 | |
---|
| 15 | package de.ugoe.cs.autoquest.tasktrees.temporalrelation; |
---|
| 16 | |
---|
| 17 | import java.io.Serializable; |
---|
| 18 | import java.util.ArrayList; |
---|
| 19 | import java.util.Arrays; |
---|
| 20 | import java.util.Collection; |
---|
| 21 | import java.util.HashMap; |
---|
| 22 | import java.util.Iterator; |
---|
| 23 | import java.util.LinkedList; |
---|
| 24 | import java.util.List; |
---|
| 25 | import java.util.Map; |
---|
| 26 | import java.util.Map.Entry; |
---|
| 27 | |
---|
[1408] | 28 | import de.ugoe.cs.autoquest.eventcore.Event; |
---|
[1853] | 29 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; |
---|
[1294] | 30 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; |
---|
[1853] | 31 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; |
---|
| 32 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional; |
---|
| 33 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; |
---|
| 34 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; |
---|
| 35 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; |
---|
[1285] | 36 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; |
---|
| 37 | import de.ugoe.cs.autoquest.usageprofiles.SymbolMap; |
---|
| 38 | |
---|
| 39 | /** |
---|
| 40 | * <p> |
---|
[1408] | 41 | * This class is a data structure for holding task instances in form of a symbol map. It is more |
---|
| 42 | * efficient than a simple list. This data structure can be used with a comparator to adapt the |
---|
| 43 | * effective list behavior and to define the equals strategy for comparing task instances. After a |
---|
| 44 | * certain size ({@link #MAX_LIST_SIZE}), the map creates an index consisting of buckets of similar |
---|
| 45 | * task instances. This allows searching for task instances in a more efficient order as the search |
---|
| 46 | * can start in the most appropriate of the internal buckets. |
---|
[1285] | 47 | * </p> |
---|
| 48 | * <p> |
---|
[1408] | 49 | * The class is called a map, although it is not. It may contain the same task instances as |
---|
| 50 | * separate keys. This implementation is done for performance improvements. If it is required to |
---|
| 51 | * really assure, that a key exists only once, then each call to the |
---|
| 52 | * {@link #addSymbol(Object, Object)} method should be done only, if the |
---|
| 53 | * {@link #containsSymbol(Object)} method for the same symbol returns false. |
---|
[1285] | 54 | * </p> |
---|
| 55 | * |
---|
[2218] | 56 | * @see TaskComparator |
---|
[1285] | 57 | * |
---|
| 58 | * @author Patrick Harms |
---|
| 59 | * @param <V> |
---|
| 60 | */ |
---|
[1853] | 61 | class TaskSymbolBucketedMap<V> implements SymbolMap<ITask, V>, Serializable { |
---|
[1285] | 62 | |
---|
| 63 | /** |
---|
| 64 | * <p> |
---|
| 65 | * default serial version UID |
---|
| 66 | * </p> |
---|
| 67 | */ |
---|
| 68 | private static final long serialVersionUID = 1L; |
---|
| 69 | |
---|
| 70 | /** |
---|
| 71 | * <p> |
---|
[1408] | 72 | * the maximum number of task instances in this map which is still only treated as list |
---|
| 73 | * instead of using buckets. |
---|
[1285] | 74 | * </p> |
---|
| 75 | */ |
---|
| 76 | private static final int MAX_LIST_SIZE = 15; |
---|
| 77 | |
---|
| 78 | /** |
---|
| 79 | * <p> |
---|
[2129] | 80 | * the id of the default event bucket |
---|
| 81 | * </p> |
---|
| 82 | */ |
---|
| 83 | private static final int DEFAULT_EVENT_BUCKET_ID = 4; |
---|
| 84 | |
---|
| 85 | /** |
---|
| 86 | * <p> |
---|
| 87 | * the id of the default sequence bucket |
---|
| 88 | * </p> |
---|
| 89 | */ |
---|
| 90 | private static final int DEFAULT_SEQUENCE_BUCKET_ID = 0; |
---|
| 91 | |
---|
| 92 | /** |
---|
| 93 | * <p> |
---|
| 94 | * the id of the default selection bucket |
---|
| 95 | * </p> |
---|
| 96 | */ |
---|
| 97 | private static final int DEFAULT_SELECTION_BUCKET_ID = 1; |
---|
| 98 | |
---|
| 99 | /** |
---|
| 100 | * <p> |
---|
| 101 | * the id of the default iteration bucket |
---|
| 102 | * </p> |
---|
| 103 | */ |
---|
| 104 | private static final int DEFAULT_ITERATION_BUCKET_ID = 2; |
---|
| 105 | |
---|
| 106 | /** |
---|
| 107 | * <p> |
---|
| 108 | * the id of the default optional bucket |
---|
| 109 | * </p> |
---|
| 110 | */ |
---|
| 111 | private static final int DEFAULT_OPTIONAL_BUCKET_ID = 3; |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * <p> |
---|
| 115 | * the default bucket search order for events |
---|
| 116 | * </p> |
---|
| 117 | */ |
---|
| 118 | private static final int[] DEFAULT_EVENT_BUCKET_SEARCH_ORDER = new int[] |
---|
| 119 | { DEFAULT_EVENT_BUCKET_ID, DEFAULT_ITERATION_BUCKET_ID, DEFAULT_OPTIONAL_BUCKET_ID, |
---|
| 120 | DEFAULT_SELECTION_BUCKET_ID }; |
---|
| 121 | |
---|
| 122 | /** |
---|
| 123 | * <p> |
---|
| 124 | * the default bucket search order for sequences |
---|
| 125 | * </p> |
---|
| 126 | */ |
---|
| 127 | private static final int[] DEFAULT_SEQUENCE_BUCKET_SEARCH_ORDER = new int[] |
---|
| 128 | { DEFAULT_SEQUENCE_BUCKET_ID, DEFAULT_ITERATION_BUCKET_ID, DEFAULT_OPTIONAL_BUCKET_ID, |
---|
| 129 | DEFAULT_SELECTION_BUCKET_ID }; |
---|
| 130 | |
---|
| 131 | /** |
---|
| 132 | * <p> |
---|
| 133 | * the default bucket search order for selection |
---|
| 134 | * </p> |
---|
| 135 | */ |
---|
| 136 | private static final int[] DEFAULT_SELECTION_BUCKET_SEARCH_ORDER = new int[] |
---|
| 137 | { DEFAULT_SELECTION_BUCKET_ID, DEFAULT_EVENT_BUCKET_ID, DEFAULT_ITERATION_BUCKET_ID, |
---|
| 138 | DEFAULT_OPTIONAL_BUCKET_ID, DEFAULT_SEQUENCE_BUCKET_ID }; |
---|
| 139 | |
---|
| 140 | /** |
---|
| 141 | * <p> |
---|
| 142 | * the default bucket search order for iterations |
---|
| 143 | * </p> |
---|
| 144 | */ |
---|
| 145 | private static final int[] DEFAULT_ITERATION_BUCKET_SEARCH_ORDER = new int[] |
---|
| 146 | { DEFAULT_ITERATION_BUCKET_ID, DEFAULT_OPTIONAL_BUCKET_ID, DEFAULT_SELECTION_BUCKET_ID, |
---|
| 147 | DEFAULT_EVENT_BUCKET_ID, DEFAULT_SEQUENCE_BUCKET_ID }; |
---|
| 148 | |
---|
| 149 | /** |
---|
| 150 | * <p> |
---|
| 151 | * the default bucket search order for optional |
---|
| 152 | * </p> |
---|
| 153 | */ |
---|
| 154 | private static final int[] DEFAULT_OPTIONAL_BUCKET_SEARCH_ORDER = new int[] |
---|
| 155 | { DEFAULT_OPTIONAL_BUCKET_ID, DEFAULT_EVENT_BUCKET_ID, DEFAULT_ITERATION_BUCKET_ID, |
---|
| 156 | DEFAULT_SELECTION_BUCKET_ID, DEFAULT_SEQUENCE_BUCKET_ID }; |
---|
| 157 | |
---|
| 158 | /** |
---|
| 159 | * <p> |
---|
[1408] | 160 | * Comparator to be used for comparing the task instances with each other |
---|
[1285] | 161 | * </p> |
---|
| 162 | */ |
---|
[1853] | 163 | private TaskComparator comparator; |
---|
[1285] | 164 | |
---|
| 165 | /** |
---|
| 166 | * <p> |
---|
[1408] | 167 | * Internally maintained plain list of task instances and associated values |
---|
[1285] | 168 | * </p> |
---|
| 169 | */ |
---|
[1853] | 170 | private List<Map.Entry<ITask, V>> symbolList; |
---|
[1285] | 171 | |
---|
| 172 | /** |
---|
| 173 | * <p> |
---|
[1408] | 174 | * If the size of the map exceeds {@link #MAX_LIST_SIZE}, this is the index using buckets |
---|
[1285] | 175 | * for optimizing the search order. |
---|
| 176 | * </p> |
---|
| 177 | */ |
---|
[1853] | 178 | private Map<Integer, List<Map.Entry<ITask, V>>> symbolBuckets; |
---|
[1285] | 179 | |
---|
| 180 | /** |
---|
| 181 | * <p> |
---|
[1408] | 182 | * When using buckets, not any task instance may be associated a correct bucket. Therefore, we |
---|
| 183 | * set a default bucket for all such task instances. This may change if the same bucket for a |
---|
| 184 | * specific symbol is selected. |
---|
[1285] | 185 | * </p> |
---|
| 186 | */ |
---|
| 187 | private int defaultBucket = 0; |
---|
| 188 | |
---|
| 189 | /** |
---|
| 190 | * <p> |
---|
[2129] | 191 | * the adjustable bucket search order for events. This array is initialized for reuse as |
---|
| 192 | * otherwise for any lookup of a bucket search order for an individual event, this array would |
---|
| 193 | * be recreated. |
---|
| 194 | * </p> |
---|
| 195 | */ |
---|
| 196 | private final int[] ADJUSTABLE_EVENT_SPECIFIC_BUCKET_SEARCH_ORDER = new int[] |
---|
| 197 | { 0, 0, DEFAULT_ITERATION_BUCKET_ID, DEFAULT_OPTIONAL_BUCKET_ID, DEFAULT_EVENT_BUCKET_ID, |
---|
| 198 | DEFAULT_SELECTION_BUCKET_ID }; |
---|
| 199 | |
---|
| 200 | /** |
---|
| 201 | * <p> |
---|
[1408] | 202 | * Instantiates a task instance map with a comparator |
---|
[1285] | 203 | * </p> |
---|
| 204 | * |
---|
[1408] | 205 | * @param comparator the comparator to use for comparing task instances |
---|
[1285] | 206 | * |
---|
| 207 | * @throws IllegalArgumentException if the provided comparator is null |
---|
| 208 | */ |
---|
[1853] | 209 | public TaskSymbolBucketedMap(TaskComparator comparator) { |
---|
[1285] | 210 | if (comparator == null) { |
---|
| 211 | throw new IllegalArgumentException("comparator must not be null"); |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | this.comparator = comparator; |
---|
[1853] | 215 | this.symbolList = new ArrayList<Map.Entry<ITask, V>>(); |
---|
[1285] | 216 | } |
---|
| 217 | |
---|
| 218 | /** |
---|
| 219 | * <p> |
---|
[1408] | 220 | * Copy constructor |
---|
[1285] | 221 | * </p> |
---|
| 222 | * |
---|
| 223 | * @param otherMap the other map to be copied including its comparator |
---|
| 224 | * |
---|
| 225 | * @throws IllegalArgumentException if the provided other map is null |
---|
| 226 | */ |
---|
| 227 | public TaskSymbolBucketedMap(TaskSymbolBucketedMap<V> otherMap) { |
---|
| 228 | if (otherMap == null) { |
---|
| 229 | throw new IllegalArgumentException("otherMap must not be null"); |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | this.comparator = otherMap.comparator; |
---|
[1853] | 233 | this.symbolList = new ArrayList<Map.Entry<ITask, V>>(otherMap.symbolList); |
---|
[1285] | 234 | |
---|
| 235 | if (this.symbolList.size() > MAX_LIST_SIZE) { |
---|
| 236 | createSymbolBuckets(); |
---|
| 237 | } |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | /** |
---|
| 241 | * <p> |
---|
[1408] | 242 | * Returns the size of the map, i.e. the number of task instance entries |
---|
[1285] | 243 | * </p> |
---|
| 244 | * |
---|
| 245 | * @return as described |
---|
| 246 | */ |
---|
| 247 | public int size() { |
---|
| 248 | return symbolList.size(); |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | /** |
---|
| 252 | * <p> |
---|
| 253 | * Returns true if this map is empty, i.e. if {@link #size()} returns 0 |
---|
| 254 | * </p> |
---|
| 255 | * |
---|
| 256 | * @return as described |
---|
| 257 | */ |
---|
| 258 | public boolean isEmpty() { |
---|
| 259 | return symbolList.isEmpty(); |
---|
| 260 | } |
---|
| 261 | |
---|
| 262 | /** |
---|
| 263 | * <p> |
---|
[1408] | 264 | * Returns true if the provided task instance was stored in this map. |
---|
[1285] | 265 | * </p> |
---|
| 266 | * |
---|
[1408] | 267 | * @param symbol the task instance to check if it was stored in this map |
---|
[1285] | 268 | * |
---|
| 269 | * @return as described |
---|
| 270 | * |
---|
[1408] | 271 | * @throws IllegalArgumentException if the provided task instance is null |
---|
[1285] | 272 | */ |
---|
[1853] | 273 | public boolean containsSymbol(ITask symbol) { |
---|
[1285] | 274 | if (symbol == null) { |
---|
| 275 | throw new IllegalArgumentException("symbol must not be null"); |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | return getEntry(symbol) != null; |
---|
| 279 | } |
---|
| 280 | |
---|
| 281 | /** |
---|
| 282 | * <p> |
---|
[1408] | 283 | * Returns the value associated to the provided task instance in this map. If there is no value |
---|
| 284 | * associated to the given task instance or if the task instance is not stored in this map, |
---|
| 285 | * the method returns null. |
---|
[1285] | 286 | * </p> |
---|
| 287 | * |
---|
[1408] | 288 | * @param symbol the task instance to return the value for |
---|
[1285] | 289 | * |
---|
| 290 | * @return as described |
---|
| 291 | * |
---|
[1408] | 292 | * @throws IllegalArgumentException if the provided task instance is null |
---|
[1285] | 293 | */ |
---|
[1853] | 294 | public V getValue(ITask symbol) { |
---|
[1285] | 295 | if (symbol == null) { |
---|
| 296 | throw new IllegalArgumentException("symbol must not be null"); |
---|
| 297 | } |
---|
| 298 | |
---|
[1853] | 299 | Map.Entry<ITask, V> entry = getEntry(symbol); |
---|
[1285] | 300 | |
---|
| 301 | if (entry != null) { |
---|
| 302 | return entry.getValue(); |
---|
| 303 | } |
---|
| 304 | else { |
---|
| 305 | return null; |
---|
| 306 | } |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | /** |
---|
| 310 | * <p> |
---|
[1408] | 311 | * Adds a task instance and an associated value to the map. If the value is null, the task |
---|
| 312 | * instance is added, anyway and {@link #containsSymbol(Object)} will return true for that |
---|
| 313 | * task instance. Adding the same task instance twice will produce two entries. This is |
---|
| 314 | * contradictory to typical map implementations. To prevent this, the |
---|
| 315 | * {@link #containsSymbol(Object)} and {@link #removeSymbol(Object)} methods should be used to |
---|
| 316 | * ensure map behavior. |
---|
[1285] | 317 | * </p> |
---|
| 318 | * |
---|
[1408] | 319 | * @param symbol the task instance to add to the map |
---|
| 320 | * @param value the value to associate to the task instance in this map |
---|
[1285] | 321 | * |
---|
| 322 | * @return as described |
---|
| 323 | * |
---|
[1408] | 324 | * @throws IllegalArgumentException if the provided task instance is null |
---|
[1285] | 325 | */ |
---|
[1853] | 326 | public void addSymbol(ITask symbol, V value) { |
---|
[1285] | 327 | if (symbol == null) { |
---|
| 328 | throw new IllegalArgumentException("symbol must not be null"); |
---|
| 329 | } |
---|
| 330 | |
---|
[1853] | 331 | Map.Entry<ITask, V> entry = new SymbolMapEntry(symbol, value); |
---|
[1285] | 332 | |
---|
| 333 | symbolList.add(entry); |
---|
| 334 | |
---|
| 335 | if (symbolList.size() > MAX_LIST_SIZE) { |
---|
| 336 | if (symbolBuckets == null) { |
---|
| 337 | createSymbolBuckets(); |
---|
| 338 | } |
---|
| 339 | else { |
---|
| 340 | addToSymbolBucket(entry); |
---|
| 341 | } |
---|
| 342 | } |
---|
| 343 | } |
---|
| 344 | |
---|
| 345 | /** |
---|
| 346 | * <p> |
---|
[1408] | 347 | * Removes a task instance and its associated value from the map. If the task instance is |
---|
| 348 | * stored several times, only the first of its occurrences is removed. |
---|
[1285] | 349 | * </p> |
---|
| 350 | * |
---|
[1408] | 351 | * @param symbol the task instance to be removed from the map |
---|
[1285] | 352 | * |
---|
| 353 | * @return as described |
---|
| 354 | * |
---|
[1408] | 355 | * @throws IllegalArgumentException if the provided task instance is null |
---|
[1285] | 356 | */ |
---|
[1853] | 357 | public V removeSymbol(ITask symbol) { |
---|
[1285] | 358 | if (symbol == null) { |
---|
| 359 | throw new IllegalArgumentException("symbol must not be null"); |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | for (int i = 0; i < symbolList.size(); i++) { |
---|
| 363 | if (comparator.equals(symbolList.get(i).getKey(), symbol)) { |
---|
| 364 | // found the symbol. Remove it from the list, and if required, also from the map. |
---|
| 365 | V value = symbolList.remove(i).getValue(); |
---|
| 366 | |
---|
| 367 | if (symbolList.size() > MAX_LIST_SIZE) { |
---|
| 368 | removeFromSymbolBuckets(symbol); |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | return value; |
---|
| 372 | } |
---|
| 373 | } |
---|
| 374 | |
---|
| 375 | return null; |
---|
| 376 | } |
---|
| 377 | |
---|
| 378 | /** |
---|
| 379 | * <p> |
---|
[1408] | 380 | * Returns a collection of all task instances in this map. |
---|
[1285] | 381 | * </p> |
---|
| 382 | * |
---|
| 383 | * @return as described |
---|
| 384 | */ |
---|
[1853] | 385 | public Collection<ITask> getSymbols() { |
---|
| 386 | return new ReadOnlyCollectionFacade<ITask>(symbolList, new SymbolFacade()); |
---|
[1285] | 387 | } |
---|
| 388 | |
---|
| 389 | /** |
---|
| 390 | * <p> |
---|
[1408] | 391 | * Returns a collection of all values associated to task instances in this map. May contain |
---|
| 392 | * null values, if some of the task instances are mapped to null. The length of the returned |
---|
| 393 | * collection is in any case the same as the size of the map. |
---|
[1285] | 394 | * </p> |
---|
| 395 | * |
---|
| 396 | * @return as described |
---|
| 397 | */ |
---|
| 398 | public Collection<V> getValues() { |
---|
| 399 | return new ReadOnlyCollectionFacade<V>(symbolList, new ValueFacade()); |
---|
| 400 | } |
---|
| 401 | |
---|
| 402 | /** |
---|
| 403 | * <p> |
---|
[1408] | 404 | * Removes all task instances and associated values from the map. |
---|
[1285] | 405 | * </p> |
---|
| 406 | */ |
---|
| 407 | public void clear() { |
---|
| 408 | symbolList.clear(); |
---|
| 409 | symbolBuckets = null; |
---|
| 410 | } |
---|
| 411 | |
---|
| 412 | /* (non-Javadoc) |
---|
| 413 | * @see java.lang.Object#hashCode() |
---|
| 414 | */ |
---|
| 415 | @Override |
---|
| 416 | public int hashCode() { |
---|
| 417 | return symbolList.size(); |
---|
| 418 | } |
---|
| 419 | |
---|
| 420 | /* (non-Javadoc) |
---|
| 421 | * @see java.lang.Object#equals(java.lang.Object) |
---|
| 422 | */ |
---|
| 423 | @SuppressWarnings("unchecked") |
---|
| 424 | @Override |
---|
| 425 | public boolean equals(Object obj) { |
---|
| 426 | if (this == obj) { |
---|
| 427 | return true; |
---|
| 428 | } |
---|
| 429 | else if (this.getClass().isInstance(obj)) { |
---|
| 430 | TaskSymbolBucketedMap<V> other = (TaskSymbolBucketedMap<V>) obj; |
---|
| 431 | |
---|
| 432 | return (symbolList.size() == other.symbolList.size()) && |
---|
| 433 | (symbolList.containsAll(other.symbolList)); |
---|
| 434 | } |
---|
| 435 | else { |
---|
| 436 | return false; |
---|
| 437 | } |
---|
| 438 | } |
---|
| 439 | |
---|
| 440 | /** |
---|
| 441 | * <p> |
---|
[1408] | 442 | * Internally used to create task instance buckets in case the number of stored task instances |
---|
| 443 | * increased above {@link #MAX_LIST_SIZE}. |
---|
[1285] | 444 | * </p> |
---|
| 445 | */ |
---|
| 446 | private void createSymbolBuckets() { |
---|
[1853] | 447 | symbolBuckets = new HashMap<Integer, List<Map.Entry<ITask, V>>>(); |
---|
[1285] | 448 | |
---|
[1853] | 449 | for (Map.Entry<ITask, V> symbol : symbolList) { |
---|
[1285] | 450 | addToSymbolBucket(symbol); |
---|
| 451 | } |
---|
| 452 | } |
---|
| 453 | |
---|
| 454 | /** |
---|
| 455 | * <p> |
---|
[1408] | 456 | * Adds a task instance and its value to its corresponding bucket. The corresponding bucket is |
---|
| 457 | * the first element of the array returned by the method |
---|
| 458 | * {@link #getBucketSearchOrder(ITaskInstance)}. If no search order for a task instance is |
---|
| 459 | * defined, the entry is added to the default bucket. If the bucket id identical to the default |
---|
| 460 | * bucket id, the default bucket id is shifted to another value. |
---|
[1285] | 461 | * </p> |
---|
| 462 | */ |
---|
[1853] | 463 | private void addToSymbolBucket(Map.Entry<ITask, V> symbolEntry) { |
---|
[1285] | 464 | int bucketId = defaultBucket; |
---|
| 465 | int[] bucketSearchOrder = getBucketSearchOrder(symbolEntry.getKey()); |
---|
| 466 | |
---|
| 467 | if ((bucketSearchOrder != null) && (bucketSearchOrder.length > 0)) { |
---|
| 468 | bucketId = bucketSearchOrder[0]; |
---|
| 469 | |
---|
| 470 | if (bucketId == defaultBucket) { |
---|
| 471 | setNewDefaultBucketId(); |
---|
| 472 | } |
---|
| 473 | } |
---|
| 474 | |
---|
[1853] | 475 | List<Map.Entry<ITask, V>> list = symbolBuckets.get(bucketId); |
---|
[1285] | 476 | |
---|
| 477 | if (list == null) { |
---|
[1853] | 478 | list = new LinkedList<Map.Entry<ITask, V>>(); |
---|
[1285] | 479 | symbolBuckets.put(bucketId, list); |
---|
| 480 | } |
---|
| 481 | |
---|
| 482 | list.add(symbolEntry); |
---|
| 483 | } |
---|
| 484 | |
---|
| 485 | /** |
---|
[1408] | 486 | * <p> |
---|
| 487 | * returns the search order for a task instance which is different for event task instances, |
---|
| 488 | * sequence instances, selection instances, and iteration instances |
---|
| 489 | * </p> |
---|
[1285] | 490 | */ |
---|
[1853] | 491 | private int[] getBucketSearchOrder(ITask task) { |
---|
[1285] | 492 | // 0 = sequence; 1 = selection; 2 = iteration; 3 = optional; 4 = event task in general; |
---|
| 493 | // other = hashCode of name of event type |
---|
| 494 | |
---|
[1853] | 495 | if (task instanceof IEventTask) { |
---|
[1408] | 496 | // event tasks are most likely equal to those of the same type happening on the same |
---|
| 497 | // target. Afterwards, they should be equal to those of the event type with the same |
---|
| 498 | // name. Afterwards, they may be equal to iterations, optionals, other event tasks, |
---|
[1285] | 499 | // selections, and finally the rest. |
---|
[1853] | 500 | |
---|
[2129] | 501 | Collection<ITaskInstance> instances = task.getInstances(); |
---|
| 502 | |
---|
| 503 | if (instances.size() > 0) { |
---|
| 504 | Event event = ((IEventTaskInstance) instances.iterator().next()).getEvent(); |
---|
[1853] | 505 | |
---|
[2129] | 506 | ADJUSTABLE_EVENT_SPECIFIC_BUCKET_SEARCH_ORDER[0] = |
---|
| 507 | event.getTarget().hashCode() + event.getType().getName().hashCode(); |
---|
| 508 | ADJUSTABLE_EVENT_SPECIFIC_BUCKET_SEARCH_ORDER[1] = |
---|
| 509 | event.getType().getName().hashCode(); |
---|
| 510 | |
---|
| 511 | return ADJUSTABLE_EVENT_SPECIFIC_BUCKET_SEARCH_ORDER; |
---|
[1853] | 512 | } |
---|
| 513 | else { |
---|
[2129] | 514 | return DEFAULT_EVENT_BUCKET_SEARCH_ORDER; |
---|
[1853] | 515 | } |
---|
[1285] | 516 | } |
---|
[1853] | 517 | else if (task instanceof ISequence) { |
---|
[2129] | 518 | return DEFAULT_SEQUENCE_BUCKET_SEARCH_ORDER; |
---|
[1285] | 519 | } |
---|
[1853] | 520 | else if (task instanceof ISelection) { |
---|
[2129] | 521 | return DEFAULT_SELECTION_BUCKET_SEARCH_ORDER; |
---|
[1285] | 522 | } |
---|
[1853] | 523 | else if (task instanceof IIteration) { |
---|
[2129] | 524 | return DEFAULT_ITERATION_BUCKET_SEARCH_ORDER; |
---|
[1285] | 525 | } |
---|
[1853] | 526 | else if (task instanceof IOptional) { |
---|
[2129] | 527 | return DEFAULT_OPTIONAL_BUCKET_SEARCH_ORDER; |
---|
[1853] | 528 | } |
---|
[1285] | 529 | |
---|
| 530 | return null; |
---|
| 531 | } |
---|
| 532 | |
---|
| 533 | /** |
---|
| 534 | * <p> |
---|
[1408] | 535 | * Removes the entry for a given task instance from the buckets. It uses the bucket search order |
---|
| 536 | * defined to find the task instance as fast as possible. |
---|
[1285] | 537 | * </p> |
---|
| 538 | */ |
---|
[1853] | 539 | private Map.Entry<ITask, V> removeFromSymbolBuckets(ITask symbol) { |
---|
[1285] | 540 | int bucketId = defaultBucket; |
---|
| 541 | int[] bucketSearchOrder = getBucketSearchOrder(symbol); |
---|
| 542 | |
---|
| 543 | if ((bucketSearchOrder != null) && (bucketSearchOrder.length > 0)) { |
---|
| 544 | bucketId = bucketSearchOrder[0]; |
---|
| 545 | } |
---|
| 546 | |
---|
[1853] | 547 | List<Map.Entry<ITask, V>> list = symbolBuckets.get(bucketId); |
---|
| 548 | Map.Entry<ITask, V> result = null; |
---|
[1285] | 549 | |
---|
| 550 | if (list != null) { |
---|
| 551 | for (int i = 0; i < list.size(); i++) { |
---|
| 552 | if (comparator.equals(list.get(i).getKey(), symbol)) { |
---|
| 553 | result = list.remove(i); |
---|
| 554 | break; |
---|
| 555 | } |
---|
| 556 | } |
---|
| 557 | |
---|
| 558 | if (list.isEmpty()) { |
---|
| 559 | symbolBuckets.remove(bucketId); |
---|
| 560 | } |
---|
| 561 | } |
---|
| 562 | |
---|
| 563 | return result; |
---|
| 564 | } |
---|
| 565 | |
---|
| 566 | /** |
---|
| 567 | * <p> |
---|
| 568 | * Updates the default bucket id to a new one |
---|
| 569 | * </p> |
---|
| 570 | */ |
---|
| 571 | private void setNewDefaultBucketId() { |
---|
| 572 | int oldDefaultBucket = defaultBucket; |
---|
| 573 | do { |
---|
| 574 | defaultBucket += 1; |
---|
| 575 | } |
---|
| 576 | while (symbolBuckets.containsKey(defaultBucket)); |
---|
| 577 | |
---|
[1408] | 578 | symbolBuckets.put(defaultBucket, symbolBuckets.remove(oldDefaultBucket)); |
---|
[1285] | 579 | } |
---|
| 580 | |
---|
| 581 | /** |
---|
| 582 | * <p> |
---|
[1408] | 583 | * searches for the entry belonging to the given task instance. The method either uses the |
---|
| 584 | * list if buckets are not used yet, or it uses the buckets and searches them in the order |
---|
| 585 | * defined by the method {@link #getBucketSearchOrder(ITaskInstance)}. If the task instances |
---|
| 586 | * isn't found and the bucket search order does not refer all buckets, then also the other |
---|
| 587 | * buckets are searched for the task instance. |
---|
[1285] | 588 | * </p> |
---|
| 589 | */ |
---|
[1853] | 590 | private Map.Entry<ITask, V> getEntry(ITask symbol) { |
---|
| 591 | Map.Entry<ITask, V> entry = null; |
---|
[1285] | 592 | if (symbolBuckets == null) { |
---|
| 593 | entry = lookup(symbol, symbolList); |
---|
| 594 | } |
---|
| 595 | else { |
---|
| 596 | int[] bucketSearchOrder = getBucketSearchOrder(symbol); |
---|
| 597 | for (int bucketId : bucketSearchOrder) { |
---|
[1853] | 598 | List<Map.Entry<ITask, V>> list = symbolBuckets.get(bucketId); |
---|
[1285] | 599 | if (list != null) { |
---|
| 600 | entry = lookup(symbol, list); |
---|
| 601 | if (entry != null) { |
---|
| 602 | break; |
---|
| 603 | } |
---|
| 604 | } |
---|
| 605 | } |
---|
| 606 | |
---|
[2129] | 607 | // try to search the other buckets (may be required, if bucket separation given by |
---|
| 608 | // bucket ids is different from logical bucket separation of comparator |
---|
[1285] | 609 | if (entry == null) { |
---|
[2129] | 610 | // create a copy of the search order to be able to sort and afterwards binary |
---|
| 611 | // search it. The original version MUST NOT BE SORTED. |
---|
| 612 | int[] bucketSearchOrderCopy = |
---|
| 613 | Arrays.copyOf(bucketSearchOrder, bucketSearchOrder.length); |
---|
| 614 | |
---|
| 615 | Arrays.sort(bucketSearchOrderCopy); |
---|
[1853] | 616 | for (Map.Entry<Integer, List<Map.Entry<ITask, V>>> bucket : symbolBuckets.entrySet()) { |
---|
[2129] | 617 | if (Arrays.binarySearch(bucketSearchOrderCopy, bucket.getKey()) < 0) { |
---|
[1853] | 618 | List<Map.Entry<ITask, V>> list = bucket.getValue(); |
---|
[1285] | 619 | if (list != null) { |
---|
| 620 | entry = lookup(symbol, list); |
---|
| 621 | if (entry != null) { |
---|
| 622 | break; |
---|
| 623 | } |
---|
| 624 | } |
---|
| 625 | } |
---|
| 626 | } |
---|
| 627 | } |
---|
| 628 | } |
---|
| 629 | |
---|
| 630 | return entry; |
---|
| 631 | } |
---|
| 632 | |
---|
| 633 | /** |
---|
| 634 | * <p> |
---|
| 635 | * Convenience method to look up a symbol in a list of entries using the comparator. |
---|
| 636 | * </p> |
---|
| 637 | */ |
---|
[1853] | 638 | private Map.Entry<ITask, V> lookup(ITask symbol, List<Map.Entry<ITask, V>> list) { |
---|
| 639 | for (Map.Entry<ITask, V> candidate : list) { |
---|
[1285] | 640 | if (comparator.equals(candidate.getKey(), symbol)) { |
---|
| 641 | return candidate; |
---|
| 642 | } |
---|
| 643 | } |
---|
| 644 | |
---|
| 645 | return null; |
---|
| 646 | } |
---|
| 647 | |
---|
| 648 | /** |
---|
| 649 | * <p> |
---|
[1408] | 650 | * Internally used data structure for storing task instance - value pairs |
---|
[1285] | 651 | * </p> |
---|
| 652 | * |
---|
| 653 | * @author Patrick Harms |
---|
| 654 | */ |
---|
[1853] | 655 | private class SymbolMapEntry implements Map.Entry<ITask, V> { |
---|
[1285] | 656 | |
---|
| 657 | /** |
---|
[1408] | 658 | * the task instance to map to a value |
---|
[1285] | 659 | */ |
---|
[1853] | 660 | private ITask symbol; |
---|
[1285] | 661 | |
---|
| 662 | /** |
---|
| 663 | * the value associated with the symbol |
---|
| 664 | */ |
---|
| 665 | private V value; |
---|
| 666 | |
---|
| 667 | /** |
---|
| 668 | * <p> |
---|
[1408] | 669 | * Simple constructor for initializing the entry with a task instance and its associated |
---|
| 670 | * value. |
---|
[1285] | 671 | * </p> |
---|
| 672 | */ |
---|
[1853] | 673 | private SymbolMapEntry(ITask symbol, V value) { |
---|
[1285] | 674 | super(); |
---|
| 675 | this.symbol = symbol; |
---|
| 676 | this.value = value; |
---|
| 677 | } |
---|
| 678 | |
---|
| 679 | /* (non-Javadoc) |
---|
| 680 | * @see java.util.Map.Entry#getKey() |
---|
| 681 | */ |
---|
| 682 | @Override |
---|
[1853] | 683 | public ITask getKey() { |
---|
[1285] | 684 | return symbol; |
---|
| 685 | } |
---|
| 686 | |
---|
| 687 | /* (non-Javadoc) |
---|
| 688 | * @see java.util.Map.Entry#getValue() |
---|
| 689 | */ |
---|
| 690 | @Override |
---|
| 691 | public V getValue() { |
---|
| 692 | return value; |
---|
| 693 | } |
---|
| 694 | |
---|
| 695 | /* (non-Javadoc) |
---|
| 696 | * @see java.util.Map.Entry#setValue(java.lang.Object) |
---|
| 697 | */ |
---|
| 698 | @Override |
---|
| 699 | public V setValue(V value) { |
---|
| 700 | V oldValue = this.value; |
---|
| 701 | this.value = value; |
---|
| 702 | return oldValue; |
---|
| 703 | } |
---|
| 704 | |
---|
| 705 | /* (non-Javadoc) |
---|
| 706 | * @see java.lang.Object#hashCode() |
---|
| 707 | */ |
---|
| 708 | @Override |
---|
| 709 | public int hashCode() { |
---|
| 710 | return symbol.hashCode(); |
---|
| 711 | } |
---|
| 712 | |
---|
| 713 | /* (non-Javadoc) |
---|
| 714 | * @see java.lang.Object#equals(java.lang.Object) |
---|
| 715 | */ |
---|
| 716 | @SuppressWarnings("unchecked") |
---|
| 717 | @Override |
---|
| 718 | public boolean equals(Object obj) { |
---|
| 719 | if (this == obj) { |
---|
| 720 | return true; |
---|
| 721 | } |
---|
| 722 | else if (this.getClass().isInstance(obj)) { |
---|
| 723 | SymbolMapEntry other = (SymbolMapEntry) obj; |
---|
| 724 | return (symbol.equals(other.symbol) && |
---|
| 725 | (value == null ? other.value == null : value.equals(other.value))); |
---|
| 726 | } |
---|
| 727 | else { |
---|
| 728 | return false; |
---|
| 729 | } |
---|
| 730 | } |
---|
| 731 | |
---|
| 732 | /* (non-Javadoc) |
---|
| 733 | * @see java.lang.Object#toString() |
---|
| 734 | */ |
---|
| 735 | @Override |
---|
| 736 | public String toString() { |
---|
| 737 | return symbol + "=" + value; |
---|
| 738 | } |
---|
| 739 | |
---|
| 740 | } |
---|
| 741 | |
---|
| 742 | /** |
---|
| 743 | * <p> |
---|
| 744 | * Used to create an efficient facade for accessing the internal list of entries either only |
---|
[1408] | 745 | * for the task instances or only for the values. It is a default implementation of the |
---|
| 746 | * collection interface. The entry facade provided to the constructor decides, if either the |
---|
| 747 | * list accesses only the task instances or only the values. |
---|
[1285] | 748 | * </p> |
---|
| 749 | * |
---|
| 750 | * @author Patrick Harms |
---|
| 751 | */ |
---|
| 752 | private class ReadOnlyCollectionFacade<TYPE> implements Collection<TYPE> { |
---|
| 753 | |
---|
| 754 | /** |
---|
| 755 | * the list facaded by this facade |
---|
| 756 | */ |
---|
[1853] | 757 | private List<Map.Entry<ITask, V>> list; |
---|
[1285] | 758 | |
---|
| 759 | /** |
---|
| 760 | * the facade to be used for the entries |
---|
| 761 | */ |
---|
| 762 | private EntryFacade<TYPE> entryFacade; |
---|
| 763 | |
---|
| 764 | /** |
---|
| 765 | * <p> |
---|
| 766 | * Initializes the facade with the facaded list and the facade to be used for the entries |
---|
| 767 | * </p> |
---|
| 768 | */ |
---|
[1853] | 769 | private ReadOnlyCollectionFacade(List<Map.Entry<ITask, V>> list, |
---|
| 770 | EntryFacade<TYPE> entryFacade) |
---|
[1285] | 771 | { |
---|
| 772 | this.list = list; |
---|
| 773 | this.entryFacade = entryFacade; |
---|
| 774 | } |
---|
| 775 | |
---|
| 776 | /* (non-Javadoc) |
---|
| 777 | * @see java.util.Collection#size() |
---|
| 778 | */ |
---|
| 779 | @Override |
---|
| 780 | public int size() { |
---|
| 781 | return list.size(); |
---|
| 782 | } |
---|
| 783 | |
---|
| 784 | /* (non-Javadoc) |
---|
| 785 | * @see java.util.Collection#isEmpty() |
---|
| 786 | */ |
---|
| 787 | @Override |
---|
| 788 | public boolean isEmpty() { |
---|
| 789 | return list.isEmpty(); |
---|
| 790 | } |
---|
| 791 | |
---|
| 792 | /* (non-Javadoc) |
---|
| 793 | * @see java.util.Collection#contains(java.lang.Object) |
---|
| 794 | */ |
---|
| 795 | @Override |
---|
| 796 | public boolean contains(Object o) { |
---|
| 797 | if (o == null) { |
---|
[1853] | 798 | for (Map.Entry<ITask, V> entry : list) { |
---|
[1285] | 799 | if (entryFacade.getFacadedElement(entry) == null) { |
---|
| 800 | return true; |
---|
| 801 | } |
---|
| 802 | } |
---|
| 803 | } |
---|
| 804 | else { |
---|
[1853] | 805 | for (Map.Entry<ITask, V> entry : list) { |
---|
[1285] | 806 | if (o.equals(entryFacade.getFacadedElement(entry))) { |
---|
| 807 | return true; |
---|
| 808 | } |
---|
| 809 | } |
---|
| 810 | } |
---|
| 811 | |
---|
| 812 | return false; |
---|
| 813 | } |
---|
| 814 | |
---|
| 815 | /* (non-Javadoc) |
---|
| 816 | * @see java.util.Collection#toArray() |
---|
| 817 | */ |
---|
| 818 | @Override |
---|
| 819 | public Object[] toArray() { |
---|
| 820 | Object[] result = new Object[list.size()]; |
---|
| 821 | |
---|
| 822 | for (int i = 0; i < list.size(); i++) { |
---|
| 823 | result[i] = entryFacade.getFacadedElement(list.get(i)); |
---|
| 824 | } |
---|
| 825 | |
---|
| 826 | return result; |
---|
| 827 | } |
---|
| 828 | |
---|
| 829 | /* (non-Javadoc) |
---|
| 830 | * @see java.util.Collection#toArray(T[]) |
---|
| 831 | */ |
---|
| 832 | @SuppressWarnings("unchecked") |
---|
| 833 | @Override |
---|
| 834 | public <T> T[] toArray(T[] a) { |
---|
| 835 | T[] result = a; |
---|
| 836 | |
---|
| 837 | for (int i = 0; i < list.size(); i++) { |
---|
| 838 | result[i] = (T) entryFacade.getFacadedElement(list.get(i)); |
---|
| 839 | } |
---|
| 840 | |
---|
| 841 | return result; |
---|
| 842 | } |
---|
| 843 | |
---|
| 844 | /* (non-Javadoc) |
---|
| 845 | * @see java.util.Collection#add(java.lang.Object) |
---|
| 846 | */ |
---|
| 847 | @Override |
---|
| 848 | public boolean add(TYPE e) { |
---|
| 849 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 850 | } |
---|
| 851 | |
---|
| 852 | /* (non-Javadoc) |
---|
| 853 | * @see java.util.Collection#remove(java.lang.Object) |
---|
| 854 | */ |
---|
| 855 | @Override |
---|
| 856 | public boolean remove(Object o) { |
---|
| 857 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 858 | } |
---|
| 859 | |
---|
| 860 | /* (non-Javadoc) |
---|
| 861 | * @see java.util.Collection#containsAll(java.util.Collection) |
---|
| 862 | */ |
---|
| 863 | @Override |
---|
| 864 | public boolean containsAll(Collection<?> c) { |
---|
| 865 | for (Object candidate : c) { |
---|
| 866 | if (!contains(candidate)) { |
---|
| 867 | return false; |
---|
| 868 | } |
---|
| 869 | } |
---|
| 870 | |
---|
| 871 | return true; |
---|
| 872 | } |
---|
| 873 | |
---|
| 874 | /* (non-Javadoc) |
---|
| 875 | * @see java.util.Collection#addAll(java.util.Collection) |
---|
| 876 | */ |
---|
| 877 | @Override |
---|
| 878 | public boolean addAll(Collection<? extends TYPE> c) { |
---|
| 879 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 880 | } |
---|
| 881 | |
---|
| 882 | /* (non-Javadoc) |
---|
| 883 | * @see java.util.Collection#removeAll(java.util.Collection) |
---|
| 884 | */ |
---|
| 885 | @Override |
---|
| 886 | public boolean removeAll(Collection<?> c) { |
---|
| 887 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 888 | } |
---|
| 889 | |
---|
| 890 | /* (non-Javadoc) |
---|
| 891 | * @see java.util.Collection#retainAll(java.util.Collection) |
---|
| 892 | */ |
---|
| 893 | @Override |
---|
| 894 | public boolean retainAll(Collection<?> c) { |
---|
| 895 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 896 | } |
---|
| 897 | |
---|
| 898 | /* (non-Javadoc) |
---|
| 899 | * @see java.util.Collection#clear() |
---|
| 900 | */ |
---|
| 901 | @Override |
---|
| 902 | public void clear() { |
---|
| 903 | throw new UnsupportedOperationException("this collection is read only"); |
---|
| 904 | } |
---|
| 905 | |
---|
| 906 | /* (non-Javadoc) |
---|
| 907 | * @see java.util.Collection#iterator() |
---|
| 908 | */ |
---|
| 909 | @Override |
---|
| 910 | public Iterator<TYPE> iterator() { |
---|
| 911 | return new ReadOnlyCollectionIteratorFacade<TYPE>(list.iterator(), entryFacade); |
---|
| 912 | } |
---|
| 913 | |
---|
| 914 | } |
---|
| 915 | |
---|
| 916 | /** |
---|
| 917 | * <p> |
---|
[1408] | 918 | * Implementation of an iterator to facade an iterator on the internal list of task instance |
---|
| 919 | * entries. |
---|
[1285] | 920 | * </p> |
---|
| 921 | * |
---|
| 922 | * @author Patrick Harms |
---|
| 923 | */ |
---|
| 924 | private class ReadOnlyCollectionIteratorFacade<TYPE> implements Iterator<TYPE> { |
---|
| 925 | |
---|
| 926 | /** |
---|
| 927 | * the facaded iterator |
---|
| 928 | */ |
---|
[1853] | 929 | private Iterator<Map.Entry<ITask, V>> iterator; |
---|
[1285] | 930 | |
---|
| 931 | /** |
---|
| 932 | * the facade for the entries provided by the facaded iterator |
---|
| 933 | */ |
---|
| 934 | private EntryFacade<TYPE> entryFacade; |
---|
| 935 | |
---|
| 936 | /** |
---|
| 937 | * <p> |
---|
| 938 | * initialized this facade with the facaded iterator and the entry facade to be used for |
---|
| 939 | * the entries. |
---|
| 940 | * </p> |
---|
| 941 | */ |
---|
[1853] | 942 | private ReadOnlyCollectionIteratorFacade(Iterator<Map.Entry<ITask, V>> iterator, |
---|
| 943 | EntryFacade<TYPE> entryFacade) |
---|
[1285] | 944 | { |
---|
| 945 | this.iterator = iterator; |
---|
| 946 | this.entryFacade = entryFacade; |
---|
| 947 | } |
---|
| 948 | |
---|
| 949 | /* (non-Javadoc) |
---|
| 950 | * @see java.util.Iterator#hasNext() |
---|
| 951 | */ |
---|
| 952 | @Override |
---|
| 953 | public boolean hasNext() { |
---|
| 954 | return iterator.hasNext(); |
---|
| 955 | } |
---|
| 956 | |
---|
| 957 | /* (non-Javadoc) |
---|
| 958 | * @see java.util.Iterator#next() |
---|
| 959 | */ |
---|
| 960 | @Override |
---|
| 961 | public TYPE next() { |
---|
| 962 | return entryFacade.getFacadedElement(iterator.next()); |
---|
| 963 | } |
---|
| 964 | |
---|
| 965 | /* (non-Javadoc) |
---|
| 966 | * @see java.util.Iterator#remove() |
---|
| 967 | */ |
---|
| 968 | @Override |
---|
| 969 | public void remove() { |
---|
| 970 | throw new UnsupportedOperationException("this iterator is read only"); |
---|
| 971 | } |
---|
| 972 | |
---|
| 973 | } |
---|
| 974 | |
---|
| 975 | /** |
---|
| 976 | * <p> |
---|
[1408] | 977 | * Used to facade task instance entries and to return only this part of an entry, that is |
---|
| 978 | * relevant. |
---|
[1285] | 979 | * </p> |
---|
| 980 | * |
---|
| 981 | * @author Patrick Harms |
---|
| 982 | */ |
---|
| 983 | private abstract class EntryFacade<T> { |
---|
| 984 | |
---|
| 985 | /** |
---|
| 986 | * <p> |
---|
| 987 | * Returns only the part of an entry that is relevant or required. |
---|
| 988 | * </p> |
---|
| 989 | * |
---|
| 990 | * @param entry of which the part shall be returned |
---|
| 991 | * |
---|
| 992 | * @return the part of the entry to be returned |
---|
| 993 | */ |
---|
[1853] | 994 | protected abstract T getFacadedElement(Entry<ITask, V> entry); |
---|
[1285] | 995 | |
---|
| 996 | } |
---|
| 997 | |
---|
| 998 | /** |
---|
| 999 | * <p> |
---|
| 1000 | * Implementation of the entry facade returning the entries key, i.e. the symbol. |
---|
| 1001 | * </p> |
---|
| 1002 | * |
---|
| 1003 | * @author Patrick Harms |
---|
| 1004 | */ |
---|
[1853] | 1005 | private class SymbolFacade extends EntryFacade<ITask> { |
---|
[1285] | 1006 | |
---|
| 1007 | /* (non-Javadoc) |
---|
| 1008 | * @see ReadOnlyCollectionIteratorFacade#getFacadedElement(Entry) |
---|
| 1009 | */ |
---|
| 1010 | @Override |
---|
[1853] | 1011 | protected ITask getFacadedElement(Entry<ITask, V> entry) { |
---|
[1285] | 1012 | return entry.getKey(); |
---|
| 1013 | } |
---|
| 1014 | } |
---|
| 1015 | |
---|
| 1016 | /** |
---|
| 1017 | * <p> |
---|
| 1018 | * Implementation of the entry facade returning the entries value, i.e. the value associated to |
---|
| 1019 | * the symbol. |
---|
| 1020 | * </p> |
---|
| 1021 | * |
---|
| 1022 | * @author Patrick Harms |
---|
| 1023 | */ |
---|
| 1024 | private class ValueFacade extends EntryFacade<V> { |
---|
| 1025 | |
---|
| 1026 | /* (non-Javadoc) |
---|
| 1027 | * @see ReadOnlyCollectionIteratorFacade#getFacadedElement(Entry) |
---|
| 1028 | */ |
---|
| 1029 | @Override |
---|
[1853] | 1030 | protected V getFacadedElement(Entry<ITask, V> entry) { |
---|
[1285] | 1031 | return entry.getValue(); |
---|
| 1032 | } |
---|
| 1033 | } |
---|
| 1034 | |
---|
| 1035 | } |
---|