0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 package org.apache.spark.util.kvstore;
0019
0020 import java.lang.reflect.Field;
0021 import java.lang.reflect.Method;
0022 import java.util.HashMap;
0023 import java.util.Map;
0024 import java.util.stream.Stream;
0025
0026 import com.google.common.base.Preconditions;
0027
0028 import org.apache.spark.annotation.Private;
0029
0030
0031
0032
0033 @Private
0034 public class KVTypeInfo {
0035
0036 private final Class<?> type;
0037 private final Map<String, KVIndex> indices;
0038 private final Map<String, Accessor> accessors;
0039
0040 public KVTypeInfo(Class<?> type) {
0041 this.type = type;
0042 this.accessors = new HashMap<>();
0043 this.indices = new HashMap<>();
0044
0045 for (Field f : type.getDeclaredFields()) {
0046 KVIndex idx = f.getAnnotation(KVIndex.class);
0047 if (idx != null) {
0048 checkIndex(idx, indices);
0049 f.setAccessible(true);
0050 indices.put(idx.value(), idx);
0051 f.setAccessible(true);
0052 accessors.put(idx.value(), new FieldAccessor(f));
0053 }
0054 }
0055
0056 for (Method m : type.getDeclaredMethods()) {
0057 KVIndex idx = m.getAnnotation(KVIndex.class);
0058 if (idx != null) {
0059 checkIndex(idx, indices);
0060 Preconditions.checkArgument(m.getParameterTypes().length == 0,
0061 "Annotated method %s::%s should not have any parameters.", type.getName(), m.getName());
0062 m.setAccessible(true);
0063 indices.put(idx.value(), idx);
0064 m.setAccessible(true);
0065 accessors.put(idx.value(), new MethodAccessor(m));
0066 }
0067 }
0068
0069 Preconditions.checkArgument(indices.containsKey(KVIndex.NATURAL_INDEX_NAME),
0070 "No natural index defined for type %s.", type.getName());
0071
0072 for (KVIndex idx : indices.values()) {
0073 if (!idx.parent().isEmpty()) {
0074 KVIndex parent = indices.get(idx.parent());
0075 Preconditions.checkArgument(parent != null,
0076 "Cannot find parent %s of index %s.", idx.parent(), idx.value());
0077 Preconditions.checkArgument(parent.parent().isEmpty(),
0078 "Parent index %s of index %s cannot be itself a child index.", idx.parent(), idx.value());
0079 }
0080 }
0081 }
0082
0083 private void checkIndex(KVIndex idx, Map<String, KVIndex> indices) {
0084 Preconditions.checkArgument(idx.value() != null && !idx.value().isEmpty(),
0085 "No name provided for index in type %s.", type.getName());
0086 Preconditions.checkArgument(
0087 !idx.value().startsWith("_") || idx.value().equals(KVIndex.NATURAL_INDEX_NAME),
0088 "Index name %s (in type %s) is not allowed.", idx.value(), type.getName());
0089 Preconditions.checkArgument(idx.parent().isEmpty() || !idx.parent().equals(idx.value()),
0090 "Index %s cannot be parent of itself.", idx.value());
0091 Preconditions.checkArgument(!indices.containsKey(idx.value()),
0092 "Duplicate index %s for type %s.", idx.value(), type.getName());
0093 }
0094
0095 public Class<?> type() {
0096 return type;
0097 }
0098
0099 public Object getIndexValue(String indexName, Object instance) throws Exception {
0100 return getAccessor(indexName).get(instance);
0101 }
0102
0103 public Stream<KVIndex> indices() {
0104 return indices.values().stream();
0105 }
0106
0107 Accessor getAccessor(String indexName) {
0108 Accessor a = accessors.get(indexName);
0109 Preconditions.checkArgument(a != null, "No index %s.", indexName);
0110 return a;
0111 }
0112
0113 Accessor getParentAccessor(String indexName) {
0114 KVIndex index = indices.get(indexName);
0115 return index.parent().isEmpty() ? null : getAccessor(index.parent());
0116 }
0117
0118 String getParentIndexName(String indexName) {
0119 KVIndex index = indices.get(indexName);
0120 return index.parent();
0121 }
0122
0123
0124
0125
0126 interface Accessor {
0127
0128 Object get(Object instance) throws ReflectiveOperationException;
0129
0130 Class<?> getType();
0131 }
0132
0133 private class FieldAccessor implements Accessor {
0134
0135 private final Field field;
0136
0137 FieldAccessor(Field field) {
0138 this.field = field;
0139 }
0140
0141 @Override
0142 public Object get(Object instance) throws ReflectiveOperationException {
0143 return field.get(instance);
0144 }
0145
0146 @Override
0147 public Class<?> getType() {
0148 return field.getType();
0149 }
0150 }
0151
0152 private class MethodAccessor implements Accessor {
0153
0154 private final Method method;
0155
0156 MethodAccessor(Method method) {
0157 this.method = method;
0158 }
0159
0160 @Override
0161 public Object get(Object instance) throws ReflectiveOperationException {
0162 return method.invoke(instance);
0163 }
0164
0165 @Override
0166 public Class<?> getType() {
0167 return method.getReturnType();
0168 }
0169 }
0170
0171 }