Package mil.nga.giat.geowave.store.adapter

Source Code of mil.nga.giat.geowave.store.adapter.AbstractDataAdapter

package mil.nga.giat.geowave.store.adapter;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import mil.nga.giat.geowave.index.ByteArrayId;
import mil.nga.giat.geowave.index.Persistable;
import mil.nga.giat.geowave.index.PersistenceUtils;
import mil.nga.giat.geowave.index.StringUtils;
import mil.nga.giat.geowave.store.adapter.NativeFieldHandler.RowBuilder;
import mil.nga.giat.geowave.store.data.PersistentDataset;
import mil.nga.giat.geowave.store.data.PersistentValue;
import mil.nga.giat.geowave.store.data.field.FieldUtils;
import mil.nga.giat.geowave.store.data.field.FieldVisibilityHandler;
import mil.nga.giat.geowave.store.dimension.DimensionField;
import mil.nga.giat.geowave.store.filter.GenericTypeResolver;
import mil.nga.giat.geowave.store.index.CommonIndexModel;
import mil.nga.giat.geowave.store.index.CommonIndexValue;
import mil.nga.giat.geowave.store.index.Index;

import org.apache.log4j.Logger;

/**
* This class generically supports most of the operations necessary to implement
* a Data Adapter and can be easily extended to support specific data types.
* Many of the details are handled by mapping IndexFieldHandler's based on
* either types or exact dimensions. These handler mappings can be supplied in
* the constructor. The dimension matching handlers are used first when trying
* to decode a persistence encoded value. This can be done specifically to match
* a field (for example if there are multiple ways of encoding/decoding the same
* type). Otherwise the type matching handlers will simply match any field with
* the same type as its generic field type.
*
* @param <T>
*            The type for the entries handled by this adapter
*/
abstract public class AbstractDataAdapter<T> implements
    WritableDataAdapter<T>
{
  private final static Logger LOGGER = Logger.getLogger(AbstractDataAdapter.class);
  protected Map<Class<?>, IndexFieldHandler<T, ? extends CommonIndexValue, Object>> typeMatchingFieldHandlers;
  protected Map<ByteArrayId, IndexFieldHandler<T, ? extends CommonIndexValue, Object>> dimensionMatchingFieldHandlers;
  protected List<NativeFieldHandler<T, Object>> nativeFieldHandlers;
  protected FieldVisibilityHandler<T, Object> fieldVisiblityHandler;

  protected AbstractDataAdapter() {}

  public AbstractDataAdapter(
      final List<PersistentIndexFieldHandler<T, ? extends CommonIndexValue, Object>> indexFieldHandlers,
      final List<NativeFieldHandler<T, Object>> nativeFieldHandlers ) {
    this(
        indexFieldHandlers,
        nativeFieldHandlers,
        null);
  }

  protected AbstractDataAdapter(
      final List<PersistentIndexFieldHandler<T, ? extends CommonIndexValue, Object>> indexFieldHandlers,
      final List<NativeFieldHandler<T, Object>> nativeFieldHandlers,
      final Object defaultTypeData ) {
    this.nativeFieldHandlers = nativeFieldHandlers;
    init(
        indexFieldHandlers,
        defaultTypeData);
  }

  protected void init(
      final List<? extends IndexFieldHandler<T, ? extends CommonIndexValue, Object>> indexFieldHandlers,
      final Object defaultIndexHandlerData ) {
    dimensionMatchingFieldHandlers = new HashMap<ByteArrayId, IndexFieldHandler<T, ? extends CommonIndexValue, Object>>();
    typeMatchingFieldHandlers = new HashMap<Class<?>, IndexFieldHandler<T, ? extends CommonIndexValue, Object>>();
    // split out the dimension matching index handlers from the type
    // matching index handlers
    for (final IndexFieldHandler<T, ? extends CommonIndexValue, Object> indexHandler : indexFieldHandlers) {
      if (indexHandler instanceof DimensionMatchingIndexFieldHandler) {
        final ByteArrayId[] matchedDimensionFieldIds = ((DimensionMatchingIndexFieldHandler<T, ? extends CommonIndexValue, Object>) indexHandler).getSupportedIndexFieldIds();
        for (final ByteArrayId matchedDimensionId : matchedDimensionFieldIds) {
          dimensionMatchingFieldHandlers.put(
              matchedDimensionId,
              indexHandler);
        }
      }
      else {
        // alternatively we could put make the dimension matching field
        // handlers match types as a last resort rather than this else,
        // but they shouldn't conflict with an existing type matching
        // class
        typeMatchingFieldHandlers.put(
            GenericTypeResolver.resolveTypeArguments(
                indexHandler.getClass(),
                IndexFieldHandler.class)[1],
            indexHandler);
      }
    }

    // add default handlers if the type is not already within the custom
    // handlers
    final List<IndexFieldHandler<T, ? extends CommonIndexValue, Object>> defaultTypeMatchingHandlers = getDefaultTypeMatchingHandlers(defaultIndexHandlerData);
    for (final IndexFieldHandler<T, ? extends CommonIndexValue, Object> defaultFieldHandler : defaultTypeMatchingHandlers) {
      final Class<?> defaultFieldHandlerClass = GenericTypeResolver.resolveTypeArguments(
          defaultFieldHandler.getClass(),
          IndexFieldHandler.class)[1];
      // if the type matching handlers can already handle this class,
      // don't overload it, otherwise, use this as a default handler
      final IndexFieldHandler<T, ? extends CommonIndexValue, Object> existingTypeHandler = FieldUtils.getAssignableValueFromClassMap(
          defaultFieldHandlerClass,
          typeMatchingFieldHandlers);
      if (existingTypeHandler == null) {
        typeMatchingFieldHandlers.put(
            defaultFieldHandlerClass,
            defaultFieldHandler);
      }
    }
  }

  protected List<IndexFieldHandler<T, ? extends CommonIndexValue, Object>> getDefaultTypeMatchingHandlers(
      final Object defaultIndexHandlerData ) {
    return new ArrayList<IndexFieldHandler<T, ? extends CommonIndexValue, Object>>();
  }

  @Override
  public AdapterPersistenceEncoding encode(
      final T entry,
      final CommonIndexModel indexModel ) {
    final PersistentDataset<CommonIndexValue> indexData = new PersistentDataset<CommonIndexValue>();
    final Set<ByteArrayId> nativeFieldsInIndex = new HashSet<ByteArrayId>();
    for (final DimensionField<? extends CommonIndexValue> dimension : indexModel.getDimensions()) {
      final IndexFieldHandler<T, ? extends CommonIndexValue, Object> fieldHandler = getFieldHandler(dimension);
      if (fieldHandler == null) {
        continue;
      }
      final CommonIndexValue value = fieldHandler.toIndexValue(entry);
      indexData.addValue(new PersistentValue<CommonIndexValue>(
          dimension.getFieldId(),
          value));
      nativeFieldsInIndex.addAll(Arrays.asList(fieldHandler.getNativeFieldIds()));
    }
    final PersistentDataset<Object> extendedData = new PersistentDataset<Object>();
    // now for the other data
    for (final NativeFieldHandler<T, Object> fieldHandler : nativeFieldHandlers) {
      final ByteArrayId fieldId = fieldHandler.getFieldId();
      if (nativeFieldsInIndex.contains(fieldId)) {
        continue;
      }
      extendedData.addValue(new PersistentValue<Object>(
          fieldId,
          fieldHandler.getFieldValue(entry)));
    }
    return new AdapterPersistenceEncoding(
        getAdapterId(),
        getDataId(entry),
        indexData,
        extendedData);
  }

  @SuppressWarnings("unchecked")
  @Override
  public T decode(
      final IndexedAdapterPersistenceEncoding data,
      final Index index ) {
    final RowBuilder<T, Object> builder = newBuilder();
    final CommonIndexModel indexModel = index.getIndexModel();
    for (final DimensionField<? extends CommonIndexValue> dimension : indexModel.getDimensions()) {
      final IndexFieldHandler<T, CommonIndexValue, Object> fieldHandler = (IndexFieldHandler<T, CommonIndexValue, Object>) getFieldHandler(dimension);
      if (fieldHandler == null) {
        continue;
      }
      final CommonIndexValue value = data.getCommonData().getValue(
          dimension.getFieldId());
      if (value == null) {
        continue;
      }
      final PersistentValue<Object>[] values = fieldHandler.toNativeValues(value);
      if ((values != null) && (values.length > 0)) {
        for (final PersistentValue<Object> v : values) {
          builder.setField(v);
        }
      }
    }
    for (final PersistentValue<Object> fieldValue : data.getAdapterExtendedData().getValues()) {
      builder.setField(fieldValue);
    }
    return builder.buildRow(data.getDataId());
  }

  abstract protected RowBuilder<T, Object> newBuilder();

  protected IndexFieldHandler<T, ? extends CommonIndexValue, Object> getFieldHandler(
      final DimensionField<? extends CommonIndexValue> dimension ) {
    // first try explicit dimension matching
    IndexFieldHandler<T, ? extends CommonIndexValue, Object> fieldHandler = dimensionMatchingFieldHandlers.get(dimension.getFieldId());
    if (fieldHandler == null) {
      // if that fails, go for type matching
      fieldHandler = FieldUtils.getAssignableValueFromClassMap(
          GenericTypeResolver.resolveTypeArgument(
              dimension.getClass(),
              DimensionField.class),
          typeMatchingFieldHandlers);
      if (fieldHandler == null) {
        LOGGER.warn("Unable to find field handler for data adapter '" + StringUtils.stringFromBinary(getAdapterId().getBytes()) + "' and indexed field '" + StringUtils.stringFromBinary(dimension.getFieldId().getBytes()));
      }
    }
    return fieldHandler;
  }

  @Override
  public byte[] toBinary() {
    // run through the list of field handlers and persist whatever is
    // persistable, if the field handler is not persistable the assumption
    // is that the data adapter can re-create it by some other means

    // use a linked hashset to maintain order and ensure no duplication
    final Set<Persistable> persistables = new LinkedHashSet<Persistable>();
    for (final NativeFieldHandler<T, Object> nativeHandler : nativeFieldHandlers) {
      if (nativeHandler instanceof Persistable) {
        persistables.add((Persistable) nativeHandler);
      }
    }
    for (final IndexFieldHandler<T, ? extends CommonIndexValue, Object> indexHandler : typeMatchingFieldHandlers.values()) {
      if (indexHandler instanceof Persistable) {
        persistables.add((Persistable) indexHandler);
      }
    }
    for (final IndexFieldHandler<T, ? extends CommonIndexValue, Object> indexHandler : dimensionMatchingFieldHandlers.values()) {
      if (indexHandler instanceof Persistable) {
        persistables.add((Persistable) indexHandler);
      }
    }
    if (fieldVisiblityHandler instanceof Persistable) {
      persistables.add((Persistable) fieldVisiblityHandler);
    }
    final byte[] defaultTypeDataBinary = defaultTypeDataToBinary();
    final byte[] persistablesBytes = PersistenceUtils.toBinary(persistables);
    final ByteBuffer buf = ByteBuffer.allocate(defaultTypeDataBinary.length + persistablesBytes.length + 4);
    buf.putInt(defaultTypeDataBinary.length);
    buf.put(defaultTypeDataBinary);
    buf.put(persistablesBytes);
    return buf.array();
  }

  @SuppressWarnings("unchecked")
  @Override
  public void fromBinary(
      final byte[] bytes ) {
    if ((bytes == null) || (bytes.length < 4)) {
      LOGGER.warn("Unable to deserialize data adapter.  Binary is incomplete.");
      return;
    }
    final List<IndexFieldHandler<T, CommonIndexValue, Object>> indexFieldHandlers = new ArrayList<IndexFieldHandler<T, CommonIndexValue, Object>>();
    final List<NativeFieldHandler<T, Object>> nativeFieldHandlers = new ArrayList<NativeFieldHandler<T, Object>>();
    final ByteBuffer buf = ByteBuffer.wrap(bytes);
    final byte[] defaultTypeDataBinary = new byte[buf.getInt()];
    Object defaultTypeData = null;
    if (defaultTypeDataBinary.length > 0) {
      buf.get(defaultTypeDataBinary);
      defaultTypeData = defaultTypeDataFromBinary(defaultTypeDataBinary);
    }

    final byte[] persistablesBytes = new byte[bytes.length - defaultTypeDataBinary.length - 4];
    if (persistablesBytes.length > 0) {
      buf.get(persistablesBytes);
      final List<Persistable> persistables = PersistenceUtils.fromBinary(persistablesBytes);
      for (final Persistable persistable : persistables) {
        if (persistable instanceof IndexFieldHandler) {
          indexFieldHandlers.add((IndexFieldHandler<T, CommonIndexValue, Object>) persistable);
        }
        // in case persistable is polymorphic and multi-purpose, check
        // both
        // handler types and visibility handler
        if (persistable instanceof NativeFieldHandler) {
          nativeFieldHandlers.add((NativeFieldHandler<T, Object>) persistable);
        }
        if (persistable instanceof FieldVisibilityHandler) {
          fieldVisiblityHandler = (FieldVisibilityHandler<T, Object>) persistable;
        }
      }
    }
    this.nativeFieldHandlers = nativeFieldHandlers;
    init(
        indexFieldHandlers,
        defaultTypeData);
  }

  public FieldVisibilityHandler<T, Object> getFieldVisiblityHandler() {
    return fieldVisiblityHandler;
  }

  protected byte[] defaultTypeDataToBinary() {
    return new byte[] {};
  }

  protected Object defaultTypeDataFromBinary(
      final byte[] bytes ) {
    return null;
  }
}
TOP

Related Classes of mil.nga.giat.geowave.store.adapter.AbstractDataAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.