package tc.oc.api.model;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.inject.Inject;
import com.google.common.base.Splitter;
import com.google.common.reflect.TypeToken;
import tc.oc.api.docs.virtual.PartialModel;
import tc.oc.api.exceptions.SerializationException;
import tc.oc.commons.core.util.AmbiguousElementException;
import tc.oc.commons.core.util.TypeMap;
public class ModelRegistry {
private final TypeMap<PartialModel, ModelMeta> byType;
private final Map<String, ModelMeta> byName;
@Inject ModelRegistry(TypeMap<PartialModel, ModelMeta> byType, Map<String, ModelMeta> byName) {
this.byType = byType;
this.byName = byName;
}
public <T extends PartialModel> ModelMeta<?, ? super T> meta(Class<T> model) {
final TypeToken<T> tt = TypeToken.of(model);
return meta(tt);
}
public <T extends PartialModel> ModelMeta<?, ? super T> meta(TypeToken<T> model) {
try {
return byType.oneAssignableFrom(model);
} catch(NoSuchElementException e) {
throw new SerializationException(model.getRawType().getName() + " is not a registered model");
} catch(AmbiguousElementException e) {
throw new SerializationException(model.getRawType().getName() + " extends from multiple models");
}
}
public ModelMeta resolve(String query) {
return Splitter.on("::") // Extract embedded Ruby classes
.splitToList(query)
.stream()
.sorted(Comparator.reverseOrder()) // Give priority to descendants
.filter(byName::containsKey)
.map(byName::get)
.findFirst()
.orElseThrow(() -> new NoSuchModelException("No registered model named '" + query + "'"));
}
public Collection<ModelMeta> all() {
return byName.values();
}
}