001/* 
002 * This file is part of the Kompics component model runtime.
003 *
004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS) 
005 * Copyright (C) 2009 Royal Institute of Technology (KTH)
006 *
007 * This program is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU General Public License
009 * as published by the Free Software Foundation; either version 2
010 * of the License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with this program; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
020 */
021package se.sics.kompics.network.netty.serialization;
022
023import java.util.Optional;
024import com.google.protobuf.ExtensionRegistry;
025import com.google.protobuf.InvalidProtocolBufferException;
026import com.google.protobuf.MessageLite;
027import io.netty.buffer.ByteBuf;
028
029/**
030 *
031 * @author Lars Kroll {@literal <[email protected]>}
032 */
033public class ProtobufSerializer implements Serializer {
034
035    private static final boolean HAS_PARSER;
036
037    static {
038        boolean hasParser = false;
039        try {
040            // MessageLite.getParsetForType() is not available until protobuf 2.5.0.
041            MessageLite.class.getDeclaredMethod("getParserForType");
042            hasParser = true;
043        } catch (Throwable t) {
044            // Ignore
045        }
046
047        HAS_PARSER = hasParser;
048    }
049
050    private final MessageLite prototype;
051    private final ExtensionRegistry extensionRegistry;
052
053    public ProtobufSerializer(MessageLite prototype) {
054        this(prototype, null);
055    }
056
057    public ProtobufSerializer(MessageLite prototype, ExtensionRegistry extensionRegistry) {
058        if (prototype == null) {
059            throw new NullPointerException("prototype");
060        }
061        this.prototype = prototype.getDefaultInstanceForType();
062        this.extensionRegistry = extensionRegistry;
063    }
064
065    @Override
066    public int identifier() {
067        return 4;
068    }
069
070    @Override
071    public void toBinary(Object msg, ByteBuf buf) {
072        if (msg instanceof MessageLite) {
073            byte[] bytes = ((MessageLite) msg).toByteArray();
074            buf.writeBytes(bytes);
075            return;
076        }
077        if (msg instanceof MessageLite.Builder) {
078            byte[] bytes = ((MessageLite.Builder) msg).build().toByteArray();
079            buf.writeBytes(bytes);
080            return;
081        }
082    }
083
084    @Override
085    public Object fromBinary(ByteBuf msg, Optional<Object> hint) {
086        final byte[] array;
087        final int offset;
088        final int length = msg.readableBytes();
089        if (msg.hasArray()) {
090            array = msg.array();
091            offset = msg.arrayOffset() + msg.readerIndex();
092        } else {
093            array = new byte[length];
094            msg.getBytes(msg.readerIndex(), array, 0, length);
095            offset = 0;
096        }
097
098        Object o = null;
099        try {
100            if (extensionRegistry == null) {
101                if (HAS_PARSER) {
102                    o = prototype.getParserForType().parseFrom(array, offset, length);
103                } else {
104                    o = prototype.newBuilderForType().mergeFrom(array, offset, length).build();
105                }
106            } else {
107                if (HAS_PARSER) {
108                    o = prototype.getParserForType().parseFrom(array, offset, length, extensionRegistry);
109                } else {
110                    o = prototype.newBuilderForType().mergeFrom(array, offset, length, extensionRegistry).build();
111                }
112            }
113        } catch (InvalidProtocolBufferException ex) {
114            Serializers.LOG.error("ProtobufSerializer: Couldn't deserialize object.", ex);
115        }
116
117        return o;
118    }
119
120}