Permalink
Browse files

Merge pull request #140 from a-peyrard/filtering-warehouse

Makes Warehouse wrappable and implements a FilteredWarehouse wrapper [breaking]

breaking: Warehouse is now an interface and Warehouse class has been renamed into StdWarehouse.

If you were using Warehouse constructor directly you probably just need to change
 your constructor call from Warehouse to StdWarehouse.
  • Loading branch information...
xhanin committed Jan 7, 2015
2 parents 9cae8b3 + c73886f commit e6cde563bf7c4b6b9847860f34201d6b14a2dde0
@@ -22,6 +22,7 @@
import restx.factory.Name;
import restx.factory.NamedComponent;
import restx.factory.SingletonFactoryMachine;
+import restx.factory.StdWarehouse;
import restx.factory.Warehouse;
import restx.http.HttpStatus;
import restx.security.RestxSessionCookieFilter;
@@ -409,7 +410,7 @@ private RestxMainRouter build(final String serverId, Optional<String> baseUri) {
Thread.currentThread().setContextClassLoader(previous);
}
- Warehouse warehouse = getLoadFactoryMode().equals("cleanrequest") ? new Warehouse() : factory.getWarehouse();
+ Warehouse warehouse = getLoadFactoryMode().equals("cleanrequest") ? new StdWarehouse() : factory.getWarehouse();
RestxMainRouter router = new PerRequestFactoryLoader(serverId, warehouse);
@@ -307,18 +307,18 @@ public Factory build() {
*/
Factory factory = new Factory(
usedServiceLoader, machines, ImmutableList.<ComponentCustomizerEngine>of(),
- new Warehouse(ImmutableList.copyOf(providers)));
+ new StdWarehouse(ImmutableList.copyOf(providers)));
Map<Name<FactoryMachine>, MachineEngine<FactoryMachine>> toBuild = new LinkedHashMap<>();
ImmutableList<FactoryMachine> factoryMachines = buildFactoryMachines(factory, factory.machines, toBuild);
while (!factoryMachines.isEmpty()) {
machines.putAll("FactoryMachines", factoryMachines);
factory = new Factory(usedServiceLoader, machines,
- ImmutableList.<ComponentCustomizerEngine>of(), new Warehouse());
+ ImmutableList.<ComponentCustomizerEngine>of(), new StdWarehouse());
factoryMachines = buildFactoryMachines(factory, factoryMachines, toBuild);
}
factory = new Factory(usedServiceLoader, machines,
- buildCustomizerEngines(factory), new Warehouse(ImmutableList.copyOf(providers)));
+ buildCustomizerEngines(factory), new StdWarehouse(ImmutableList.copyOf(providers)));
return factory;
}
@@ -760,7 +760,7 @@ public Factory concat(FactoryMachine machine) {
machines.removeAll("WarehouseProvidersMachine");
machines.put("IndividualMachines", machine);
return new Factory(usedServiceLoader, machines, customizerEngines,
- new Warehouse(warehouse.getProviders()));
+ new StdWarehouse(warehouse.getProviders()));
}
public String getId() {
@@ -0,0 +1,195 @@
+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);
+ }
+ }
+ );
+ }
+ }
+}
@@ -0,0 +1,155 @@
+package restx.factory;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * User: xavierhanin
+ * Date: 1/31/13
+ * Time: 5:47 PM
+ */
+public class StdWarehouse implements Warehouse {
+ private static final AtomicLong ID = new AtomicLong();
+
+ public StdWarehouse() {
+ this(ImmutableList.<Warehouse>of());
+ }
+
+ public StdWarehouse(ImmutableList<Warehouse> providers) {
+ this.providers = providers;
+ StringBuilder sb = new StringBuilder();
+ for (Warehouse provider : providers) {
+ sb.append("<<").append(provider.getId());
+ }
+ this.id = String.format("%03d%s", ID.incrementAndGet(), sb.toString());
+ }
+
+ @Override
+ public ImmutableList<Warehouse> getProviders() {
+ return providers;
+ }
+
+ private static final Logger logger = LoggerFactory.getLogger(StdWarehouse.class);
+
+ private final String id;
+ private final ConcurrentMap<Name<?>, StoredBox<?>> boxes = new ConcurrentHashMap<>();
+ private final ImmutableList<Warehouse> providers;
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> Optional<StoredBox<T>> getStoredBox(Name<T> name) {
+ return Optional.fromNullable((StoredBox<T>) boxes.get(name));
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> Optional<NamedComponent<T>> checkOut(Name<T> name) {
+ StoredBox<T> storedBox = (StoredBox<T>) boxes.get(name);
+ if (storedBox != null) {
+ return storedBox.box.pick();
+ }
+
+ for (Warehouse provider : providers) {
+ Optional<NamedComponent<T>> component = provider.checkOut(name);
+ if (component.isPresent()) {
+ return component;
+ }
+ }
+
+ return Optional.absent();
+ }
+
+ @Override
+ public <T> void checkIn(ComponentBox<T> componentBox, SatisfiedBOM satisfiedBOM) {
+ StoredBox<?> previousBox = boxes.put(componentBox.getName(), new StoredBox<>(componentBox, satisfiedBOM));
+ if (previousBox != null) {
+ try {
+ previousBox.box.close();
+ } catch (Exception e) {
+ logger.warn("exception raised when closing box " + previousBox.box, e);
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ Collection<Exception> exceptions = Lists.newArrayList();
+ for (StoredBox<?> storedBox : boxes.values()) {
+ try {
+ storedBox.box.close();
+ } catch (Exception e) {
+ logger.warn("exception while closing " + storedBox.box, e);
+ exceptions.add(e);
+ }
+ }
+ boxes.clear();
+ if (!exceptions.isEmpty()) {
+ if (exceptions.size() == 1) {
+ throw new IllegalStateException("exception raised while closing warehouse",
+ exceptions.iterator().next());
+ }
+ throw new IllegalStateException("exceptions raised when closing warehouse."
+ + " Exceptions: " + Joiner.on(", ").join(exceptions));
+ }
+ }
+
+
+ @Override
+ public Iterable<Name<?>> listNames() {
+ Set<Name<?>> names = new LinkedHashSet<>();
+ names.addAll(boxes.keySet());
+ for (Warehouse provider : providers) {
+ Iterables.addAll(names, provider.listNames());
+ }
+
+ return ImmutableSet.copyOf(names);
+ }
+
+ @Override
+ public Iterable<Name<?>> listDependencies(Name name) {
+ StoredBox storedBox = boxes.get(name);
+ if (storedBox != null) {
+ Collection<Name<?>> deps = Lists.newArrayList();
+ for (NamedComponent<? extends Object> namedComponent : storedBox.satisfiedBOM.getAllComponents()) {
+ deps.add(namedComponent.getName());
+ }
+ return deps;
+ } else {
+ for (Warehouse provider : providers) {
+ Iterable<Name<?>> deps = provider.listDependencies(name);
+ if (!Iterables.isEmpty(deps)) {
+ return deps;
+ }
+ }
+
+ return Collections.emptySet();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Warehouse{" +
+ "boxes=" + boxes +
+ "; providers=" + providers +
+ '}';
+ }
+}
Oops, something went wrong.

0 comments on commit e6cde56

Please sign in to comment.