private void validateForPrioritize(S s) { if (s.strict()) { throw new IllegalArgumentException(s.name() + ": not prioritizable: is strict"); } if (!this.range.contains(s)) { throw new IllegalArgumentException(s.name() + ": not contained or is backup"); } }
private boolean containsName(List<S> source, String strategyName) { for (S s : source) { if (s.name().equals(strategyName)) { return true; } } return false; }
/** * Removes the given strategy and returns true if it was found and removed. If <code>s</code> is * strict then it will be searched by target, else it will be searched by name. * * @param s to remove * @return true if strategy has been removed, false otherwise */ public boolean remove(S s) { if (s.strict()) { return this.strict.remove(s.target()) != null; } else { final ListIterator<S> it = this.range.listIterator(); while (it.hasNext()) { if (it.next().name().equals(s.name())) { it.remove(); return true; } } return false; } }
/** * Adds the given strategy. If <code>s.strict()</code> and this instance already contains a * strict strategy with the exact same target then <code>s</code> will replace the contained * strategy. * * @param s to add * @return the replaced strict strategy, if any, or null */ public S add(S s) { if (s.strict()) { return this.strict.put(s.target(), s); } else { final ListIterator<S> it = this.range.listIterator(); while (it.hasNext()) { final S crt = it.next(); if (crt.target().isAssignableFrom(s.target())) { it.set(s); it.add(crt); return null; } } this.range.add(s); return null; } }
/** * Returns <code>true</code> if the given strategy is contained within this instance, <code> * false</code> otherwise. * * @param s to search * @return true if strategy has been found, false otherwise */ public boolean contains(S s) { // if s is strict then search in strict: if (s.strict() && this.strict.containsKey(s.target())) { return true; } // else search in range: if (this.containsName(this.range, s.name())) { return true; } // search for it in backup, if any: if (this.backup != null) { if (this.containsName(this.backup, s.name())) { return true; } } return false; }
/** * Returns the strategy applicable for the given class or <code>null</code> if no such strategy * is found. A strategy that applies strictly to the given class is always preferable. If no * such strategy is available then the range strategies are checked for applicability. Backup * strategies, if applicable, are returned as a last resort. * * @param target to lookup strategy for * @return the applicable strategy or null */ public S lookup(Class target) { final S ss = this.strict.get(target); if (ss != null) { return ss; // found strict. } for (S rs : this.range) { if (rs.appliesTo(target)) { return rs; // found range. } } if (this.backup != null) { for (S bs : this.backup) { if (bs.appliesTo(target)) { return bs; // found backup. } } } return null; }
/** * Prioritizes the given <code>high</code> strategy over the given <code>low</code> strategy, * iff <code>high</code> has a lower priority than <code>low</code> else nothing is done. Both * <code>high</code> and <code>low</code> must be contained, <b>not</b> as backup strategies, by * this instance and must be non-{@linkplain Strategy#strict()}. * * @param high the non-strict strategy to ensure higher priority for * @param low the non-strict strategy to be shadowed by high * @throws IllegalArgumentException if high and/or low is strict or not contained as non-backup * by this instance */ public void prioritize(S high, S low) { // validate: this.validateForPrioritize(high); this.validateForPrioritize(low); // prioritize: final ListIterator<S> rangeItr = this.range.listIterator(); while (rangeItr.hasNext()) { S crt = rangeItr.next(); if (crt.equals(high)) { return; } if (crt.equals(low)) { final int lowIdx = rangeItr.nextIndex() - 1; while (rangeItr.hasNext()) { crt = rangeItr.next(); if (crt.equals(high)) { rangeItr.remove(); this.range.add(lowIdx, crt); return; } } } } }