All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.cask.cdap.common.stream.StreamEventDataCodec Maven / Gradle / Ivy

There is a newer version: 5.1.2
Show newest version
/*
 * Copyright © 2014-2015 Cask Data, Inc.
 *
 * 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 co.cask.cdap.common.stream;

import co.cask.cdap.api.data.schema.Schema;
import co.cask.cdap.api.data.schema.UnsupportedTypeException;
import co.cask.cdap.api.stream.StreamEventData;
import co.cask.cdap.common.io.Decoder;
import co.cask.cdap.common.io.Encoder;
import co.cask.cdap.internal.io.ReflectionSchemaGenerator;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;

/**
 * Utility class for encode/decode {@link co.cask.cdap.api.stream.StreamEventData}.
 *
 * The StreamEventData is encoded using Avro binary encoding, with the schema:
 *
 * 
 * {
 *   "type": "record",
 *   "name": "StreamEvent",
 *   "fields" : [
 *     {"name": "body", "type": "bytes"},
 *     {"name": "headers", "type": {"type": "map", "values": ["string", "null"]}}
 *   ]
 * }
 * 
* */ public final class StreamEventDataCodec { public static final Schema STREAM_DATA_SCHEMA; static { Schema schema; try { schema = new ReflectionSchemaGenerator().generate(StreamEventData.class); } catch (UnsupportedTypeException e) { // Never happen, as schema can always be generated from StreamEventData. schema = null; } STREAM_DATA_SCHEMA = schema; } /** * Encodes the given {@link StreamEventData} using the {@link Encoder}. * * @param data The data to encode * @param encoder The encoder * @throws IOException If there is any IO error during encoding. */ public static void encode(StreamEventData data, Encoder encoder) throws IOException { // The schema is sorted by name, hence it is {body, header}. // Writes the body encoder.writeBytes(data.getBody()); // Writes the headers Map headers = data.getHeaders(); encoder.writeInt(headers.size()); for (Map.Entry entry : headers.entrySet()) { String value = entry.getValue(); encoder.writeString(entry.getKey()) .writeInt(value == null ? 1 : 0) .writeString(entry.getValue()); } if (!headers.isEmpty()) { encoder.writeInt(0); } } /** * Decodes from the given {@link Decoder} to reconstruct a {@link StreamEventData}. * * @param decoder the decoder to read data from * @return A new instance of {@link co.cask.cdap.api.stream.StreamEventData}. * @throws IOException If there is any IO error during decoding. */ public static StreamEventData decode(Decoder decoder) throws IOException { return decode(decoder, ImmutableMap.of()); } /** * Decodes from the given {@link Decoder} to reconstruct a {@link StreamEventData}. * The set of headers provided is used as the default set of headers. * * @param decoder the decoder to read data from * @param defaultHeaders A map of headers available by default. * @return A new instance of {@link co.cask.cdap.api.stream.StreamEventData}. * @throws IOException If there is any IO error during decoding. */ public static StreamEventData decode(Decoder decoder, Map defaultHeaders) throws IOException { // Reads the body ByteBuffer body = decoder.readBytes(); // Reads the headers int len = decoder.readInt(); // A special optimization for the case where there is no event header. if (len == 0) { return new StreamEventData(defaultHeaders, body); } Map headers = defaultHeaders.isEmpty() ? Maps.newHashMap() : Maps.newHashMap(defaultHeaders); do { for (int i = 0; i < len; i++) { String key = decoder.readString(); String value = decoder.readInt() == 0 ? decoder.readString() : (String) decoder.readNull(); headers.put(key, value); } len = decoder.readInt(); } while (len != 0); return new StreamEventData(headers, body); } /** * Skips an encoded {@link co.cask.cdap.api.stream.StreamEventData}. * * @param decoder Decoder to skip data from. * @throws IOException If there is any IO error during decoding. */ public static void skip(Decoder decoder) throws IOException { // Skips the body decoder.skipBytes(); // Skips the headers int len = decoder.readInt(); while (len != 0) { for (int i = 0; i < len; i++) { decoder.skipString(); if (decoder.readInt() == 0) { decoder.skipString(); } else { decoder.readNull(); } } len = decoder.readInt(); } } private StreamEventDataCodec() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy