com.hortonworks.registries.schemaregistry.serdes.avro.AvroSnapshotDeserializer.java Source code

Java tutorial

Introduction

Here is the source code for com.hortonworks.registries.schemaregistry.serdes.avro.AvroSnapshotDeserializer.java

Source

/**
 * Copyright 2016 Hortonworks.
 *
 * 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.hortonworks.registries.schemaregistry.serdes.avro;

import com.hortonworks.registries.schemaregistry.serde.AbstractSnapshotDeserializer;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.commons.io.IOUtils;
import com.hortonworks.registries.schemaregistry.SchemaIdVersion;
import com.hortonworks.registries.schemaregistry.SchemaMetadata;
import com.hortonworks.registries.schemaregistry.SchemaVersionInfo;
import com.hortonworks.registries.schemaregistry.SchemaVersionKey;
import com.hortonworks.registries.schemaregistry.avro.AvroSchemaProvider;
import com.hortonworks.registries.schemaregistry.serde.SerDesException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

/**
 *
 */
public class AvroSnapshotDeserializer extends AbstractSnapshotDeserializer<Object, Schema> {
    private static final Logger LOG = LoggerFactory.getLogger(AvroSnapshotDeserializer.class);

    @Override
    protected Schema getParsedSchema(SchemaVersionInfo schemaVersionInfo) {
        return new Schema.Parser().parse(schemaVersionInfo.getSchemaText());
    }

    protected SchemaIdVersion retrieveSchemaIdVersion(InputStream payloadInputStream) throws SerDesException {
        // it can be enhanced to have respective protocol handlers for different versions
        // first byte is protocol version/id.
        // protocol format:
        // 1 byte  : protocol version
        // 8 bytes : schema metadata Id
        // 4 bytes : schema version
        ByteBuffer byteBuffer = ByteBuffer.allocate(13);
        try {
            payloadInputStream.read(byteBuffer.array());
        } catch (IOException e) {
            throw new SerDesException(e);
        }

        byte protocolId = byteBuffer.get();
        if (protocolId != AvroSchemaProvider.CURRENT_PROTOCOL_VERSION) {
            throw new SerDesException(
                    "Unknown protocol id [" + protocolId + "] received while deserializing the payload");
        }
        long schemaMetadataId = byteBuffer.getLong();
        int schemaVersion = byteBuffer.getInt();

        return new SchemaIdVersion(schemaMetadataId, schemaVersion);
    }

    protected Object doDeserialize(InputStream payloadInputStream, SchemaMetadata schemaMetadata,
            Integer writerSchemaVersion, Integer readerSchemaVersion) throws SerDesException {
        Object deserializedObj;
        String schemaName = schemaMetadata.getName();
        SchemaVersionKey writerSchemaVersionKey = new SchemaVersionKey(schemaName, writerSchemaVersion);
        LOG.debug("SchemaKey: [{}] for the received payload", writerSchemaVersionKey);
        try {
            Schema writerSchema = getSchema(writerSchemaVersionKey);
            if (writerSchema == null) {
                throw new SerDesException("No schema exists with metadata-key: " + schemaMetadata
                        + " and writerSchemaVersion: " + writerSchemaVersion);
            }

            Schema.Type writerSchemaType = writerSchema.getType();
            if (Schema.Type.BYTES.equals(writerSchemaType)) {
                // serializer writes byte array directly without going through avro encoder layers.
                deserializedObj = IOUtils.toByteArray(payloadInputStream);
            } else if (Schema.Type.STRING.equals(writerSchemaType)) {
                // generate UTF-8 string object from the received bytes.
                deserializedObj = new String(IOUtils.toByteArray(payloadInputStream), AvroUtils.UTF_8);
            } else {
                int recordType = payloadInputStream.read();
                LOG.debug("Received record type: [{}]", recordType);
                GenericDatumReader datumReader = null;
                Schema readerSchema = readerSchemaVersion != null
                        ? getSchema(new SchemaVersionKey(schemaName, readerSchemaVersion))
                        : null;

                if (recordType == AvroUtils.GENERIC_RECORD) {
                    datumReader = readerSchema != null ? new GenericDatumReader(writerSchema, readerSchema)
                            : new GenericDatumReader(writerSchema);
                } else {
                    datumReader = readerSchema != null ? new SpecificDatumReader(writerSchema, readerSchema)
                            : new SpecificDatumReader(writerSchema);
                }
                deserializedObj = datumReader.read(null,
                        DecoderFactory.get().binaryDecoder(payloadInputStream, null));
            }
        } catch (IOException e) {
            throw new SerDesException(e);
        }

        return deserializedObj;
    }

}