Skip to content

Commit e6cde56

Browse files
committed
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.
2 parents 9cae8b3 + c73886f commit e6cde56

10 files changed

Lines changed: 885 additions & 147 deletions

File tree

restx-core/src/main/java/restx/RestxMainRouterFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import restx.factory.Name;
2323
import restx.factory.NamedComponent;
2424
import restx.factory.SingletonFactoryMachine;
25+
import restx.factory.StdWarehouse;
2526
import restx.factory.Warehouse;
2627
import restx.http.HttpStatus;
2728
import restx.security.RestxSessionCookieFilter;
@@ -409,7 +410,7 @@ private RestxMainRouter build(final String serverId, Optional<String> baseUri) {
409410
Thread.currentThread().setContextClassLoader(previous);
410411
}
411412

412-
Warehouse warehouse = getLoadFactoryMode().equals("cleanrequest") ? new Warehouse() : factory.getWarehouse();
413+
Warehouse warehouse = getLoadFactoryMode().equals("cleanrequest") ? new StdWarehouse() : factory.getWarehouse();
413414

414415
RestxMainRouter router = new PerRequestFactoryLoader(serverId, warehouse);
415416

restx-factory/src/main/java/restx/factory/Factory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,18 +307,18 @@ public Factory build() {
307307
*/
308308
Factory factory = new Factory(
309309
usedServiceLoader, machines, ImmutableList.<ComponentCustomizerEngine>of(),
310-
new Warehouse(ImmutableList.copyOf(providers)));
310+
new StdWarehouse(ImmutableList.copyOf(providers)));
311311

312312
Map<Name<FactoryMachine>, MachineEngine<FactoryMachine>> toBuild = new LinkedHashMap<>();
313313
ImmutableList<FactoryMachine> factoryMachines = buildFactoryMachines(factory, factory.machines, toBuild);
314314
while (!factoryMachines.isEmpty()) {
315315
machines.putAll("FactoryMachines", factoryMachines);
316316
factory = new Factory(usedServiceLoader, machines,
317-
ImmutableList.<ComponentCustomizerEngine>of(), new Warehouse());
317+
ImmutableList.<ComponentCustomizerEngine>of(), new StdWarehouse());
318318
factoryMachines = buildFactoryMachines(factory, factoryMachines, toBuild);
319319
}
320320
factory = new Factory(usedServiceLoader, machines,
321-
buildCustomizerEngines(factory), new Warehouse(ImmutableList.copyOf(providers)));
321+
buildCustomizerEngines(factory), new StdWarehouse(ImmutableList.copyOf(providers)));
322322
return factory;
323323
}
324324

@@ -760,7 +760,7 @@ public Factory concat(FactoryMachine machine) {
760760
machines.removeAll("WarehouseProvidersMachine");
761761
machines.put("IndividualMachines", machine);
762762
return new Factory(usedServiceLoader, machines, customizerEngines,
763-
new Warehouse(warehouse.getProviders()));
763+
new StdWarehouse(warehouse.getProviders()));
764764
}
765765

766766
public String getId() {
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package restx.factory;
2+
3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
6+
import com.google.common.base.Optional;
7+
import com.google.common.base.Predicate;
8+
import com.google.common.base.Predicates;
9+
import com.google.common.collect.ImmutableList;
10+
import com.google.common.collect.ImmutableSet;
11+
import com.google.common.collect.Iterables;
12+
13+
import java.util.Collections;
14+
15+
/**
16+
* Wrap a warehouse in order to filter components by classes or names.
17+
* <p>
18+
* When request are made using {@link #checkOut(Name)}, {@link #listNames()}
19+
* or {@link #listDependencies(Name)} for a filtered name or class, the wrapper
20+
* would respond like if the component was not present.
21+
*
22+
* @author apeyrard
23+
*/
24+
public class FilteredWarehouse implements Warehouse {
25+
26+
public static FilteredWarehouse excludingClasses(Warehouse original, Class<?>... classes) {
27+
return builder(original).excludingClasses(classes).build();
28+
}
29+
30+
public static FilteredWarehouse excludingClasses(Warehouse original, Iterable<Class<?>> classes) {
31+
return builder(original).excludingClasses(classes).build();
32+
}
33+
34+
35+
public static FilteredWarehouse excludingNames(Warehouse original, Name<?>... names) {
36+
return builder(original).excludingNames(names).build();
37+
}
38+
39+
public static FilteredWarehouse excludingNames(Warehouse original, Iterable<Name<?>> names) {
40+
return builder(original).excludingNames(names).build();
41+
}
42+
43+
@SafeVarargs
44+
public static FilteredWarehouse excluding(Warehouse original, Predicate<Name<?>>... filters) {
45+
return builder(original).excluding(filters).build();
46+
}
47+
48+
public static FilteredWarehouse excluding(Warehouse original, Iterable<Predicate<Name<?>>> filters) {
49+
return builder(original).excluding(filters).build();
50+
}
51+
52+
public static FilteredWarehouseBuilder builder(Warehouse original) {
53+
return new FilteredWarehouseBuilder(original);
54+
}
55+
56+
private final Predicate<Name<?>> filter;
57+
private final Warehouse original;
58+
59+
private FilteredWarehouse(Warehouse original, Predicate<Name<?>> filter) {
60+
this.original = checkNotNull(original);
61+
this.filter = checkNotNull(filter);
62+
}
63+
64+
@Override
65+
public String getId() {
66+
return original.getId();
67+
}
68+
69+
@Override
70+
public ImmutableList<Warehouse> getProviders() {
71+
return original.getProviders();
72+
}
73+
74+
@Override
75+
public <T> Optional<StoredBox<T>> getStoredBox(Name<T> name) {
76+
if (isFiltered(name)) {
77+
return Optional.absent();
78+
}
79+
return original.getStoredBox(name);
80+
}
81+
82+
@Override
83+
public <T> Optional<NamedComponent<T>> checkOut(Name<T> name) {
84+
if (isFiltered(name)) {
85+
return Optional.absent();
86+
}
87+
return original.checkOut(name);
88+
}
89+
90+
@Override
91+
public <T> void checkIn(ComponentBox<T> componentBox, SatisfiedBOM satisfiedBOM) {
92+
original.checkIn(componentBox, satisfiedBOM);
93+
}
94+
95+
@Override
96+
public Iterable<Name<?>> listNames() {
97+
return Iterables.filter(original.listNames(), new Predicate<Name<?>>() {
98+
@Override
99+
public boolean apply(Name<?> name) {
100+
return !isFiltered(name);
101+
}
102+
});
103+
}
104+
105+
@Override
106+
public Iterable<Name<?>> listDependencies(Name name) {
107+
if (isFiltered(name)) {
108+
return Collections.emptySet();
109+
}
110+
return original.listDependencies(name);
111+
}
112+
113+
@Override
114+
public void close() {
115+
original.close();
116+
}
117+
118+
/**
119+
* checks if the specified Name is filtered
120+
*/
121+
private boolean isFiltered(Name<?> name) {
122+
return filter.apply(name);
123+
}
124+
125+
/**
126+
* Builder to create a custom {@link FilteredWarehouse}
127+
*/
128+
public static class FilteredWarehouseBuilder {
129+
private final Warehouse original;
130+
private final ImmutableList.Builder<Predicate<Name<?>>> predicatesBuilder = ImmutableList.builder();
131+
132+
private FilteredWarehouseBuilder(Warehouse original) {
133+
this.original = original;
134+
}
135+
136+
public FilteredWarehouseBuilder excludingClasses(Class<?>... classes) {
137+
return excludingClasses(ImmutableSet.copyOf(classes));
138+
}
139+
140+
public FilteredWarehouseBuilder excludingClasses(Iterable<Class<?>> classes) {
141+
final ImmutableSet<Class<?>> classesSet = ImmutableSet.copyOf(classes);
142+
if (!classesSet.isEmpty()) {
143+
predicatesBuilder.add(new Predicate<Name<?>>() {
144+
@Override
145+
public boolean apply(Name<?> name) {
146+
return classesSet.contains(name.getClazz());
147+
}
148+
});
149+
}
150+
return this;
151+
}
152+
153+
public FilteredWarehouseBuilder excludingNames(Name<?>... names) {
154+
return excludingNames(ImmutableSet.copyOf(names));
155+
}
156+
157+
public FilteredWarehouseBuilder excludingNames(Iterable<Name<?>> names) {
158+
final ImmutableSet<Name<?>> namesSet = ImmutableSet.copyOf(names);
159+
if (!namesSet.isEmpty()) {
160+
predicatesBuilder.add(new Predicate<Name<?>>() {
161+
@Override
162+
public boolean apply(Name<?> name) {
163+
return namesSet.contains(name);
164+
}
165+
});
166+
}
167+
return this;
168+
}
169+
170+
@SafeVarargs
171+
public final FilteredWarehouseBuilder excluding(Predicate<Name<?>>... predicates) {
172+
predicatesBuilder.add(predicates);
173+
return this;
174+
}
175+
176+
public FilteredWarehouseBuilder excluding(Iterable<Predicate<Name<?>>> predicates) {
177+
predicatesBuilder.addAll(predicates);
178+
return this;
179+
}
180+
181+
public FilteredWarehouse build() {
182+
final ImmutableList<Predicate<Name<?>>> predicates = predicatesBuilder.build();
183+
184+
return new FilteredWarehouse(
185+
original,
186+
new Predicate<Name<?>>() {
187+
@Override
188+
public boolean apply(Name<?> name) {
189+
return Predicates.or(predicates).apply(name);
190+
}
191+
}
192+
);
193+
}
194+
}
195+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package restx.factory;
2+
3+
import com.google.common.base.Joiner;
4+
import com.google.common.base.Optional;
5+
import com.google.common.collect.ImmutableList;
6+
import com.google.common.collect.ImmutableSet;
7+
import com.google.common.collect.Iterables;
8+
import com.google.common.collect.Lists;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
12+
import java.util.Collection;
13+
import java.util.Collections;
14+
import java.util.LinkedHashSet;
15+
import java.util.Set;
16+
import java.util.concurrent.ConcurrentHashMap;
17+
import java.util.concurrent.ConcurrentMap;
18+
import java.util.concurrent.atomic.AtomicLong;
19+
20+
/**
21+
* User: xavierhanin
22+
* Date: 1/31/13
23+
* Time: 5:47 PM
24+
*/
25+
public class StdWarehouse implements Warehouse {
26+
private static final AtomicLong ID = new AtomicLong();
27+
28+
public StdWarehouse() {
29+
this(ImmutableList.<Warehouse>of());
30+
}
31+
32+
public StdWarehouse(ImmutableList<Warehouse> providers) {
33+
this.providers = providers;
34+
StringBuilder sb = new StringBuilder();
35+
for (Warehouse provider : providers) {
36+
sb.append("<<").append(provider.getId());
37+
}
38+
this.id = String.format("%03d%s", ID.incrementAndGet(), sb.toString());
39+
}
40+
41+
@Override
42+
public ImmutableList<Warehouse> getProviders() {
43+
return providers;
44+
}
45+
46+
private static final Logger logger = LoggerFactory.getLogger(StdWarehouse.class);
47+
48+
private final String id;
49+
private final ConcurrentMap<Name<?>, StoredBox<?>> boxes = new ConcurrentHashMap<>();
50+
private final ImmutableList<Warehouse> providers;
51+
52+
@Override
53+
public String getId() {
54+
return id;
55+
}
56+
57+
@Override
58+
@SuppressWarnings("unchecked")
59+
public <T> Optional<StoredBox<T>> getStoredBox(Name<T> name) {
60+
return Optional.fromNullable((StoredBox<T>) boxes.get(name));
61+
}
62+
63+
@Override
64+
@SuppressWarnings("unchecked")
65+
public <T> Optional<NamedComponent<T>> checkOut(Name<T> name) {
66+
StoredBox<T> storedBox = (StoredBox<T>) boxes.get(name);
67+
if (storedBox != null) {
68+
return storedBox.box.pick();
69+
}
70+
71+
for (Warehouse provider : providers) {
72+
Optional<NamedComponent<T>> component = provider.checkOut(name);
73+
if (component.isPresent()) {
74+
return component;
75+
}
76+
}
77+
78+
return Optional.absent();
79+
}
80+
81+
@Override
82+
public <T> void checkIn(ComponentBox<T> componentBox, SatisfiedBOM satisfiedBOM) {
83+
StoredBox<?> previousBox = boxes.put(componentBox.getName(), new StoredBox<>(componentBox, satisfiedBOM));
84+
if (previousBox != null) {
85+
try {
86+
previousBox.box.close();
87+
} catch (Exception e) {
88+
logger.warn("exception raised when closing box " + previousBox.box, e);
89+
}
90+
}
91+
}
92+
93+
@Override
94+
public void close() {
95+
Collection<Exception> exceptions = Lists.newArrayList();
96+
for (StoredBox<?> storedBox : boxes.values()) {
97+
try {
98+
storedBox.box.close();
99+
} catch (Exception e) {
100+
logger.warn("exception while closing " + storedBox.box, e);
101+
exceptions.add(e);
102+
}
103+
}
104+
boxes.clear();
105+
if (!exceptions.isEmpty()) {
106+
if (exceptions.size() == 1) {
107+
throw new IllegalStateException("exception raised while closing warehouse",
108+
exceptions.iterator().next());
109+
}
110+
throw new IllegalStateException("exceptions raised when closing warehouse."
111+
+ " Exceptions: " + Joiner.on(", ").join(exceptions));
112+
}
113+
}
114+
115+
116+
@Override
117+
public Iterable<Name<?>> listNames() {
118+
Set<Name<?>> names = new LinkedHashSet<>();
119+
names.addAll(boxes.keySet());
120+
for (Warehouse provider : providers) {
121+
Iterables.addAll(names, provider.listNames());
122+
}
123+
124+
return ImmutableSet.copyOf(names);
125+
}
126+
127+
@Override
128+
public Iterable<Name<?>> listDependencies(Name name) {
129+
StoredBox storedBox = boxes.get(name);
130+
if (storedBox != null) {
131+
Collection<Name<?>> deps = Lists.newArrayList();
132+
for (NamedComponent<? extends Object> namedComponent : storedBox.satisfiedBOM.getAllComponents()) {
133+
deps.add(namedComponent.getName());
134+
}
135+
return deps;
136+
} else {
137+
for (Warehouse provider : providers) {
138+
Iterable<Name<?>> deps = provider.listDependencies(name);
139+
if (!Iterables.isEmpty(deps)) {
140+
return deps;
141+
}
142+
}
143+
144+
return Collections.emptySet();
145+
}
146+
}
147+
148+
@Override
149+
public String toString() {
150+
return "Warehouse{" +
151+
"boxes=" + boxes +
152+
"; providers=" + providers +
153+
'}';
154+
}
155+
}

0 commit comments

Comments
 (0)