package org.eclipse.jst.jsf.common.internal.strategy; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jst.jsf.common.internal.strategy.StrategyComposite.AbstractCompositionStrategy; import org.eclipse.jst.jsf.common.internal.strategy.StrategyComposite.CompositionArguments; /** * A composition strategy that merges the result of all composed strategies. The * merge policy is left to concrete implementations. Three concrete impls are * provided: one that uses compose all (List) and one that uses compose unique * (Set) and a third that uses Map. * * @author cbateman * * @param <INPUT> * @param <MERGETYPE> * @param <STRATEGY> */ /** * @author cbateman * * @param <INPUT> * @param <OUTPUT> * @param <MERGETYPE> * @param <STRATEGY> */ public abstract class MergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE, STRATEGY extends ISimpleStrategy<INPUT, OUTPUT>> extends AbstractCompositionStrategy<INPUT, OUTPUT, MERGETYPE, STRATEGY> { /** * The result of the merge. */ protected final MERGETYPE _composedResult; /** * @param composedResult * @param noResultValue */ public MergingCompositionStrategy(final MERGETYPE composedResult, final MERGETYPE noResultValue) { super(); _composedResult = composedResult; } @Override public boolean compose(final CompositionArguments<INPUT, OUTPUT, STRATEGY> args) throws Exception { final OUTPUT result = args.getStrategy().perform(args.getInput()); if (result != args.getStrategy().getNoResult()) { doCompose(result); } // never stop composing early return false; } /** * Sub-classes must implement to do the detail composition for their result * type. * * @param result */ protected abstract void doCompose(OUTPUT result); @Override public MERGETYPE getComposedResult() { return _composedResult; } @Override public abstract void reset(); /** * An implementation that uses a List to implement the list policy. The * result is to add all results from all composed strategies to a single * list. Duplicates may occur. * * @param <INPUT> * @param <OUTPUT> * @param <MERGETYPE> * @param <STRATEGY> * ` */ public static class ListMergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE extends List, STRATEGY extends ISimpleStrategy<INPUT, OUTPUT>> extends MergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE, STRATEGY> { /** * @param composedResult * @param noResultValue */ public ListMergingCompositionStrategy(final MERGETYPE composedResult, final MERGETYPE noResultValue) { super(composedResult, noResultValue); } @Override protected void doCompose(final OUTPUT result) { if (result instanceof Collection) { _composedResult.addAll((Collection) result); } else { _composedResult.add(result); } } @Override public void reset() { _composedResult.clear(); } } /** * An implementation that uses a List to implement the list policy. The * result is to add all results from all composed strategies to a single * list. Duplicates will not occur. * * @param <INPUT> * @param <OUTPUT> * @param <MERGETYPE> * @param <STRATEGY> */ public static class SetMergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE extends Set, STRATEGY extends ISimpleStrategy<INPUT, OUTPUT>> extends MergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE, STRATEGY> { /** * @param composedResult * @param noResultValue */ public SetMergingCompositionStrategy(final MERGETYPE composedResult, final MERGETYPE noResultValue) { super(composedResult, noResultValue); } @Override protected void doCompose(final OUTPUT result) { if (result instanceof Collection) { _composedResult.addAll((Collection) result); } else { _composedResult.add(result); } } @Override public void reset() { _composedResult.clear(); } } /** * @author cbateman * * @param <INPUT> * @param <OUTPUT> * @param <MERGETYPE> * @param <STRATEGY> */ public abstract static class MapMergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE extends Map, STRATEGY extends ISimpleStrategy<INPUT, OUTPUT>> extends MergingCompositionStrategy<INPUT, OUTPUT, MERGETYPE, STRATEGY> { /** * @param composedResult * @param noResultValue */ public MapMergingCompositionStrategy(final MERGETYPE composedResult, final MERGETYPE noResultValue) { super(composedResult, noResultValue); } @Override protected void doCompose(final OUTPUT result) { if (result instanceof Map) { _composedResult.putAll((Map) result); } else { _composedResult.put(calculateKey(result), result); } } /** * @param result * @return the key to be used for result in any composed map. */ protected abstract Object calculateKey(final OUTPUT result); @Override public void reset() { _composedResult.clear(); } } }