Package org.graylog2.plugin.journal

Source Code of org.graylog2.plugin.journal.RawMessage

/**
* The MIT License
* Copyright (c) 2012 TORCH GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.graylog2.plugin.journal;

import com.eaio.uuid.UUID;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Objects;
import org.graylog2.plugin.Tools;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.nio.charset.StandardCharsets.UTF_8;

/**
* A raw message is the unparsed data Graylog2 was handed by an input.
* <p>
* Typically this is a copy of the exact bytes received over the network, after all de-chunking, removal of transport
* headers, etc has been performed, but before any parsing, decoding, checking of the actual payload has been performed.
* </p>
* <p>
* Each raw message has a unique id, a timestamp it was received at (this might be different from the timestamp contained
* in the payload, if that has any), a tag of what payload type this is supposed to be (e.g. syslog, GELF, RadioMessage etc.),
* as well as an opaque meta data structure.<br>
* The format of the meta data is not stable yet, but will likely be a JSON string.
* </p>
*/
public class RawMessage implements Serializable {

    public static final byte CURRENT_VERSION = 1;

    public static final InetSocketAddress LOCALHOST_ANYPORT = new InetSocketAddress(0);

    private final long sequenceNumber;
    private final byte version;
    private final UUID id;
    private final DateTime timestamp;
    private final String sourceInputId;
    private final InetSocketAddress remoteAddress;
    private final String metaData;
    private final String payloadType;
    private final byte[] payload;
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    public RawMessage(String payloadType,
                      String sourceInputId,
                      InetSocketAddress remoteAddress,
                      byte[] payload) {
        this(payloadType, sourceInputId, remoteAddress, null, payload);
    }

    public RawMessage(String payloadType,
                      String sourceInputId,
                      InetSocketAddress remoteAddress,
                      @Nullable String metaData,
                      byte[] payload) {
        this(Long.MIN_VALUE, new UUID(), Tools.iso8601(), payloadType, sourceInputId, remoteAddress, metaData, payload);
    }

    public RawMessage(long sequenceNumber,
                      UUID id,
                      DateTime timestamp,
                      String payloadType,
                      String sourceInputId,
                      InetSocketAddress remoteAddress,
                      @Nullable String metaData,
                      byte[] payload) {
        this.sequenceNumber = sequenceNumber;
        checkNotNull(payload, "The messsage payload must not be null!");
        checkArgument(payload.length > 0, "The message payload must not be empty!");
        checkArgument(!isNullOrEmpty(payloadType), "The payload type must not be null or empty!");

        this.version = CURRENT_VERSION;
        this.id = id;
        this.timestamp = timestamp;
        this.sourceInputId = sourceInputId;
        this.remoteAddress = Objects.firstNonNull(remoteAddress, LOCALHOST_ANYPORT);
        this.metaData = metaData == null ? "" : metaData;
        this.payloadType = payloadType;
        this.payload = payload.clone();
    }

    public byte[] encode() {
        final byte[] sourceInputIdBytes = sourceInputId.getBytes(UTF_8);
        final byte[] metaDataBytes = metaData.getBytes(UTF_8);
        final byte[] payloadTypeBytes = payloadType.getBytes(UTF_8);

        final int bufferSize =
                1 + /* version */
                        16 + /* UUID is 2 longs */
                        8 + /* timestamp is 1 long, in millis from 1970 */
                        4 + /* source input id length */
                        sourceInputIdBytes.length + /* source input id string. TODO could this be a proper UUID instead? would save many bytes*/
                        1 + /* inet sock address length */
                        remoteAddress.getAddress().getAddress().length + /* inet sock address byte representation */
                        2 + /* source port */
                        4 + /* payload type length */
                        payloadTypeBytes.length + /* utf-8 encoded name of the payload type */
                        4 + /* size of metadata, one int */
                        metaDataBytes.length + /* number of bytes of UTF-8 encoded metadata, or 0 */
                        4 + /* size of payload, one int */
                        payload.length; /* raw length of payload data */

        return ByteBuffer.allocate(bufferSize)
                .put(version)
                .putLong(id.getTime())
                .putLong(id.getClockSeqAndNode())
                .putLong(timestamp.getMillis())
                .putInt(payloadTypeBytes.length)
                .put(payloadTypeBytes)
                .putInt(sourceInputIdBytes.length)
                .put(sourceInputIdBytes)
                .put((byte) (remoteAddress.getAddress() instanceof Inet4Address ? 4 : 16))
                .put(remoteAddress.getAddress().getAddress())
                .putInt(remoteAddress.getPort())
                .putInt(metaDataBytes.length)
                .put(metaDataBytes)
                .putInt(payload.length)
                .put(payload)
                .array();
    }

    public static RawMessage decode(final ByteBuffer buffer, final long sequenceNumber) {

        try {
            final byte version = buffer.get();
            if (version > CURRENT_VERSION) {
                throw new IllegalArgumentException("Cannot decode raw message with version " + version +
                                                           " this decoder only supports up to version " + CURRENT_VERSION);
            }

            final long time = buffer.getLong();
            final long clockSeqAndNode = buffer.getLong();

            final long millis = buffer.getLong();

            final int payloadTypeLength = buffer.getInt();
            final byte[] payloadType = new byte[payloadTypeLength];
            buffer.get(payloadType);

            final int sourceInputLength = buffer.getInt();
            final byte[] sourceInput = new byte[sourceInputLength];
            buffer.get(sourceInput);

            final byte addressLength = buffer.get();
            final byte[] address = new byte[addressLength];
            buffer.get(address);

            final int port = buffer.getInt();

            final int metaDataLength = buffer.getInt();
            final byte[] metaData = new byte[metaDataLength];
            buffer.get(metaData);

            final int payloadLength = buffer.getInt();
            final byte[] payload = new byte[payloadLength];
            buffer.get(payload);

            return new RawMessage(
                    sequenceNumber,
                    new UUID(time, clockSeqAndNode),
                    new DateTime(millis, DateTimeZone.UTC),
                    new String(payloadType, UTF_8),
                    new String(sourceInput, UTF_8),
                    new InetSocketAddress(InetAddress.getByAddress(address), port),
                    new String(metaData, UTF_8),
                    payload);

        } catch (IndexOutOfBoundsException e) {
            throw new IllegalStateException("Cannot decode truncated raw message.", e);
        } catch (UnknownHostException e) {
            throw new IllegalStateException("Cannot decode raw message, malformed InetSockAddress", e);
        }
    }

    public long getSequenceNumber() {
        return sequenceNumber;
    }

    public int getVersion() {
        return version;
    }

    public DateTime getTimestamp() {
        return timestamp;
    }

    public String getSourceInputId() {
        return sourceInputId;
    }

    public InetSocketAddress getRemoteAddress() {
        return remoteAddress;
    }

    public String getMetaData() {
        return metaData;
    }

    @Nonnull
    public Map<String, Object> getParsedMetaData() {
        if (getMetaData() == null) {
            return Collections.emptyMap();
        }
        try {
            return OBJECT_MAPPER.readValue(getMetaData(), new TypeReference<Map<String, Object>>() {});
        } catch (IOException e) {
            return Collections.emptyMap();
        }
    }

    public String getPayloadType() {
        return payloadType;
    }

    public byte[] getPayload() {
        return payload;
    }

    public UUID getId() {
        return id;
    }

    public byte[] getIdBytes() {
        final long time = id.getTime();
        final long clockSeqAndNode = id.getClockSeqAndNode();

        return ByteBuffer.allocate(16)
                .putLong(time)
                .putLong(clockSeqAndNode)
                .array();
    }

    @Override
    public String toString() {
        return "RawMessage{" +
                "version=" + version +
                ", id=" + id +
                ", timestamp=" + timestamp +
                ", sourceInputId='" + sourceInputId + '\'' +
                ", metaData='" + metaData + '\'' +
                ", payloadType='" + payloadType + '\'' +
                ", payload.length=" + payload.length +
                '}';
    }
}
TOP

Related Classes of org.graylog2.plugin.journal.RawMessage

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.