Package com.senseidb.search.req

Source Code of com.senseidb.search.req.SenseiRequestProtoSerializer

/**
* This software is licensed to you under the Apache License, Version 2.0 (the
* "Apache License").
*
* LinkedIn's contributions are made under the Apache License. If you contribute
* to the Software, the contributions will be deemed to have been made under the
* Apache License, unless you expressly indicate otherwise. Please do not make any
* contributions that would be inconsistent with the Apache License.
*
* You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, this software
* distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache
* License for the specific language governing permissions and limitations for the
* software governed under the Apache License.
*
* © 2012 LinkedIn Corp. All Rights Reserved.
*/
package com.senseidb.search.req;


import com.alibaba.fastjson.JSON;
import com.browseengine.bobo.api.*;
import com.browseengine.bobo.facets.DefaultFacetHandlerInitializerParam;
import com.browseengine.bobo.facets.FacetHandlerInitializerParam;
import com.browseengine.bobo.mapred.MapReduceResult;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.linkedin.norbert.network.Serializer;
import com.sensei.search.req.protobuf.SenseiProtos;
import com.senseidb.search.req.mapred.SenseiMapReduce;
import com.senseidb.search.req.mapred.functions.*;
import com.senseidb.util.JSONUtil;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.SortField;
import org.json.JSONException;

import java.io.*;
import java.util.*;


public class SenseiRequestProtoSerializer implements Serializer<SenseiRequest, SenseiResult> {
  private final static Logger logger = Logger.getLogger(SenseiRequestProtoSerializer.class);

  @Override
  public String requestName() {
    return "SenseiRequestV2";
  }

  @Override
  public String responseName() {
    return "SenseiResponseV2";
  }

  @Override
  public SenseiRequest requestFromBytes(byte[] bytes) {
    SenseiProtos.SenseiProtoRequest senseiProtoRequest = null;
    try {
      senseiProtoRequest = SenseiProtos.SenseiProtoRequest.parseFrom(bytes);
    } catch (InvalidProtocolBufferException e) {
      throw new IllegalArgumentException("Could not parse");
    }

    SenseiRequest senseiRequest = new SenseiRequest();

    for (SenseiProtos.BrowseSelection selection : senseiProtoRequest.getSelectionList()) {
      senseiRequest.addSelection(convertBrowseSelection(selection));
    }

    for (SenseiProtos.SortField sortField : senseiProtoRequest.getSortSpecList()) {
      senseiRequest.addSortField(convertSortField(sortField));
    }

    senseiRequest.setFacetSpecs(convertFacetSpecs(senseiProtoRequest.getFacetSpecList()));

    if (senseiProtoRequest.hasSenseiQuery()) {
      String senseiQueryString = senseiProtoRequest.getSenseiQuery();
      SenseiQuery senseiQuery = null;

      try {
        com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(senseiQueryString);
        senseiQuery = new SenseiJSONQuery(new JSONUtil.FastJSONObject(jsonObject));
      } catch (Exception e) {
        senseiQuery = new SenseiQuery(senseiQueryString.getBytes(SenseiQuery.UTF_8_CHARSET));
      }

      senseiRequest.setQuery(senseiQuery);
    }

    if (senseiProtoRequest.hasOffset())
      senseiRequest.setOffset(senseiProtoRequest.getOffset());

    if (senseiProtoRequest.hasCount())
      senseiRequest.setCount(senseiProtoRequest.getCount());

    if (senseiProtoRequest.hasFetchStoredFields())
      senseiRequest.setFetchStoredFields(senseiProtoRequest.getFetchStoredFields());

    if (senseiProtoRequest.hasFetchStoredValue())
      senseiRequest.setFetchStoredValue(senseiProtoRequest.getFetchStoredValue());

    if (senseiProtoRequest.hasFacetHandlerParam())
      senseiRequest.setFacetHandlerInitParamMap(convertFacetParams(senseiProtoRequest.getFacetHandlerParam()));

    if (senseiProtoRequest.getPartitionsCount() > 0)
      senseiRequest.setPartitions(new HashSet<Integer>(senseiProtoRequest.getPartitionsList()));

    if (senseiProtoRequest.hasExplain())
      senseiRequest.setShowExplanation(senseiProtoRequest.getExplain());

    if (senseiProtoRequest.hasRouteParam())
      senseiRequest.setRouteParam(senseiProtoRequest.getRouteParam());

    if (senseiProtoRequest.getGroupByCount() > 0) {
      List<String> groupByList = senseiProtoRequest.getGroupByList();
      senseiRequest.setGroupBy(groupByList.toArray(new String[]{}));
    }

    if (senseiProtoRequest.getDistinctCount() > 0)
      senseiRequest.setDistinct(senseiProtoRequest.getDistinctList().toArray(new String[]{}));

    if (senseiProtoRequest.hasMaxPerGroup())
      senseiRequest.setMaxPerGroup(senseiProtoRequest.getMaxPerGroup());

    if (senseiProtoRequest.getTermVectorsToFetchCount() > 0) {
      senseiRequest.setTermVectorsToFetch(new HashSet<String>(senseiProtoRequest.getTermVectorsToFetchList()));
    }

    if (senseiProtoRequest.getSelectListCount() > 0) {
      senseiRequest.setSelectList(senseiProtoRequest.getSelectListList());
    }

    if (senseiProtoRequest.hasMapReduce()) {

      SenseiMapReduce mapReduceFunction = convertMapReduce(senseiProtoRequest.getMapReduce());
      if (mapReduceFunction != null) {
        senseiRequest.setMapReduceFunction(mapReduceFunction);
        List<String> columns = senseiProtoRequest.getMapReduceColumnsList();
        JSONUtil.FastJSONObject jsonObject = new JSONUtil.FastJSONObject();
        try {
          jsonObject.put("column", columns.get(0));
          jsonObject.put("columns", columns.toArray(new String[]{}));
        } catch (JSONException e) {
          throw new IllegalStateException(e);
        }
        senseiRequest.getMapReduceFunction().init(jsonObject);
      } else {
        ByteString mapReduceBytes = senseiProtoRequest.getMapReduceBytes();

        Object object = null;
        try {
          ObjectInputStream ois = new ObjectInputStream(mapReduceBytes.newInput());
          object = ois.readObject();
        } catch (IOException ioException) {
          // Shouldn't happen.
          logger.error("IO Exception deserializing map reduce, ignoring mapreduce", ioException);
        } catch (ClassNotFoundException cnfe) {
          logger.error("Could not find class to deserialize to, ignoring mapreduce", cnfe);
        }

        if (object != null) {
          SenseiMapReduce mapReduce = (SenseiMapReduce) object;
          senseiRequest.setMapReduceFunction(mapReduce);
        }
      }
    }

    return senseiRequest;
  }

  @Override
  public byte[] requestToBytes(SenseiRequest request) {
    SenseiProtos.SenseiProtoRequest.Builder builder = SenseiProtos.SenseiProtoRequest.newBuilder();

    if (request.getSelections() != null) {
      for (BrowseSelection browseSelection : request.getSelections()) {
        builder.addSelection(convertBrowseSelection(browseSelection));
      }
    }

    for (SortField sortField : request.getSort()) {
      builder.addSortSpec(convertSortField(sortField));
    }

    if (request.getFacetSpecs() != null) {
      for (Map.Entry<String, FacetSpec> facetSpec : request.getFacetSpecs().entrySet()) {
        builder.addFacetSpec(convertFacetSpec(facetSpec.getKey(), facetSpec.getValue()));
      }
    }

    if (request.getQuery() != null) {
      SenseiQuery senseiQuery = request.getQuery();
      builder.setSenseiQuery(senseiQuery.toString());
    }

    builder
        .setOffset(request.getOffset())
        .setCount(request.getCount())
        .setFetchStoredFields(request.isFetchStoredFields())
        .setFetchStoredValue(request.isFetchStoredValue())
        .setFacetHandlerParam(convertFacetParams(request.getFacetHandlerInitParamMap()))
        .addAllPartitions(request.getPartitions() == null ? Collections.<Integer>emptyList() : request.getPartitions())
        .setExplain(request.isShowExplanation())
        .setRouteParam(request.getRouteParam())
        .setMaxPerGroup(request.getMaxPerGroup());

    if (request.getGroupBy() != null) {
      builder.addAllGroupBy(Arrays.asList(request.getGroupBy()));
    }

    if(request.getDistinct() != null) {
      builder.addAllDistinct(Arrays.asList(request.getDistinct()));
    }

    if(request.getTermVectorsToFetch() != null) {
      builder.addAllTermVectorsToFetch(request.getTermVectorsToFetch());
    }

    if(request.getSelectList() != null) {
      builder.addAllSelectList(request.getSelectList());
    }

    if (request.getMapReduceFunction() != null) {
      SenseiProtos.SenseiMapReduceFunction protoMapReduceFunction = convertMapReduce(request.getMapReduceFunction());
      builder.setMapReduce(protoMapReduceFunction);

      if (protoMapReduceFunction == SenseiProtos.SenseiMapReduceFunction.UNKNOWN) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
          ObjectOutputStream oos = new ObjectOutputStream(baos);
          oos.writeObject(request.getMapReduceFunction());
          oos.flush();
        } catch (IOException e) {
          logger.error("Could not deserialize map reduce function", e);
        }

        builder.setMapReduceBytes(ByteString.copyFrom(baos.toByteArray()));
      } else {
        String[] columns = request.getMapReduceFunction().getColumns();
        builder.addAllMapReduceColumns(Arrays.asList(columns));
      }
    }

    SenseiProtos.SenseiProtoRequest senseiProtoRequest = builder.build();
    return senseiProtoRequest.toByteArray();
  }

  private SenseiProtos.JavaPrimitives getPrimitiveType(Object[] array) {
    if (array instanceof Integer[]) {
      return SenseiProtos.JavaPrimitives.INT;
    } else if (array instanceof Long[]) {
      return SenseiProtos.JavaPrimitives.LONG;
    } else if (array instanceof Byte[]) {
      return SenseiProtos.JavaPrimitives.BYTE;
    } else if (array instanceof Character[]) {
      return SenseiProtos.JavaPrimitives.CHAR;
    } else if (array instanceof Float[]) {
      return SenseiProtos.JavaPrimitives.FLOAT;
    } else if (array instanceof Double[]) {
      return SenseiProtos.JavaPrimitives.DOUBLE;
    } else if (array instanceof Integer[]) {
      return SenseiProtos.JavaPrimitives.INT;
    } else if (array instanceof Short[]) {
      return SenseiProtos.JavaPrimitives.SHORT;
    } else if (array instanceof String[]) {
      return SenseiProtos.JavaPrimitives.STRING;
    } else {
      // Try to figure if the individual elements in the array are primitive and homogenous
      int[] counts = new int[SenseiProtos.JavaPrimitives.values().length + 1];

      for(Object o : array) {
        SenseiProtos.JavaPrimitives primitiveType = getPrimitiveType(o);
        counts[primitiveType.getNumber()]++;
      }

      int uniqueCount = 0;
      int primitiveIndex = 0;

      for(int i = 0; i < counts.length; i++) {
        int count = counts[i];
        if(count > 0) {
          primitiveIndex = i;
          uniqueCount++;
        }
      }

      if(uniqueCount == 1) {
        return SenseiProtos.JavaPrimitives.valueOf(primitiveIndex);
      } else {
        return SenseiProtos.JavaPrimitives.OBJECT;
      }
    }
  }

  private SenseiProtos.JavaPrimitives getPrimitiveType(Object o) {
    if (o instanceof Integer) {
      return SenseiProtos.JavaPrimitives.INT;
    } else if (o instanceof Long) {
      return SenseiProtos.JavaPrimitives.LONG;
    } else if (o instanceof Byte) {
      return SenseiProtos.JavaPrimitives.BYTE;
    } else if (o instanceof Character) {
      return SenseiProtos.JavaPrimitives.CHAR;
    } else if (o instanceof Float) {
      return SenseiProtos.JavaPrimitives.FLOAT;
    } else if (o instanceof Double) {
      return SenseiProtos.JavaPrimitives.DOUBLE;
    } else if (o instanceof Short) {
      return SenseiProtos.JavaPrimitives.SHORT;
    } else if (o instanceof String) {
      return SenseiProtos.JavaPrimitives.STRING;
    } else {
      return SenseiProtos.JavaPrimitives.OBJECT;
    }
  }

  private Object[] convert(List<String> values, SenseiProtos.JavaPrimitives type) {
    switch (type) {
      case BOOLEAN: {
        Boolean[] result = new Boolean[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Boolean.parseBoolean(values.get(i));
        return result;
      }
      case INT: {
        Integer[] result = new Integer[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Integer.parseInt(values.get(i));
        return result;
      }
      case LONG: {
        Long[] result = new Long[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Long.parseLong(values.get(i));
        return result;
      }
      case BYTE: {
        Byte[] result = new Byte[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Byte.parseByte(values.get(i));
        return result;
      }
      case CHAR: {
        Character[] result = new Character[values.size()];
        for (int i = 0; i < result.length; i++) {
          result[i] = values.get(i).charAt(0);
        }
        return result;
      }
      case FLOAT: {
        Float[] result = new Float[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Float.parseFloat(values.get(i));
        return result;
      }
      case DOUBLE: {
        Double[] result = new Double[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Double.parseDouble(values.get(i));
        return result;
      }
      case SHORT: {
        Short[] result = new Short[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = Short.parseShort(values.get(i));
        return result;
      }
      case STRING: {
        String[] result = new String[values.size()];
        for (int i = 0; i < result.length; i++) result[i] = values.get(i);
        return result;
      }
      default: {
        String error = "Unknown type for converting raw field values " + type;
        throw new IllegalArgumentException(error);
      }
    }
  }

  private Object convert(String value, SenseiProtos.JavaPrimitives type) {
    switch (type) {
      case BOOLEAN: return Boolean.parseBoolean(value);
      case INT: return Integer.parseInt(value);
      case LONG: return Long.parseLong(value);
      case BYTE: return Byte.parseByte(value);
      case CHAR: return value.charAt(0);
      case FLOAT: return Float.parseFloat(value);
      case DOUBLE: return Double.parseDouble(value);
      case SHORT: return Short.parseShort(value);
      case STRING: return value;
      default: {
        String error = "Unknown type for converting raw field values " + type;
        throw new IllegalArgumentException(error);
      }
    }

  }

  private SenseiProtos.Explanation convertExplanation(Explanation explanation) {
    SenseiProtos.Explanation.Builder builder = SenseiProtos.Explanation.newBuilder();

    builder.setDescription(explanation.getDescription());
    builder.setValue(explanation.getValue());
    if (explanation.getDetails() != null && explanation.getDetails().length > 0) {
      for (int i = 0; i < explanation.getDetails().length; i++) {
        builder.addDetails(convertExplanation(explanation.getDetails()[i]));
      }
    }

    return builder.build();
  }

  private Explanation convertExplanation(SenseiProtos.Explanation protoExplanation) {
    Explanation explanation = new Explanation(protoExplanation.getValue(), protoExplanation.getDescription());
    if (protoExplanation.getDetailsCount() > 0) {
      for (SenseiProtos.Explanation detail : protoExplanation.getDetailsList()) {
        explanation.addDetail(convertExplanation(detail));
      }
    }
    return explanation;
  }

  private SenseiProtos.Fieldable convertFieldable(Fieldable fieldable) {
    SenseiProtos.Fieldable.Builder builder = SenseiProtos.Fieldable.newBuilder();
    builder.setBoost(fieldable.getBoost());
    builder.setName(fieldable.name());

    if (fieldable.stringValue() != null)
      builder.setStringValue(fieldable.stringValue());

    builder.setStored(fieldable.isStored());
    builder.setIndexed(fieldable.isIndexed());
    builder.setTokenized(fieldable.isTokenized());
    builder.setTermVectorStored(fieldable.isTermVectorStored());
    builder.setStoreOffsetWithTermVector(fieldable.isStoreOffsetWithTermVector());
    builder.setStorePositionWithTermVector(fieldable.isStorePositionWithTermVector());
    builder.setBinary(fieldable.isBinary());
    builder.setOmitNorms(fieldable.getOmitNorms());
    builder.setLazy(fieldable.isLazy());
    builder.setBinaryOffset(fieldable.getBinaryOffset());
    builder.setBinaryLength(fieldable.getBinaryLength());
    if (fieldable.getBinaryValue() != null) {
      builder.setBinaryValue(ByteString.copyFrom(fieldable.getBinaryValue()));
    }
    return builder.build();
  }

  private Fieldable convertFieldable(SenseiProtos.Fieldable protoFieldable) {
    String name = protoFieldable.hasName() ? protoFieldable.getName() : null;
    String value = protoFieldable.hasStringValue() ? protoFieldable.getStringValue() : null;

    if (value != null) {
      Field.Store store = protoFieldable.hasStored() ? (protoFieldable.getStored() ? Field.Store.YES : Field.Store.NO) : Field.Store.NO;

      Field.TermVector termVector = Field.TermVector.toTermVector(protoFieldable.getStored(),
          protoFieldable.getStoreOffsetWithTermVector(),
          protoFieldable.getStorePositionWithTermVector());

      Field.Index index = Field.Index.toIndex(protoFieldable.getIndexed(), false, protoFieldable.getOmitNorms());

      Field field = new Field(name, value, store, index, termVector);

      if (protoFieldable.hasBoost())
        field.setBoost(protoFieldable.getBoost());

      if (protoFieldable.hasOmitNorms())
        field.setOmitNorms(protoFieldable.getOmitNorms());

      return field;
    } else {
      Field.Store store = protoFieldable.hasStored() ? (protoFieldable.getStored() ? Field.Store.YES : Field.Store.NO) : Field.Store.NO;
      byte[] binaryValue = protoFieldable.getBinaryValue() == null ? null : protoFieldable.getBinaryValue().toByteArray();
      int binaryOffset = protoFieldable.getBinaryOffset();
      int binaryLength = protoFieldable.getBinaryLength();

      Field field = new Field(name, binaryValue, binaryOffset, binaryLength, store);
      return field;
    }
  }

  private SenseiProtos.Document convertDocument(Document document) {
    SenseiProtos.Document.Builder builder = SenseiProtos.Document.newBuilder();
    builder.setBoost(document.getBoost());

    if (document.getFields() != null) {
      for (Fieldable field : document.getFields()) {
        builder.addFields(convertFieldable(field));
      }
    }
    return builder.build();
  }

  private Document convertDocument(SenseiProtos.Document protoDocument) {
    Document document = new Document();
    if (protoDocument.hasBoost())
      document.setBoost(protoDocument.getBoost());

    if (protoDocument.getFieldsCount() > 0) {
      for (SenseiProtos.Fieldable protoFieldable : protoDocument.getFieldsList()) {
        document.add(convertFieldable(protoFieldable));
      }
    }
    return document;
  }

  private SenseiProtos.TermFrequencyMap convert(Map<String, BrowseHit.TermFrequencyVector> map) {
    SenseiProtos.TermFrequencyMap.Builder builder = SenseiProtos.TermFrequencyMap.newBuilder();
    for(Map.Entry<String, BrowseHit.TermFrequencyVector> entry : map.entrySet()) {
      SenseiProtos.TermFrequencyVector.Builder vectorBuilder = SenseiProtos.TermFrequencyVector.newBuilder();

      BrowseHit.TermFrequencyVector vector = entry.getValue();
      for(int i = 0; i < vector.freqs.length; i++) {
        vectorBuilder.addFreq(vector.freqs[i]);
        vectorBuilder.addTerms(vector.terms[i]);
      }

      builder.addKey(entry.getKey());
      builder.addValue(vectorBuilder);
    }
    return builder.build();
  }

  private Map<String, BrowseHit.TermFrequencyVector> convert(SenseiProtos.TermFrequencyMap protoMap) {
    HashMap<String, BrowseHit.TermFrequencyVector> result = new HashMap<String, BrowseHit.TermFrequencyVector>();
    for(int i = 0; i < protoMap.getKeyCount(); i++) {
      SenseiProtos.TermFrequencyVector protoVector = protoMap.getValue(i);
      int[] freq = new int[protoVector.getFreqCount()];
      String[] terms = new String[protoVector.getTermsCount()];

      for(int j = 0; j < protoVector.getFreqCount(); j++) {
        freq[j] = protoVector.getFreq(j);
      }

      for(int j = 0; j < protoVector.getTermsCount(); j++) {
        terms[j] = protoVector.getTerms(j);
      }

      BrowseHit.TermFrequencyVector termFrequencyVector = new BrowseHit.TermFrequencyVector(terms, freq);
      result.put(protoMap.getKey(i), termFrequencyVector);
    }
    return result;
  }

  private SenseiProtos.ObjectArray convert(Object[] objects) {
    SenseiProtos.ObjectArray.Builder builder = SenseiProtos.ObjectArray.newBuilder();
    SenseiProtos.JavaPrimitives primitiveType = getPrimitiveType(objects);
    builder.setType(primitiveType);

    switch (primitiveType) {
      case BYTE: {
        for(Object o : objects) {
          builder.addIntValue((Byte) o);
        }
        break;
      }
      case SHORT: {
        for(Object o : objects) {
          builder.addIntValue((Short) o);
        }
        break;
      }
      case CHAR: {
        for(Object o : objects) {
          builder.addIntValue((Character) o);
        }
        break;
      }
      case INT: {
        for(Object o : objects) {
          builder.addIntValue((Integer) o);
        }
        break;
      }
      case BOOLEAN: {
        for(Object o : objects) {
          builder.addBooleanValue((Boolean) o);
        }
        break;
      }
      case LONG: {
        for(Object o : objects) {
          builder.addLongValue((Long) o);
        }
        break;
      }
      case FLOAT: {
        for(Object o : objects) {
          builder.addFloatValue((Float) o);
        }
        break;
      }
      case DOUBLE: {
        for(Object o : objects) {
          builder.addDoubleValue((Double) o);
        }
        break;
      }
      case STRING: {
        for(Object o : objects) {
          builder.addStringValue((String) o);
        }
        break;
      }
      case OBJECT: {
        for(Object o : objects) {
          if(o instanceof long[]) {
            SenseiProtos.LongArray.Builder longArrayBuilder = SenseiProtos.LongArray.newBuilder();
            for(long item : (long[]) o) {
              longArrayBuilder.addItem(item);
            }
            builder.addLongArray(longArrayBuilder);
          } else {
            builder.addObjectValue(javaSerialize(o));
          }
        }
        break;
      }
    }
    return builder.build();
  }

  private Object[] convert(SenseiProtos.ObjectArray objectArray) {
    SenseiProtos.JavaPrimitives type = objectArray.getType();
    switch (type) {
      case BOOLEAN: {
        Boolean[] result = new Boolean[objectArray.getBooleanValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getBooleanValue(i);
        }
        return result;
      }
      case BYTE: {
        Byte[] result = new Byte[objectArray.getIntValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = (byte) objectArray.getIntValue(i);
        }
        return result;
      }
      case CHAR: {
        Character[] result = new Character[objectArray.getIntValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = (char) objectArray.getIntValue(i);
        }
        return result;
      }
      case SHORT: {
        Short[] result = new Short[objectArray.getIntValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = (short) objectArray.getIntValue(i);
        }
        return result;
      }
      case INT: {
        Integer[] result = new Integer[objectArray.getIntValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getIntValue(i);
        }
        return result;
      }
      case LONG: {
        Long[] result = new Long[objectArray.getLongValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getLongValue(i);
        }
        return result;
      }
      case FLOAT: {
        Float[] result = new Float[objectArray.getFloatValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getFloatValue(i);
        }
        return result;
      }
      case DOUBLE: {
        Double[] result = new Double[objectArray.getDoubleValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getDoubleValue(i);
        }
        return result;
      }
      case STRING: {
        String[] result = new String[objectArray.getStringValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = objectArray.getStringValue(i);
        }
        return result;
      }
      case OBJECT: {
        if(objectArray.getLongArrayCount() > 0) {
          long[][] result = new long[objectArray.getLongArrayCount()][];
          for(int i = 0; i < result.length; i++) {
            result[i] = new long[objectArray.getLongArray(i).getItemCount()];
            for(int j = 0; j < result[i].length; j++) {
              result[i][j] = objectArray.getLongArray(i).getItem(j);
            }
          }
          return result;
        } else {
          Object[] result = new Object[objectArray.getObjectValueCount()];
          for(int i = 0; i < result.length; i++) {
            result[i] = javaDeserialize(objectArray.getObjectValue(i));
          }
          return result;
        }
      }
      default: {
        Object[] result = new Object[objectArray.getObjectValueCount()];
        for(int i = 0; i < result.length; i++) {
          result[i] = javaDeserialize(objectArray.getObjectValue(i));
        }
        return result;
      }
    }
  }

  private SenseiProtos.SenseiHit convert(SenseiHit senseiHit) {
    SenseiProtos.SenseiHit.Builder builder = SenseiProtos.SenseiHit.newBuilder();
    builder.setScore(senseiHit.getScore());
    builder.setDocId(senseiHit.getDocid());

    if(senseiHit.getFeatures() != null) {
      for (float f : senseiHit.getFeatures()) {
        builder.addFeatures(f);
      }
    }

    if(senseiHit.getRawFieldValues() != null) {
      SenseiProtos.FieldValues.Builder fieldValues = SenseiProtos.FieldValues.newBuilder();
      for(Map.Entry<String, Object[]> entry : senseiHit.getRawFieldValues().entrySet()) {
        fieldValues.addKey(entry.getKey());
        fieldValues.addRawValue(convert(entry.getValue()));

        String[] fields = senseiHit.getFields(entry.getKey());
        fieldValues.addValue(convert(fields));
      }
      builder.setFieldValues(fieldValues);
    }

    builder.setGroupPosition(senseiHit.getGroupPosition());

    if (senseiHit.getGroupField() != null)
      builder.setGroupField(senseiHit.getGroupField());

    if (senseiHit.getGroupValue() != null) {
      builder.setGroupValue(senseiHit.getGroupValue());
    }

    if(senseiHit.getRawGroupValue() != null) {
      builder.setRawGroupValue(javaSerialize(senseiHit.getRawGroupValue()));
    }

    builder.setTotalGroupHitCount(senseiHit.getGroupHitsCount());

    if (senseiHit.getGroupHits() != null && senseiHit.getSenseiGroupHits().length > 0) {
      for (BrowseHit groupHit : senseiHit.getSenseiGroupHits()) {
        if(groupHit instanceof SenseiHit) {
          SenseiProtos.SenseiHit protoGroupHit = convert((SenseiHit) groupHit);
          builder.addGroupHit(protoGroupHit);
        } else {
          throw new IllegalArgumentException("Expect the browse hits to be of type SenseiHit");
        }
      }
    }

    if (senseiHit.getExplanation() != null) {
      builder.setExplanation(convertExplanation(senseiHit.getExplanation()));
    }

    builder.setUid(senseiHit.getUID());
    if (senseiHit.getSrcData() != null) {
      builder.setSrcData(senseiHit.getSrcData());
    }

    if (senseiHit.getStoredFields() != null) {
      builder.setStoredFields(convertDocument(senseiHit.getStoredFields()));
    }

    if (senseiHit.getStoredValue() != null)
      builder.setStoredValue(ByteString.copyFrom(senseiHit.getStoredValue()));

    if(senseiHit.getTermFreqMap() != null) {
      builder.setTermFrequencyMap(convert(senseiHit.getTermFreqMap()));
    }

//    builder.setSenseiHitBytes(javaSerialize(senseiHit));

    return builder.build();
  }

  private String[] convert(SenseiProtos.StringArray protoStringArray) {
    String[] result = new String[protoStringArray.getItemCount()];
    for(int i = 0; i < result.length; i++) {
      result[i] = protoStringArray.getItem(i);
    }
    return result;
  }

  private SenseiProtos.StringArray convert(String[] stringArray) {
    SenseiProtos.StringArray.Builder builder = SenseiProtos.StringArray.newBuilder();
    for(String string : stringArray) {
      builder.addItem(string);
    }
    return builder.build();
  }

  private SenseiHit convert(SenseiProtos.SenseiHit protoSenseiHit) {
    SenseiHit senseiHit = new SenseiHit();
    if (protoSenseiHit.hasScore()) {
      senseiHit.setScore(protoSenseiHit.getScore());
    }

    if (protoSenseiHit.hasDocId()) {
      senseiHit.setDocid(protoSenseiHit.getDocId());
    }

    SenseiProtos.FieldValues protoFieldValues = protoSenseiHit.getFieldValues();
    Map<String, Object[]> rawFieldValues = new LinkedHashMap<String, Object[]>();
    Map<String, String[]> fieldValues = new LinkedHashMap<String, String[]>();
    if(protoFieldValues != null) {
      int numItems = protoFieldValues.getKeyCount();

      if(numItems > 0) {
        for(int i = 0; i < numItems; i++) {
          String key = protoFieldValues.getKey(i);
          SenseiProtos.ObjectArray protoObjectArray = protoFieldValues.getRawValue(i);
          Object[] objects = convert(protoObjectArray);

          rawFieldValues.put(key, objects);

          fieldValues.put(key, convert(protoFieldValues.getValue(i)));
        }

      }
    }
    senseiHit.setRawFieldValues(rawFieldValues);
    senseiHit.setFieldValues(fieldValues);


    if (protoSenseiHit.hasGroupPosition()) {
      senseiHit.setGroupPosition(protoSenseiHit.getGroupPosition());
    }

    if (protoSenseiHit.hasGroupField()) {
      senseiHit.setGroupField(protoSenseiHit.getGroupField());
    }

    if (protoSenseiHit.hasGroupValue()) {
      senseiHit.setGroupValue(protoSenseiHit.getGroupValue());
    }

    if(protoSenseiHit.hasRawGroupValue()) {
      senseiHit.setRawGroupValue(javaDeserialize(protoSenseiHit.getRawGroupValue()));
    }

    if(protoSenseiHit.hasTotalGroupHitCount()) {
      senseiHit.setGroupHitsCount(protoSenseiHit.getTotalGroupHitCount());
    }

    if (protoSenseiHit.getGroupHitCount() > 0) {
      SenseiHit[] groupHits = new SenseiHit[protoSenseiHit.getGroupHitCount()];
      int i = 0;
      for (SenseiProtos.SenseiHit hit : protoSenseiHit.getGroupHitList()) {
        groupHits[i++] = convert(hit);
      }
      senseiHit.setGroupHits(groupHits);
    }

    if (protoSenseiHit.hasExplanation()) {
      senseiHit.setExplanation(convertExplanation(protoSenseiHit.getExplanation()));
    }

    if (protoSenseiHit.hasUid()) {
      senseiHit.setUID(protoSenseiHit.getUid());
    }

    if (protoSenseiHit.hasSrcData()) {
      senseiHit.setSrcData(protoSenseiHit.getSrcData());
    }

    if (protoSenseiHit.hasStoredFields()) {
      senseiHit.setStoredFields(convertDocument(protoSenseiHit.getStoredFields()));
    }

    if (protoSenseiHit.hasStoredValue()) {
      senseiHit.setStoredValue(protoSenseiHit.getStoredValue().toByteArray());
    }

    if (protoSenseiHit.hasTermFrequencyMap()) {
      senseiHit.setTermFreqMap(convert(protoSenseiHit.getTermFrequencyMap()));
    }

    if (protoSenseiHit.getFeaturesList() != null) {
      float [] features = new float[protoSenseiHit.getFeaturesCount()];
      for (int i = 0; i < features.length; i++) {
        features[i] = protoSenseiHit.getFeatures(i);
      }
      senseiHit.setFeatures(features);
    }

    return senseiHit;
  }

  private BrowseFacet convertBrowseFacet(SenseiProtos.BrowseFacet protoFacet) {
    BrowseFacet facet = new BrowseFacet();
    facet.setFacetValueHitCount(protoFacet.getHitCount());

    if (protoFacet.hasValue())
      facet.setValue(protoFacet.getValue());
    return facet;
  }

  private SenseiProtos.BrowseFacet convertBrowseFacet(BrowseFacet browseFacet) {
    SenseiProtos.BrowseFacet.Builder builder = SenseiProtos.BrowseFacet.newBuilder();
    builder.setHitCount(browseFacet.getFacetValueHitCount());
    if (browseFacet.getValue() != null)
      builder.setValue(browseFacet.getValue());

    return builder.build();
  }

  private SenseiProtos.FacetAccessible convertFacetAccessible(FacetAccessible facetAccessible) {
    SenseiProtos.FacetAccessible.Builder builder = SenseiProtos.FacetAccessible.newBuilder();

//    ByteString byteString = javaSerialize(facetAccessible);
//    builder.setFacetAccessibleBytes(byteString);

    List<BrowseFacet> facets = facetAccessible.getFacets();
    for (BrowseFacet facet : facets) {
      SenseiProtos.BrowseFacet protoFacet = convertBrowseFacet(facet);
      builder.addFacets(protoFacet);
    }
    return builder.build();
  }

  private FacetAccessible convertFacetAccessible(SenseiProtos.FacetAccessible facetAccessible) {
//    ByteString facetAccessibleBytes = facetAccessible.getFacetAccessibleBytes();
//    return (FacetAccessible) javaDeserialize(facetAccessibleBytes);
    List<SenseiProtos.BrowseFacet> protoFacets = facetAccessible.getFacetsList();
    BrowseFacet[] facets = new BrowseFacet[protoFacets.size()];

    int i = 0;
    for (SenseiProtos.BrowseFacet protoFacet : protoFacets) {
      BrowseFacet browseFacet = convertBrowseFacet(protoFacet);
      facets[i++] = browseFacet;
    }

    return new MappedFacetAccessible(facets);
  }

  private SenseiProtos.FacetMap convertFacetMap(Map<String, FacetAccessible> facetMap) {
    SenseiProtos.FacetMap.Builder builder = SenseiProtos.FacetMap.newBuilder();
    for (Map.Entry<String, FacetAccessible> entry : facetMap.entrySet()) {
      builder.addKey(entry.getKey());
      builder.addValue(convertFacetAccessible(entry.getValue()));
    }
    return builder.build();
  }

  private Map<String, FacetAccessible> convertFacetMap(SenseiProtos.FacetMap protoFacetMap) {
    Map<String, FacetAccessible> facetMap = new HashMap<String, FacetAccessible>();
    for (int i = 0; i < protoFacetMap.getKeyCount(); i++) {
      facetMap.put(protoFacetMap.getKey(i), convertFacetAccessible(protoFacetMap.getValue(i)));

    }
    return facetMap;
  }

  private static final ByteString javaSerialize(Object o) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
      ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);
      objectOutputStream.writeObject(o);
      objectOutputStream.close();
    } catch (IOException ioException) {
      logger.error("Could not serialize java object ", ioException);
    }
    return ByteString.copyFrom(baos.toByteArray());
  }

  private static final Object javaDeserialize(ByteString bytes) {
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray());

    Object object = null;
    try {
      ObjectInputStream objectInputStream = new ObjectInputStream(bais);
      object = objectInputStream.readObject();
    } catch (IOException ioException) {
      logger.error("Could not deserialize reduce result ", ioException);
    } catch (ClassNotFoundException cnfe) {
      logger.error("Unknown class trying to deserialize reduce result ", cnfe);
    }
    return object;
  }


  private SenseiProtos.MapReduceResult convertMapReduceResult(MapReduceResult mapReduceResult) {
    SenseiProtos.MapReduceResult.Builder builder = SenseiProtos.MapReduceResult.newBuilder();

    List mapResults = mapReduceResult.getMapResults();
    Serializable reduceResult = mapReduceResult.getReduceResult();

    if (reduceResult != null) {
      builder.setReduceResult(javaSerialize(reduceResult));
    }

    if (mapResults != null) {
      for (Object mapResult : mapResults) {
        builder.addMapResult(javaSerialize(mapResult));
      }
    }

    return builder.build();
  }

  private MapReduceResult convertMapReduceResult(SenseiProtos.MapReduceResult protoMapReduceResult) {
    MapReduceResult mapReduceResult = new MapReduceResult();

    if (protoMapReduceResult.hasReduceResult()) {
      Object reduceResult = javaDeserialize(protoMapReduceResult.getReduceResult());

      if (reduceResult != null)
        mapReduceResult.setReduceResult((Serializable) reduceResult);
    }

    if (protoMapReduceResult.getMapResultCount() > 0) {
      List mapResults = new ArrayList();
      for (ByteString protoMapResult : protoMapReduceResult.getMapResultList()) {
        Object mapResult = javaDeserialize(protoMapResult);

        if (mapResult != null)
          mapResults.add(mapResult);
      }
      mapReduceResult.setMapResults(mapResults);
    }
    return mapReduceResult;
  }

  private SenseiProtos.ErrorType convert(ErrorType errorType) {
    switch (errorType) {
      case BoboExecutionError: return SenseiProtos.ErrorType.BoboExecutionError;
      case BQLParsingError: return SenseiProtos.ErrorType.BQLParsingError;
      case BrokerGatherError: return SenseiProtos.ErrorType.BrokerGatherError;
      case BrokerTimeout: return SenseiProtos.ErrorType.BrokerTimeout;
      case ExecutionTimeout: return SenseiProtos.ErrorType.ExecutionTimeout;
      case FederatedBrokerUnavailable: return SenseiProtos.ErrorType.FederatedBrokerUnavailable;
      case InternalError: return SenseiProtos.ErrorType.InternalError;
      case JsonCompilationError: return SenseiProtos.ErrorType.JsonCompilationError;
      case JsonParsingError: return SenseiProtos.ErrorType.JsonParsingError;
      case MergePartitionError: return SenseiProtos.ErrorType.MergePartitionError;
      case PartitionCallError: return SenseiProtos.ErrorType.PartitionCallError;
      case UnknownError: return SenseiProtos.ErrorType.UnknownError;
      default: {
        logger.warn("Unknown error type in proto serialization, setting unknown " + errorType);
        return SenseiProtos.ErrorType.UnknownError;
      }
    }
  }

  private ErrorType convert(SenseiProtos.ErrorType protoErrorType) {
    switch (protoErrorType) {
      case BoboExecutionError: return ErrorType.BoboExecutionError;
      case BQLParsingError: return ErrorType.BQLParsingError;
      case BrokerGatherError: return ErrorType.BrokerGatherError;
      case BrokerTimeout: return ErrorType.BrokerTimeout;
      case ExecutionTimeout: return ErrorType.ExecutionTimeout;
      case FederatedBrokerUnavailable: return ErrorType.FederatedBrokerUnavailable;
      case InternalError: return ErrorType.InternalError;
      case JsonCompilationError: return ErrorType.JsonCompilationError;
      case JsonParsingError: return ErrorType.JsonParsingError;
      case MergePartitionError: return ErrorType.MergePartitionError;
      case PartitionCallError: return ErrorType.PartitionCallError;
      case UnknownError: return ErrorType.UnknownError;
      default: {
        logger.warn("Unknown serialization error coming from protobuf, setting unknown " + protoErrorType);
        return ErrorType.UnknownError;
      }
    }
  }

  private SenseiProtos.SenseiError convert(SenseiError senseiError) {
    SenseiProtos.SenseiError.Builder builder = SenseiProtos.SenseiError.newBuilder();

    builder.setCode(senseiError.getErrorCode());

    if(senseiError.getMessage() != null) {
      builder.setMessage(senseiError.getMessage());
    }

    if(senseiError.getErrorType() != null) {
      builder.setType(convert(senseiError.getErrorType()));
    }

    return builder.build();
  }

  private SenseiError convert(SenseiProtos.SenseiError protoSenseiError) {
    String message = protoSenseiError.hasMessage() ? protoSenseiError.getMessage() : null;
    ErrorType errorType = protoSenseiError.hasType() ? convert(protoSenseiError.getType()) : null;
    int code = protoSenseiError.hasCode() ? protoSenseiError.getCode() :
        (errorType != null ? errorType.getDefaultErrorCode() : 0);

    SenseiError senseiError =
        new SenseiError(message, errorType, code);

    return senseiError;
  }


  @Override
  public byte[] responseToBytes(SenseiResult senseiResult) {
    SenseiProtos.SenseiProtoResult.Builder builder = SenseiProtos.SenseiProtoResult.newBuilder();

    if (senseiResult.getParsedQuery() != null)
      builder.setParsedQuery(senseiResult.getParsedQuery());

    if (senseiResult.getSenseiHits() != null && senseiResult.getSenseiHits().length > 0) {
      for (SenseiHit senseiHit : senseiResult.getSenseiHits()) {
        builder.addHit(convert(senseiHit));
      }
    }

    builder.setTid(senseiResult.getTid());
    builder.setNumHits(senseiResult.getNumHits());
    builder.setTotalDocs(senseiResult.getTotalDocs());

    FacetAccessible[] groupAccessibles = senseiResult.getGroupAccessibles();
    if (groupAccessibles != null && groupAccessibles.length > 0) {
      for (FacetAccessible groupAccessible : groupAccessibles) {
        builder.addGroupAccessible(convertFacetAccessible(groupAccessible));
      }
    }

    Map<String, FacetAccessible> facetMap = senseiResult.getFacetMap();
    if (facetMap != null) {
      builder.setFacetMap(convertFacetMap(facetMap));
    }

    builder.setTime(senseiResult.getTime());

    if (senseiResult.getMapReduceResult() != null)
      builder.setMapReduceResult(convertMapReduceResult(senseiResult.getMapReduceResult()));

    if(senseiResult.getErrors() != null && !senseiResult.getErrors().isEmpty()) {
      for(SenseiError senseiError : senseiResult.getErrors()) {
        builder.addError(convert(senseiError));
      }
    }

    SenseiProtos.SenseiProtoResult protoResult = builder.build();
    return protoResult.toByteArray();
  }

  @Override
  public SenseiResult responseFromBytes(byte[] bytes) {
    SenseiProtos.SenseiProtoResult senseiProtoResult = null;
    try {
      senseiProtoResult = SenseiProtos.SenseiProtoResult.parseFrom(bytes);
    } catch (InvalidProtocolBufferException e) {
      throw new IllegalArgumentException("Could not parse proto result");
    }

    SenseiResult senseiResult = new SenseiResult();
    if (senseiProtoResult.hasParsedQuery())
      senseiResult.setParsedQuery(senseiProtoResult.getParsedQuery());

    List<SenseiHit> hits = new ArrayList<SenseiHit>(senseiProtoResult.getHitCount());
    for (SenseiProtos.SenseiHit senseiHit : senseiProtoResult.getHitList()) {
      hits.add(convert(senseiHit));
    }
    senseiResult.setHits(hits.toArray(new SenseiHit[]{}));

    if (senseiProtoResult.hasTid())
      senseiResult.setTid(senseiProtoResult.getTid());

    if (senseiProtoResult.hasNumHits())
      senseiResult.setNumHits((int) senseiProtoResult.getNumHits());

    if (senseiProtoResult.hasTotalDocs())
      senseiResult.setTotalDocs((int) senseiProtoResult.getTotalDocs());

    if (senseiProtoResult.getGroupAccessibleCount() > 0) {
      List<SenseiProtos.FacetAccessible> groupAccessibleList = senseiProtoResult.getGroupAccessibleList();
      FacetAccessible[] facetAccessibles = new FacetAccessible[groupAccessibleList.size()];
      int i = 0;
      for (SenseiProtos.FacetAccessible protoFacetAccessible : groupAccessibleList) {
        FacetAccessible facetAccessible = convertFacetAccessible(protoFacetAccessible);
        facetAccessibles[i++] = facetAccessible;
      }

      senseiResult.setGroupAccessibles(facetAccessibles);

    }

    if (senseiProtoResult.hasFacetMap()) {
      senseiResult.addAll(convertFacetMap(senseiProtoResult.getFacetMap()));
    }

    if (senseiProtoResult.hasTime())
      senseiResult.setTime(senseiProtoResult.getTime());

    if (senseiProtoResult.hasMapReduceResult())
      senseiResult.setMapReduceResult(convertMapReduceResult(senseiProtoResult.getMapReduceResult()));

    if (senseiProtoResult.getErrorCount() > 0) {
      List<SenseiProtos.SenseiError> errorList = senseiProtoResult.getErrorList();
      for(SenseiProtos.SenseiError error : errorList) {
        senseiResult.addError(convert(error));
      }
    }

    return senseiResult;
  }


  private SenseiProtos.BooleanOperator convertOperator(BrowseSelection.ValueOperation valueOperation) {
    switch (valueOperation) {
      case ValueOperationAnd:
        return SenseiProtos.BooleanOperator.AND;
      case ValueOperationOr:
        return SenseiProtos.BooleanOperator.OR;
      default:
        throw new IllegalArgumentException();
    }
  }

  private BrowseSelection.ValueOperation convertOperator(SenseiProtos.BooleanOperator valueOperation) {
    switch (valueOperation) {
      case AND:
        return BrowseSelection.ValueOperation.ValueOperationAnd;
      case OR:
        return BrowseSelection.ValueOperation.ValueOperationOr;
      default:
        throw new IllegalArgumentException();
    }
  }

  private SenseiProtos.StringProperties convertProperties(Map<?, ?> map) {
    SenseiProtos.StringProperties.Builder stringPropertiesBuilder = SenseiProtos.StringProperties.newBuilder();
    for (Map.Entry<?, ?> entry : map.entrySet()) {
      String key = entry.getKey().toString();
      String value = entry.getValue().toString();
      stringPropertiesBuilder.addKey(key);
      stringPropertiesBuilder.addValue(value);
    }
    return stringPropertiesBuilder.build();
  }

  private Map<String, String> convertProperties(SenseiProtos.StringProperties stringProperties) {
    Map<String, String> results = new HashMap<String, String>();
    for (int i = 0; i < stringProperties.getKeyCount(); i++) {
      results.put(stringProperties.getKey(i), stringProperties.getValue(i));
    }
    return results;
  }

  private SenseiProtos.BrowseSelection convertBrowseSelection(BrowseSelection browseSelection) {
    BrowseSelection.ValueOperation selectionOperation = browseSelection.getSelectionOperation();

    return SenseiProtos.BrowseSelection.newBuilder().setOperator(convertOperator(selectionOperation)).setFieldName(
        browseSelection.getFieldName()).addAllValue(browseSelection.getValues() == null ? Collections.<String>emptyList() : Arrays.asList(
        browseSelection.getValues())).addAllNotValue(browseSelection.getNotValues() == null ? Collections.<String>emptyList() : Arrays.asList(
        browseSelection.getNotValues())).setProperties(convertProperties(browseSelection.getSelectionProperties())).build();
  }

  private BrowseSelection convertBrowseSelection(SenseiProtos.BrowseSelection protoBrowseSelection) {
    BrowseSelection browseSelection = new BrowseSelection(protoBrowseSelection.getFieldName());
    browseSelection.setSelectionOperation(convertOperator(protoBrowseSelection.getOperator()));
    browseSelection.setValues(protoBrowseSelection.getValueList().toArray(new String[]{}));
    browseSelection.setNotValues(protoBrowseSelection.getNotValueList().toArray(new String[]{}));
    browseSelection.setSelectionProperties(convertProperties(protoBrowseSelection.getProperties()));

    return browseSelection;
  }

  private SenseiProtos.Locale convertLocale(Locale locale) {
    String country = locale.getCountry();
    String language = locale.getLanguage();
    String variant = locale.getVariant();

    SenseiProtos.Locale.Builder builder = SenseiProtos.Locale.newBuilder();
    if (country != null)
      builder.setCountry(country);

    if (language != null)
      builder.setLanguage(language);

    if (variant != null)
      builder.setVariant(variant);

    return builder.build();
  }

  private Locale convertLocale(SenseiProtos.Locale locale) {
    String country = locale.hasCountry() ? locale.getCountry() : "";
    String language = locale.hasLanguage() ? locale.getLanguage() : "";
    String variant = locale.hasVariant() ? locale.getVariant() : "";

    return new Locale(language, country, variant);
  }

  private SenseiProtos.SortField convertSortField(SortField sortField) {
    SenseiProtos.SortField.Builder builder = SenseiProtos.SortField.newBuilder();
    if (sortField.getField() != null)
      builder.setField(sortField.getField());

    builder.setType(sortField.getType());

    if (sortField.getLocale() != null)
      builder.setLocale(convertLocale(sortField.getLocale()));

    builder.setReverse(sortField.getReverse());

    return builder.build();
  }

  private SortField convertSortField(SenseiProtos.SortField protoSortField) {
    String field = protoSortField.hasField() ? protoSortField.getField() : null;
    SortField sortField = new SortField(field,
        protoSortField.getType(),
        protoSortField.getReverse());
    return sortField;
  }

  private SenseiProtos.SortOrder convertSortOrder(FacetSpec.FacetSortSpec facetSortSpec) {
    switch (facetSortSpec) {
      case OrderValueAsc:
        return SenseiProtos.SortOrder.ASCENDING;
      case OrderHitsDesc:
        return SenseiProtos.SortOrder.DESCENDING;
      case OrderByCustom:
        return SenseiProtos.SortOrder.CUSTOM;
      default:
        throw new IllegalArgumentException();
    }
  }

  private FacetSpec.FacetSortSpec convertSortOrder(SenseiProtos.SortOrder sortOrder) {
    switch (sortOrder) {
      case ASCENDING:
        return FacetSpec.FacetSortSpec.OrderValueAsc;
      case DESCENDING:
        return FacetSpec.FacetSortSpec.OrderHitsDesc;
      case CUSTOM:
        return FacetSpec.FacetSortSpec.OrderByCustom;
      default:
        throw new IllegalArgumentException();
    }
  }

  private SenseiProtos.FacetSpec convertFacetSpec(String field, FacetSpec facetSpec) {
    return SenseiProtos.FacetSpec.newBuilder().setOrderBy(convertSortOrder(facetSpec.getOrderBy())).setMax(facetSpec.getMaxCount()).setExpandSelection(
        facetSpec.isExpandSelection()).setMinCount(facetSpec.getMinHitCount()).setProperties(convertProperties(facetSpec.getProperties())).setField(
        field).build();
  }

  private Map<String, FacetSpec> convertFacetSpecs(Iterable<SenseiProtos.FacetSpec> facetSpecs) {
    Map<String, FacetSpec> result = new HashMap<String, FacetSpec>();
    for (SenseiProtos.FacetSpec protoFacetSpec : facetSpecs) {
      FacetSpec facetSpec = new FacetSpec();
      facetSpec.setOrderBy(convertSortOrder(protoFacetSpec.getOrderBy()));
      facetSpec.setMaxCount(protoFacetSpec.getMax());
      facetSpec.setExpandSelection(protoFacetSpec.getExpandSelection());
      facetSpec.setMinHitCount(protoFacetSpec.getMinCount());
      facetSpec.setProperties(convertProperties(protoFacetSpec.getProperties()));
      result.put(protoFacetSpec.getField(), facetSpec);
    }
    return result;
  }

  private SenseiProtos.SenseiMapReduceFunction convertMapReduce(SenseiMapReduce mapReduce) {
    if (mapReduce instanceof AvgMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.AVG;
    } else if (mapReduce instanceof CountGroupByMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.COUNT_GROUP_BY;
    } else if (mapReduce instanceof DistinctCountMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.DISTINCT_COUNT;
    } else if (mapReduce instanceof DistinctUIDCount) {
      return SenseiProtos.SenseiMapReduceFunction.DISTINCT_UID;
    } else if (mapReduce instanceof FacetCountsMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.FACET_COUNTS;
    } else if (mapReduce instanceof HashSetDistinctCountMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.HASH_SET_DISTINCT_COUNT;
    } else if (mapReduce instanceof MaxMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.MAX;
    } else if (mapReduce instanceof MinMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.MIN;
    } else if (mapReduce instanceof SumMapReduce) {
      return SenseiProtos.SenseiMapReduceFunction.SUM;
    } else {
      return SenseiProtos.SenseiMapReduceFunction.UNKNOWN;
    }
  }

  private SenseiMapReduce convertMapReduce(SenseiProtos.SenseiMapReduceFunction mapReduce) {
    switch (mapReduce) {
      case AVG:
        return new AvgMapReduce();
      case COUNT_GROUP_BY:
        return new CountGroupByMapReduce();
      case DISTINCT_COUNT:
        return new DistinctCountMapReduce();
      case DISTINCT_UID:
        return new DistinctUIDCount();
      case FACET_COUNTS:
        return new FacetCountsMapReduce();
      case HASH_SET_DISTINCT_COUNT:
        return new HashSetDistinctCountMapReduce();
      case MAX:
        return new MaxMapReduce();
      case MIN:
        return new MinMapReduce();
      case SUM:
        return new SumMapReduce();
      case UNKNOWN:
        return null;
      default:
        throw new IllegalArgumentException("Cannot translate " + mapReduce + " from protobuf");
    }
  }

  private SenseiProtos.FacetHandlerInitializerParams convertFacetParams(Map<String, FacetHandlerInitializerParam> facetHandlerInitializerParamMap) {
    SenseiProtos.FacetHandlerInitializerParams.Builder builder = SenseiProtos.FacetHandlerInitializerParams.newBuilder();
    for (Map.Entry<String, FacetHandlerInitializerParam> entry : facetHandlerInitializerParamMap.entrySet()) {
      builder.addKey(entry.getKey());
      builder.addValue(convertFacetParam(entry.getValue()));
    }
    return builder.build();
  }

  private Map<String, FacetHandlerInitializerParam> convertFacetParams(SenseiProtos.FacetHandlerInitializerParams protoFacetHandlerInitializerParams) {
    Map<String, FacetHandlerInitializerParam> result = new HashMap<String, FacetHandlerInitializerParam>();
    for (int i = 0; i < protoFacetHandlerInitializerParams.getKeyCount(); i++) {
      result.put(protoFacetHandlerInitializerParams.getKey(i),
          convertFacetParam(protoFacetHandlerInitializerParams.getValue(i)));
    }
    return result;
  }

  private SenseiProtos.FacetHandlerInitializerParam convertFacetParam(FacetHandlerInitializerParam facetHandlerInitializerParam) {
    SenseiProtos.FacetHandlerInitializerParam.Builder protoParams = SenseiProtos.FacetHandlerInitializerParam.newBuilder();

    for (String paramName : facetHandlerInitializerParam.getBooleanParamNames()) {
      SenseiProtos.BooleanParams.Builder paramBuilder = SenseiProtos.BooleanParams.newBuilder();
      paramBuilder.setKey(paramName);
      boolean[] param = facetHandlerInitializerParam.getBooleanParam(paramName);
      if(param != null) {
        for (int i = 0; i < param.length; i++) {
          paramBuilder.addValue(param[i]);
        }
      } else {
        paramBuilder.setIsNull(true);
      }
      protoParams.addBooleanParam(paramBuilder.build());
    }

    for (String paramName : facetHandlerInitializerParam.getIntParamNames()) {
      SenseiProtos.IntParams.Builder paramBuilder = SenseiProtos.IntParams.newBuilder();
      paramBuilder.setKey(paramName);
      int[] param = facetHandlerInitializerParam.getIntParam(paramName);
      if (param != null) {
        for (int i = 0; i < param.length; i++) {
          paramBuilder.addValue(param[i]);
        }
      } else {
        paramBuilder.setIsNull(true);
      }

      protoParams.addIntParam(paramBuilder.build());
    }

    for (String paramName : facetHandlerInitializerParam.getLongParamNames()) {
      SenseiProtos.LongParams.Builder paramBuilder = SenseiProtos.LongParams.newBuilder();
      paramBuilder.setKey(paramName);
      long[] param = facetHandlerInitializerParam.getLongParam(paramName);
      if (param != null) {
        for (int i = 0; i < param.length; i++) {
          paramBuilder.addValue(param[i]);
        }
      } else {
        paramBuilder.setIsNull(true);
      }
      protoParams.addLongParam(paramBuilder.build());
    }

    for (String paramName : facetHandlerInitializerParam.getDoubleParamNames()) {
      SenseiProtos.DoubleParams.Builder paramBuilder = SenseiProtos.DoubleParams.newBuilder();
      paramBuilder.setKey(paramName);
      double[] param = facetHandlerInitializerParam.getDoubleParam(paramName);
      if (param != null) {
        for (int i = 0; i < param.length; i++) {
          paramBuilder.addValue(param[i]);
        }
      }  else {
        paramBuilder.setIsNull(true);
      }

      protoParams.addDoubleParam(paramBuilder.build());
    }

    for (String paramName : facetHandlerInitializerParam.getStringParamNames()) {
      SenseiProtos.StringParams.Builder paramBuilder = SenseiProtos.StringParams.newBuilder();
      paramBuilder.setKey(paramName);
      List<String> param = facetHandlerInitializerParam.getStringParam(paramName);
      if (param != null) {
        paramBuilder.addAllValue(param);
      } else {
        paramBuilder.setIsNull(true);
      }

      protoParams.addStringParam(paramBuilder.build());
    }

    for (String paramName : facetHandlerInitializerParam.getByteArrayParamNames()) {
      SenseiProtos.ByteArrayParams.Builder paramBuilder = SenseiProtos.ByteArrayParams.newBuilder();
      paramBuilder.setKey(paramName);
      byte[] param = facetHandlerInitializerParam.getByteArrayParam(paramName);
      if (param != null) {
        for (int i = 0; i < param.length; i++) {
          paramBuilder.setValue(ByteString.copyFrom(param));
        }
      } else {
        paramBuilder.setIsNull(true);
      }
      protoParams.addByteParam(paramBuilder.build());
    }

    return protoParams.build();
  }

  private FacetHandlerInitializerParam convertFacetParam(SenseiProtos.FacetHandlerInitializerParam protoFacetHandlerInitializerParam) {
    DefaultFacetHandlerInitializerParam facetHandlerInitializerParam = new DefaultFacetHandlerInitializerParam();

    for (SenseiProtos.BooleanParams param : protoFacetHandlerInitializerParam.getBooleanParamList()) {
      boolean[] value = null;
      if(!param.getIsNull()) {
        value = new boolean[param.getValueCount()];
        for (int i = 0; i < value.length; i++) {
          value[i] = param.getValue(i);
        }
      }
      facetHandlerInitializerParam.putBooleanParam(param.getKey(), value);
    }

    for (SenseiProtos.IntParams param : protoFacetHandlerInitializerParam.getIntParamList()) {
      int[] value = null;

      if (!param.getIsNull()) {
        value = new int[param.getValueCount()];
        for (int i = 0; i < value.length; i++) {
          value[i] = param.getValue(i);
        }
      }
      facetHandlerInitializerParam.putIntParam(param.getKey(), value);
    }

    for (SenseiProtos.LongParams param : protoFacetHandlerInitializerParam.getLongParamList()) {
      long[] value = null;
      if (!param.getIsNull()) {
        value = new long[param.getValueCount()];
        for (int i = 0; i < value.length; i++) {
          value[i] = param.getValue(i);
        }
      }
      facetHandlerInitializerParam.putLongParam(param.getKey(), value);
    }

    for (SenseiProtos.StringParams param : protoFacetHandlerInitializerParam.getStringParamList()) {
      List<String> value = null;
      if(!param.getIsNull()) {
        value = param.getValueList();
      }
      facetHandlerInitializerParam.putStringParam(param.getKey(), value);
    }

    for (SenseiProtos.DoubleParams param : protoFacetHandlerInitializerParam.getDoubleParamList()) {
      double[] value = null;
      if (!param.getIsNull()) {
        value = new double[param.getValueCount()];
        for (int i = 0; i < value.length; i++) {
          value[i] = param.getValue(i);
        }
      }
      facetHandlerInitializerParam.putDoubleParam(param.getKey(), value);
    }

    for (SenseiProtos.StringParams param : protoFacetHandlerInitializerParam.getStringParamList()) {
      List<String> value = null;
      if (!param.getIsNull()) {
        value = param.getValueList();
      }
      facetHandlerInitializerParam.putStringParam(param.getKey(), value);
    }

    for (SenseiProtos.ByteArrayParams param : protoFacetHandlerInitializerParam.getByteParamList()) {
      ByteString value = null;
      if (!param.getIsNull()) {
        value = param.getValue();
      }
      facetHandlerInitializerParam.putByteArrayParam(param.getKey(), value.toByteArray());
    }

    return facetHandlerInitializerParam;
  }
}
TOP

Related Classes of com.senseidb.search.req.SenseiRequestProtoSerializer

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.