cereal.impl.ThriftStructMapping.java Source code

Java tutorial

Introduction

Here is the source code for cereal.impl.ThriftStructMapping.java

Source

/*
 * Copyright 2015 Josh Elser
 *
 * Licensed 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.
 */
package cereal.impl;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.nio.charset.StandardCharsets.UTF_8;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.hadoop.io.Text;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.meta_data.FieldMetaData;
import org.apache.thrift.meta_data.FieldValueMetaData;
import org.apache.thrift.protocol.TType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cereal.Field;
import cereal.InstanceOrBuilder;
import cereal.InstanceOrBuilder.Type;
import cereal.Mapping;

/**
 * A default {@link Mapping} implementation for Thrift structs.
 */
public abstract class ThriftStructMapping<E extends TBase<? extends TBase<?, ?>, ? extends TFieldIdEnum>>
        implements Mapping<E> {
    private static final Logger log = LoggerFactory.getLogger(ThriftStructMapping.class);

    private volatile Method getFieldValue, isSet, setFieldValue;

    @Override
    public List<Field> getFields(E obj) {
        checkNotNull(obj, "The struct was null");

        List<Field> fields;
        try {
            @SuppressWarnings("rawtypes")
            Class<? extends TBase> tbaseClz = obj.getClass();
            if (null == getFieldValue) {
                synchronized (this) {
                    if (null == getFieldValue) {
                        Class<?> fieldsClz = Class.forName(obj.getClass().getName() + "$_Fields");
                        getFieldValue = tbaseClz.getMethod("getFieldValue", fieldsClz);
                        isSet = tbaseClz.getMethod("isSet", fieldsClz);
                    }
                }
            }

            Map<? extends TFieldIdEnum, FieldMetaData> thriftFields = FieldMetaData.getStructMetaDataMap(tbaseClz);
            fields = new ArrayList<>();

            for (Entry<? extends TFieldIdEnum, FieldMetaData> entry : thriftFields.entrySet()) {
                TFieldIdEnum field = entry.getKey();
                FieldMetaData fMetaData = entry.getValue();
                if ((boolean) isSet.invoke(obj, field)) {
                    Object value = getFieldValue.invoke(obj, field);
                    FieldValueMetaData fvMetaData = fMetaData.valueMetaData;
                    switch (fvMetaData.type) {
                    case TType.BOOL:
                        Boolean booleanVal = (Boolean) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(booleanVal.toString())));
                        break;
                    case TType.BYTE:
                        Byte byteVal = (Byte) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(byteVal.toString())));
                        break;
                    case TType.DOUBLE:
                        Double dblVal = (Double) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(dblVal.toString())));
                        break;
                    case TType.I16:
                        Short shortVal = (Short) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(shortVal.toString())));
                        break;
                    case TType.I32:
                        Integer intVal = (Integer) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(intVal.toString())));
                        break;
                    case TType.I64:
                        Long longVal = (Long) value;
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), value(longVal.toString())));
                        break;
                    case TType.STRING:
                        byte[] bytes;
                        if (fvMetaData.isBinary()) {
                            bytes = (byte[]) value;
                        } else {
                            String strVal = (String) value;
                            bytes = strVal.getBytes(UTF_8);
                        }
                        fields.add(new FieldImpl(text(fMetaData.fieldName), getGrouping(fMetaData),
                                getVisibility(fMetaData), new Value(bytes)));
                        break;
                    default:
                        log.warn("Ignoring field: {}", field.getFieldName());
                        break;
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return fields;
    }

    /**
     * The grouping for a field.
     *
     * @param field
     *          The protocol buffer field
     * @return The grouping for the field
     */
    public abstract Text getGrouping(FieldMetaData field);

    /**
     * The visibility for a field.
     *
     * @param field
     *          The protocol buffer field.
     * @return The visibility for the field
     */
    public abstract ColumnVisibility getVisibility(FieldMetaData field);

    private Text text(String str) {
        return new Text(str);
    }

    private Value value(String str) {
        return new Value(str.getBytes(UTF_8));
    }

    @Override
    public void update(Iterable<Entry<Key, Value>> iter, InstanceOrBuilder<E> instOrBuilder) {
        checkNotNull(iter, "Iterator is null");
        checkNotNull(instOrBuilder, "InstOrBuilder is null");
        checkArgument(Type.INSTANCE == instOrBuilder.getType(), "Expected INSTANCE in InstanceOrBuilder");

        try {
            @SuppressWarnings("rawtypes")
            Class<? extends TBase> tbaseClz = instOrBuilder.getWrappedClass();
            if (null == setFieldValue) {
                synchronized (this) {
                    if (null == setFieldValue) {
                        Class<?> fieldsClz = Class.forName(instOrBuilder.getWrappedClass().getName() + "$_Fields");
                        setFieldValue = tbaseClz.getMethod("setFieldValue", fieldsClz, Object.class);
                    }
                }
            }

            for (Entry<Key, Value> entry : iter) {
                String fieldName = entry.getKey().getColumnQualifier().toString();
                Map<? extends TFieldIdEnum, FieldMetaData> thriftFields = FieldMetaData
                        .getStructMetaDataMap(tbaseClz);
                for (Entry<? extends TFieldIdEnum, FieldMetaData> fieldEntry : thriftFields.entrySet()) {
                    TFieldIdEnum fieldId = fieldEntry.getKey();
                    if (fieldName.equals(fieldId.getFieldName())) {
                        FieldValueMetaData fvMetaData = fieldEntry.getValue().valueMetaData;
                        Value v = entry.getValue();
                        Object obj = instOrBuilder.get();
                        switch (fvMetaData.type) {
                        case TType.BOOL:
                            Boolean booleanVal = Boolean.parseBoolean(v.toString());
                            setFieldValue.invoke(obj, fieldId, booleanVal);
                            break;
                        case TType.BYTE:
                            Byte byteVal = Byte.parseByte(v.toString());
                            setFieldValue.invoke(obj, fieldId, byteVal);
                            break;
                        case TType.DOUBLE:
                            Double dblVal = Double.parseDouble(v.toString());
                            setFieldValue.invoke(obj, fieldId, dblVal);
                            break;
                        case TType.I16:
                            Short shortVal = Short.parseShort(v.toString());
                            setFieldValue.invoke(obj, fieldId, shortVal);
                            break;
                        case TType.I32:
                            Integer intVal = Integer.parseInt(v.toString());
                            setFieldValue.invoke(obj, fieldId, intVal);
                            break;
                        case TType.I64:
                            Long longVal = Long.parseLong(v.toString());
                            setFieldValue.invoke(obj, fieldId, longVal);
                            break;
                        case TType.STRING:
                            if (fvMetaData.isBinary()) {
                                setFieldValue.invoke(obj, fieldId, ByteBuffer.wrap(v.get()));
                            } else {
                                String strVal = v.toString();
                                setFieldValue.invoke(obj, fieldId, strVal);
                            }
                            break;
                        default:
                            log.warn("Ignoring field: {}", fieldName);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}