io.scalecube.socketio.serialization.PacketEncoder.java Source code

Java tutorial

Introduction

Here is the source code for io.scalecube.socketio.serialization.PacketEncoder.java

Source

/**
 * Copyright 2012 Ronen Hamias, Anton Kharenko
 *
 * 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 io.scalecube.socketio.serialization;

import java.io.IOException;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.util.CharsetUtil;
import io.scalecube.socketio.packets.Packet;

/**
 * Class that provides encoding Socket.IO packets according to specification
 * below.
 *
 * <h1>Encoding</h1>
 * <p/>
 * Messages have to be encoded before they're sent. The structure of a message
 * is as follows:
 * <p/>
 * {@code [message type] ':' [message id ('+')] ':' [message endpoint] (':' [message
 * data])}
 * <p/>
 * The message type is a single digit integer.
 * <p/>
 * The message id is an incremental integer, required for ACKs (can be
 * ommitted). If the message id is followed by a {@code +}, the ACK is not handled by
 * socket.io, but by the user instead.
 * <p/>
 * Socket.IO has built-in support for multiple channels of communication (which
 * we call "multiple sockets"). Each socket is identified by an endpoint (can be
 * omitted).
 *
 * @author Anton Kharenko
 *
 */
public final class PacketEncoder {

    private static final String DELIMITER = ":";
    private static final byte[] DELIMITER_BYTES = DELIMITER.getBytes(CharsetUtil.UTF_8);
    private static final int DELIMITER_LENGTH = DELIMITER_BYTES.length;

    /**
     * Don't let anyone instantiate this class.
     */
    private PacketEncoder() {
    }

    public static ByteBuf encodePacket(final Packet packet) throws IOException {
        ByteBuf dataBytes = packet.getData();
        boolean hasData = dataBytes != null;

        CompositeByteBuf compositeByteBuf = PooledByteBufAllocator.DEFAULT.compositeBuffer(hasData ? 1 : 2);

        byte[] typeBytes = packet.getType().getValueAsBytes();
        int headerCapacity = typeBytes.length + DELIMITER_LENGTH + DELIMITER_LENGTH
                + (hasData ? DELIMITER_LENGTH : 0);
        ByteBuf headerByteBuf = PooledByteBufAllocator.DEFAULT.buffer(headerCapacity, headerCapacity);
        headerByteBuf.writeBytes(typeBytes);
        headerByteBuf.writeBytes(DELIMITER_BYTES);
        headerByteBuf.writeBytes(DELIMITER_BYTES);
        if (hasData) {
            headerByteBuf.writeBytes(DELIMITER_BYTES);
        }
        compositeByteBuf.addComponent(headerByteBuf);
        int compositeReadableBytes = headerByteBuf.readableBytes();

        if (hasData) {
            compositeByteBuf.addComponent(dataBytes);
            compositeReadableBytes += dataBytes.readableBytes();
        }

        compositeByteBuf.writerIndex(compositeReadableBytes);
        return compositeByteBuf;
    }
}