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 +
'}';
}
}