Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one or more
0003  * contributor license agreements.  See the NOTICE file distributed with
0004  * this work for additional information regarding copyright ownership.
0005  * The ASF licenses this file to You under the Apache License, Version 2.0
0006  * (the "License"); you may not use this file except in compliance with
0007  * the License.  You may obtain a copy of the License at
0008  *
0009  *    http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
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  * Wrapper around types managed in a KVStore, providing easy access to their indexed fields.
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    * Abstracts the difference between invoking a Field and a Method.
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 }