com.delphix.session.impl.frame.SerialNumber.java Source code

Java tutorial

Introduction

Here is the source code for com.delphix.session.impl.frame.SerialNumber.java

Source

/**
 * 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.
 */

/**
 * Copyright (c) 2013 by Delphix. All rights reserved.
 */

package com.delphix.session.impl.frame;

import org.apache.commons.lang.builder.HashCodeBuilder;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

/**
 * This describes the serial number as defined in RFC 1982.
 *
 * Serial numbers are formed from non-negative integers from a finite subset of the range of all integer values.  The
 * lowest integer in every subset used for this purpose is zero, the maximum is always one less than a power of two.
 *
 * When considered as serial numbers however no value has any particular significance, there is no minimum or maximum
 * serial number, every value has a successor and predecessor.
 *
 * To define a serial number to be used in this way, the size of the serial number space must be given.  This value,
 * called "SERIAL_BITS", gives the power of two which results in one larger than the largest integer corresponding to
 * a serial number value.  This also specifies the number of bits required to hold every possible value of a serial
 * number of the defined type.  The operations permitted upon serial numbers are defined in the following section.
 *
 * Only two operations are defined upon serial numbers, addition of a positive integer of limited range, and comparison
 * with another serial number.
 *
 * The simplest meaningful serial number space has SERIAL_BITS == 2. In this space, the integers that make up the
 * serial number space are 0, 1, 2, and 3. That is, 3 == 2 ^ SERIAL_BITS - 1. In this space, the largest integer that
 * it is meaningful to add to a sequence number is 2 ^ (SERIAL_BITS - 1) - 1, or 1. Then, as defined 0 + 1 == 1,
 * 1 + 1 == 2, 2 + 1 == 3, and 3 + 1 == 0. Further, 1 > 0, 2 > 1, 3 > 2, and 0 > 3. It is undefined whether 2 > 0 or
 * 0 > 2, and whether 1 > 3 or 3 > 1.
 */
public class SerialNumber implements Comparable<SerialNumber>, Externalizable {

    // Zero sequences that fit snugly into the corresponding signed java primitive type
    public static final SerialNumber ZERO_SEQUENCE_BYTE = new SerialNumber(7);
    public static final SerialNumber ZERO_SEQUENCE_SHORT = new SerialNumber(15);
    public static final SerialNumber ZERO_SEQUENCE_INTEGER = new SerialNumber(31);
    public static final SerialNumber ZERO_SEQUENCE_LONG = new SerialNumber(63);

    private static final int MINIMUM_SERIAL_BITS = 1;
    private static final int MAXIMUM_SERIAL_BITS = 63;
    private static final int DEFAULT_SERIAL_BITS = 31;

    private int serialBits;
    private long serialNumber;

    private SerialNumber() {

    }

    public SerialNumber(long serialNumber) {
        this(DEFAULT_SERIAL_BITS, serialNumber);
    }

    public SerialNumber(int serialBits) {
        this(serialBits, 0);
    }

    public SerialNumber(SerialNumber sn) {
        this(sn.serialBits, sn.serialNumber);
    }

    public SerialNumber(int serialBits, long serialNumber) {
        if (serialBits < MINIMUM_SERIAL_BITS || serialBits > MAXIMUM_SERIAL_BITS) {
            throw new IllegalArgumentException("serial bits " + serialBits + " out of range");
        }

        if (serialNumber < 0 || serialNumber > (1L << serialBits) - 1) {
            throw new IllegalArgumentException("serial number " + serialNumber + " out of range");
        }

        this.serialBits = serialBits;
        this.serialNumber = serialNumber;
    }

    public int getSerialBits() {
        return serialBits;
    }

    public long getSerialNumber() {
        return serialNumber;
    }

    private long serialAdd(long val) {
        if (val < 0 || val > (1L << (serialBits - 1)) - 1) {
            throw new IllegalArgumentException("additional value " + val + " out of range");
        }

        return (serialNumber + val) % (1L << serialBits);
    }

    private void increment(long val) {
        serialNumber = serialAdd(val);
    }

    public boolean isNext(SerialNumber sn) {
        return serialBits == sn.serialBits && serialNumber == sn.serialAdd(1);
    }

    public SerialNumber next() {
        return next(1);
    }

    public SerialNumber next(long val) {
        SerialNumber sn = new SerialNumber(this);
        sn.increment(val);
        return sn;
    }

    public boolean greaterThan(SerialNumber sn) {
        if (serialNumber < sn.serialNumber) {
            return sn.serialNumber - serialNumber > (1L << (serialBits - 1));
        } else if (serialNumber > sn.serialNumber) {
            return serialNumber - sn.serialNumber < (1L << (serialBits - 1));
        } else {
            return false;
        }
    }

    public boolean lessThan(SerialNumber sn) {
        if (serialNumber < sn.serialNumber) {
            return sn.serialNumber - serialNumber < (1L << (serialBits - 1));
        } else if (serialNumber > sn.serialNumber) {
            return serialNumber - sn.serialNumber > (1L << (serialBits - 1));
        } else {
            return false;
        }
    }

    public boolean greaterThanOrEqual(SerialNumber sn) {
        if (serialBits == sn.serialBits && serialNumber == sn.serialNumber) {
            return true;
        } else {
            return greaterThan(sn);
        }
    }

    public boolean lessThanOrEqual(SerialNumber sn) {
        if (serialBits == sn.serialBits && serialNumber == sn.serialNumber) {
            return true;
        } else {
            return lessThan(sn);
        }
    }

    @Override
    public int compareTo(SerialNumber sn) {
        if (greaterThan(sn)) {
            return 1;
        } else if (lessThan(sn)) {
            return -1;
        } else {
            return 0;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        if (!(obj instanceof SerialNumber)) {
            return false;
        }

        SerialNumber sn = (SerialNumber) obj;

        return serialBits == sn.serialBits && serialNumber == sn.serialNumber;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(serialBits).append(serialNumber).toHashCode();
    }

    @Override
    public String toString() {
        return "[SN:" + String.valueOf(serialNumber) + "]";
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        serialBits = in.readByte() & 0xff; // Unsigned byte

        if (serialBits < Byte.SIZE) {
            serialNumber = in.readByte();
        } else if (serialBits < Short.SIZE) {
            serialNumber = in.readShort();
        } else if (serialBits < Integer.SIZE) {
            serialNumber = in.readInt();
        } else {
            serialNumber = in.readLong();
        }
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeByte(serialBits);

        if (serialBits < Byte.SIZE) {
            out.writeByte((int) serialNumber);
        } else if (serialBits < Short.SIZE) {
            out.writeShort((int) serialNumber);
        } else if (serialBits < Integer.SIZE) {
            out.writeInt((int) serialNumber);
        } else {
            out.writeLong(serialNumber);
        }
    }

    public static SerialNumber deserialize(ObjectInput in) throws IOException, ClassNotFoundException {
        SerialNumber sn = new SerialNumber();
        sn.readExternal(in);
        return sn;
    }
}