/**
* Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.eventsourcing.index;
import com.eventsourcing.Entity;
import com.eventsourcing.EntityHandle;
import com.googlecode.cqengine.query.option.QueryOptions;
import lombok.Getter;
import lombok.SneakyThrows;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import com.googlecode.cqengine.index.Index;
import lombok.extern.slf4j.Slf4j;
import org.osgi.service.component.annotations.Component;
import static com.eventsourcing.index.IndexEngine.IndexFeature.EQ;
@Component
@Slf4j
public class JavaStaticFieldIndexLoader implements IndexLoader {
@SneakyThrows
@Override public Iterable<Index> load(IndexEngine engine, Class entityClass) {
List<com.googlecode.cqengine.index.Index> indices = new ArrayList<>();
Class<?>[] classes = new Class[]{entityClass};
if (entityClass.isAnnotationPresent(Indices.class)) {
classes = ((Indices)entityClass.getAnnotation(Indices.class)).value();
}
for (Class<?> klass : classes) {
for (Field field : klass.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) &&
EntityIndex.class.isAssignableFrom(field.getType())) {
com.eventsourcing.index.Index annotation = field
.getAnnotation(com.eventsourcing.index.Index.class);
IndexEngine.IndexFeature[] features = annotation == null ? new IndexEngine.IndexFeature[]{EQ} : annotation.value();
EntityIndex index = ((EntityIndex) field.get(null));
ParameterizedType type = (ParameterizedType) field.getGenericType();
Class<Entity> objectType = (Class<Entity>) type.getActualTypeArguments()[0];
Type attributeType = type.getActualTypeArguments()[1];
Class<EntityHandle<Entity>> entityType = (Class<EntityHandle<Entity>>) field.getType()
.getInterfaces()[0];
Attribute attribute;
if (SimpleIndex.class.isAssignableFrom(field.getType())) {
attribute = new EntitySimpleAttribute(objectType, entityType, attributeType, field, index);
if (index instanceof IndexWithAttribute) {
((IndexWithAttribute) index).setAttribute(attribute);
} else {
log.warn("Non-final index definitions are deprecated, use SimpleIndex.as() instead");
WrappedSimpleIndex wrappedIndex = new WrappedSimpleIndex<>((BiFunction<Entity, QueryOptions, Object>) ((SimpleIndex) index)::getValue);
wrappedIndex.setAttribute(attribute);
field.set(null, wrappedIndex);
}
} else {
attribute = new MultiValueEntityAttribute(objectType, entityType, attributeType, field, index);
if (index instanceof IndexWithAttribute) {
((IndexWithAttribute) index).setAttribute(attribute);
} else {
log.warn("Non-final index definitions are deprecated, use MultiValueIndex.as() instead");
WrappedMultiValueIndex wrappedIndex = new WrappedMultiValueIndex(((BiFunction<Entity,
QueryOptions, Object>) ((MultiValueIndex) index)::getValues));
wrappedIndex.setAttribute(attribute);
field.set(null, wrappedIndex);
}
}
indices.add(engine.getIndexOnAttribute(attribute, features));
}
}
}
return indices;
}
class EntitySimpleAttribute extends SimpleAttribute<Entity, Object> {
@Getter
private final Type attributeReflectedType;
private final EntityIndex index;
public EntitySimpleAttribute(Class<Entity> objectType, Class<EntityHandle<Entity>> entityType,
Type attributeType,
Field field, EntityIndex index) {
super(objectType, entityType,
(Class<Object>) (attributeType instanceof ParameterizedType ? ((ParameterizedType) attributeType)
.getRawType(): attributeType),
field.getName());
this.attributeReflectedType = attributeType;
this.index = index;
}
@Override public Object getValue(Entity object, QueryOptions queryOptions) {
return ((SimpleIndex) index).getValue(object, queryOptions);
}
}
class MultiValueEntityAttribute extends MultiValueAttribute<Entity, Object> {
@Getter
private final Type attributeReflectedType;
private final EntityIndex index;
public MultiValueEntityAttribute(Class<Entity> objectType, Class<EntityHandle<Entity>> entityType,
Type attributeType,
Field field, EntityIndex index) {
super(objectType, entityType, (Class<Object>) (attributeType instanceof ParameterizedType ? ((ParameterizedType) attributeType)
.getRawType(): attributeType), field.getName());
this.attributeReflectedType = attributeType;
this.index = index;
}
@Override public Iterable<Object> getValues(Entity object, QueryOptions queryOptions) {
return index.getValues(object, queryOptions);
}
}
}