Package co.cask.cdap.common.stream

Source Code of co.cask.cdap.common.stream.StreamEventTypeAdapter

/*
* Copyright © 2014 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.common.Bytes;
import co.cask.cdap.api.flow.flowlet.StreamEvent;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

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

/**
* A GSon {@link TypeAdapter} for serializing/deserializing {@link StreamEvent} to/from JSON. It serializes
*
* StreamEvent into
* <p/>
* {@code {"timestamp": ... , "headers": { ... }, "body": ... }}
* <p/>
* where the the body is encoded as string binary using Bytes.toStringBinary
*/
public class StreamEventTypeAdapter extends TypeAdapter<StreamEvent> {

  private static final TypeToken<Map<String, String>> HEADERS_TYPE = new TypeToken<Map<String, String>>() { };

  private final TypeAdapter<Map<String, String>> mapTypeAdapter;

  /**
   * Register an instance of the {@link StreamEventTypeAdapter} to the given {@link GsonBuilder}.
   * @param gsonBuilder The build to register to
   * @return The same {@link GsonBuilder} instance in the argument
   */
  public static GsonBuilder register(GsonBuilder gsonBuilder) {
    return gsonBuilder.registerTypeAdapterFactory(new TypeAdapterFactory() {
      @Override
      @SuppressWarnings("unchecked")
      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (StreamEvent.class.isAssignableFrom(type.getRawType())) {
          return (TypeAdapter<T>) new StreamEventTypeAdapter(gson.getAdapter(HEADERS_TYPE));
        }
        return null;
      }
    });
  }

  private StreamEventTypeAdapter(TypeAdapter<Map<String, String>> mapTypeAdapter) {
    this.mapTypeAdapter = mapTypeAdapter;
  }

  @Override
  public void write(JsonWriter out, StreamEvent event) throws IOException {
    out.beginObject()
       .name("timestamp").value(event.getTimestamp())
       .name("headers");
    mapTypeAdapter.write(out, event.getHeaders());

    out.name("body");
    ByteBuffer body = event.getBody();
    if (body.hasArray()) {
      // Need to use ByteBuffer.slice() to make sure position starts at 0, which the toStringBinary requires.
      out.value(Bytes.toStringBinary(body.slice()));
    } else {
      // Slow path, if the byte buffer doesn't have array
      byte[] bytes = new byte[body.remaining()];
      body.mark();
      body.get(bytes);
      body.reset();
      out.value(Bytes.toStringBinary(bytes));
    }
    out.endObject();
  }

  @Override
  public StreamEvent read(JsonReader in) throws IOException {
    long timestamp = -1;
    Map<String, String> headers = null;
    ByteBuffer body = null;

    in.beginObject();
    while (in.peek() == JsonToken.NAME) {
      String key = in.nextName();
      if ("timestamp".equals(key)) {
        timestamp = in.nextLong();
      } else if ("headers".equals(key)) {
        headers = mapTypeAdapter.read(in);
      } else if ("body".equals(key)) {
        body = ByteBuffer.wrap(Bytes.toBytesBinary(in.nextString()));
      } else {
        in.skipValue();
      }
    }

    if (timestamp >= 0 && headers != null && body != null) {
      in.endObject();
      return new DefaultStreamEvent(headers, body, timestamp);
    }
    throw new IOException(String.format("Failed to read StreamEvent. Timestamp: %d, headers: %s, body: %s",
                                        timestamp, headers, body));
  }
}
TOP

Related Classes of co.cask.cdap.common.stream.StreamEventTypeAdapter

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.