/** * Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com) * * 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 com.linkedin.pinot.core.data; import com.linkedin.pinot.common.data.RowEvent; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * A plain implementation of RowEvent based on HashMap. Should be reused as much as possible via * {@link GenericRow#createOrReuseRow(GenericRow)} */ public class GenericRow implements RowEvent { private Map<String, Object> _fieldMap = new HashMap<String, Object>(); private static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public void init(Map<String, Object> field) { _fieldMap = field; } public Set<Map.Entry<String, Object>> getEntrySet() { return _fieldMap.entrySet(); } @Override public String[] getFieldNames() { return _fieldMap.keySet().toArray(new String[_fieldMap.size()]); } @Override public Object getValue(String fieldName) { return _fieldMap.get(fieldName); } public void putField(String key, Object value) { _fieldMap.put(key, value); } @Override public String toString() { StringBuilder b = new StringBuilder(); for (String key : _fieldMap.keySet()) { Object value = _fieldMap.get(key); b.append(key); b.append(" : "); if (value instanceof Object[]) { b.append(Arrays.toString((Object[]) value)); } else { b.append(value); } b.append(", "); } return b.toString(); } @Override public int hashCode() { return _fieldMap.hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof GenericRow)) { return false; } GenericRow r = (GenericRow) o; return _fieldMap.equals(r._fieldMap); } /** * Empties the values of this generic row, keeping the keys and hash map nodes to minimize object allocation. */ public void clear() { for (Map.Entry<String, Object> mapEntry : getEntrySet()) { mapEntry.setValue(null); } } static TypeReference typeReference = new TypeReference<Map<String, Object>>() {}; public static GenericRow fromBytes(byte[] buffer) throws IOException { Map<String, Object> fieldMap = (Map<String, Object>) OBJECT_MAPPER.readValue(buffer, typeReference); GenericRow genericRow = new GenericRow(); genericRow.init(fieldMap); return genericRow; } public byte[] toBytes() throws IOException { StringWriter writer = new StringWriter(); OBJECT_MAPPER.writeValue(writer, _fieldMap); return writer.toString().getBytes(Charset.forName("UTF-8")); } /** * Creates a new row if the row given is null, otherwise just {@link GenericRow#clear()} the row so that it can be * reused. * * @param row The row to potentially reuse. * @return A cleared or new row. */ public static GenericRow createOrReuseRow(GenericRow row) { if (row == null) { return new GenericRow(); } else { row.clear(); return row; } } }