package restx.factory; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import java.util.Collections; /** * Wrap a warehouse in order to filter components by classes or names. * <p> * When request are made using {@link #checkOut(Name)}, {@link #listNames()} * or {@link #listDependencies(Name)} for a filtered name or class, the wrapper * would respond like if the component was not present. * * @author apeyrard */ public class FilteredWarehouse implements Warehouse { public static FilteredWarehouse excludingClasses(Warehouse original, Class<?>... classes) { return builder(original).excludingClasses(classes).build(); } public static FilteredWarehouse excludingClasses(Warehouse original, Iterable<Class<?>> classes) { return builder(original).excludingClasses(classes).build(); } public static FilteredWarehouse excludingNames(Warehouse original, Name<?>... names) { return builder(original).excludingNames(names).build(); } public static FilteredWarehouse excludingNames(Warehouse original, Iterable<Name<?>> names) { return builder(original).excludingNames(names).build(); } @SafeVarargs public static FilteredWarehouse excluding(Warehouse original, Predicate<Name<?>>... filters) { return builder(original).excluding(filters).build(); } public static FilteredWarehouse excluding(Warehouse original, Iterable<Predicate<Name<?>>> filters) { return builder(original).excluding(filters).build(); } public static FilteredWarehouseBuilder builder(Warehouse original) { return new FilteredWarehouseBuilder(original); } private final Predicate<Name<?>> filter; private final Warehouse original; private FilteredWarehouse(Warehouse original, Predicate<Name<?>> filter) { this.original = checkNotNull(original); this.filter = checkNotNull(filter); } @Override public String getId() { return original.getId(); } @Override public ImmutableList<Warehouse> getProviders() { return original.getProviders(); } @Override public <T> Optional<StoredBox<T>> getStoredBox(Name<T> name) { if (isFiltered(name)) { return Optional.absent(); } return original.getStoredBox(name); } @Override public <T> Optional<NamedComponent<T>> checkOut(Name<T> name) { if (isFiltered(name)) { return Optional.absent(); } return original.checkOut(name); } @Override public <T> void checkIn(ComponentBox<T> componentBox, SatisfiedBOM satisfiedBOM) { original.checkIn(componentBox, satisfiedBOM); } @Override public Iterable<Name<?>> listNames() { return Iterables.filter(original.listNames(), new Predicate<Name<?>>() { @Override public boolean apply(Name<?> name) { return !isFiltered(name); } }); } @Override public Iterable<Name<?>> listDependencies(Name name) { if (isFiltered(name)) { return Collections.emptySet(); } return original.listDependencies(name); } @Override public void close() { original.close(); } /** * checks if the specified Name is filtered */ private boolean isFiltered(Name<?> name) { return filter.apply(name); } /** * Builder to create a custom {@link FilteredWarehouse} */ public static class FilteredWarehouseBuilder { private final Warehouse original; private final ImmutableList.Builder<Predicate<Name<?>>> predicatesBuilder = ImmutableList.builder(); private FilteredWarehouseBuilder(Warehouse original) { this.original = original; } public FilteredWarehouseBuilder excludingClasses(Class<?>... classes) { return excludingClasses(ImmutableSet.copyOf(classes)); } public FilteredWarehouseBuilder excludingClasses(Iterable<Class<?>> classes) { final ImmutableSet<Class<?>> classesSet = ImmutableSet.copyOf(classes); if (!classesSet.isEmpty()) { predicatesBuilder.add(new Predicate<Name<?>>() { @Override public boolean apply(Name<?> name) { return classesSet.contains(name.getClazz()); } }); } return this; } public FilteredWarehouseBuilder excludingNames(Name<?>... names) { return excludingNames(ImmutableSet.copyOf(names)); } public FilteredWarehouseBuilder excludingNames(Iterable<Name<?>> names) { final ImmutableSet<Name<?>> namesSet = ImmutableSet.copyOf(names); if (!namesSet.isEmpty()) { predicatesBuilder.add(new Predicate<Name<?>>() { @Override public boolean apply(Name<?> name) { return namesSet.contains(name); } }); } return this; } @SafeVarargs public final FilteredWarehouseBuilder excluding(Predicate<Name<?>>... predicates) { predicatesBuilder.add(predicates); return this; } public FilteredWarehouseBuilder excluding(Iterable<Predicate<Name<?>>> predicates) { predicatesBuilder.addAll(predicates); return this; } public FilteredWarehouse build() { final ImmutableList<Predicate<Name<?>>> predicates = predicatesBuilder.build(); return new FilteredWarehouse( original, new Predicate<Name<?>>() { @Override public boolean apply(Name<?> name) { return Predicates.or(predicates).apply(name); } } ); } } }