/* * Licensed to Think Big Analytics, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Think Big Analytics, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2010 Think Big Analytics. All Rights Reserved. */ package tap.core; import java.util.*; import org.apache.avro.Schema; import org.apache.avro.generic.GenericData; import tap.Phase; import tap.core.io.BinaryKey; import com.google.protobuf.Message; public class ReflectionKeyExtractor<OUT> implements KeyExtractor<BinaryKey, OUT> { final Map<String,java.lang.reflect.Field> inFields = new HashMap<String,java.lang.reflect.Field>(); final Map<String,java.lang.reflect.Method> inGetters = new HashMap<String,java.lang.reflect.Method>(); private final List<String> fieldNames; private final Schema keySchema; public ReflectionKeyExtractor(Schema keySchema, List<String> fieldNames) { this.keySchema = keySchema; this.fieldNames = fieldNames; } public ReflectionKeyExtractor(Schema schema, String groupBy, String sortBy) { String[] groupFields = groupBy==null ? new String[0] : groupBy.split(","); String[] sortFields = sortBy==null ? new String[0] : sortBy.split(","); fieldNames = new ArrayList<String>(groupFields.length + sortFields.length); addFieldnames(fieldNames, groupFields); addFieldnames(fieldNames, sortFields); keySchema = Phase.groupAndSort(schema, groupBy, sortBy); // pass fields name *and* sort order } public static ReflectionKeyExtractor getReflectionKeyExtractorForReduceOutKey(Schema schema, String groupBy, String sortBy) { String[] groupFields = groupBy==null ? new String[0] : groupBy.split(","); String[] sortFields = sortBy==null ? new String[0] : sortBy.split(","); List<String> fieldNames = new ArrayList<String>(groupFields.length + sortFields.length); for (String name : groupFields) { String[] parts = name.trim().split("\\s", 2); // skip asc/desc if(schema.getField(parts[0]) == null) continue; if (fieldNames.contains(parts[0])) continue; fieldNames.add(parts[0]); } for (String name : sortFields) { String[] parts = name.trim().split("\\s", 2); // skip asc/desc if(schema.getField(parts[0]) == null) continue; if (fieldNames.contains(parts[0])) continue; fieldNames.add(parts[0]); } Schema keySchema = Phase.groupAndSortSubset(schema, groupBy, sortBy); // pass fields name *and* sort order return new ReflectionKeyExtractor(keySchema, fieldNames); } public static void addFieldnames(List<String> fieldNames, String[] groupFields) { for (String name : groupFields) { String[] parts = name.trim().split("\\s", 2); // skip asc/desc if (fieldNames.contains(parts[0])) continue; fieldNames.add(parts[0]); } } @Override public BinaryKey getProtypeKey() { BinaryKey key = new BinaryKey(); key.setSchema(keySchema); return key; } @Override public void setKey(OUT value, BinaryKey key) { //if you are setting key, set key.dirty...otherwise if it is a null key, dirty doesn't get set key.dirty(); if (inFields.isEmpty() && inGetters.isEmpty()) { Class<?> inClass = value.getClass(); try { for (String fieldName : fieldNames) { if(Message.class.isAssignableFrom(inClass)) { java.lang.reflect.Method getter = inClass.getMethod(getter(fieldName)); inGetters.put(fieldName, getter); } else { java.lang.reflect.Field field = inClass.getField(fieldName); field.setAccessible(true); inFields.put(fieldName, field); } } } catch (Exception e) { throw new RuntimeException(e); } } try { for (Map.Entry<String, java.lang.reflect.Field> entry : inFields.entrySet()) { String fieldName = entry.getKey(); key.setField(fieldName, entry.getValue().get(value)); } for (Map.Entry<String, java.lang.reflect.Method> entry : inGetters.entrySet()) { String fieldName = entry.getKey(); key.setField(fieldName, entry.getValue().invoke(value)); } } catch (Exception e) { throw new RuntimeException(e); } } private static String getter(String fieldName) { return "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); } }