Package com.cloudhopper.mq.util

Source Code of com.cloudhopper.mq.util.CompositeKeyUtil

package com.cloudhopper.mq.util;

/*
* #%L
* ch-mq
* %%
* Copyright (C) 2012 Cloudhopper by Twitter
* %%
* 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.
* #L%
*/

import com.cloudhopper.mq.util.CompositeKey;

/**
* A utility class for working with CompositeKey instances.  Methods for
* encoding, decoding, and comparing their values.
*
* @author joelauer
*/
public class CompositeKeyUtil {
    //
    // ranges of values for unsigned
    //
    // 1 byte: 0-255
    // 2 bytes: 0-65535
    // 3 bytes: 0-16,777,215
    // 4 bytes: 0-4,294,967,295
    // 5 bytes: 0-1,099,511,627,775
    // 6 bytes: 0-281,474,976,710,655
    // 7 bytes: 0-72,057,594,037,927,935
    // 8 bytes: 0-18,446,744,073,709,551,615
    // 8 bytes (signed): 9,223,372,036,854,775,808
    private final int queueIdByteLength;
    private final int itemIdByteLength;

    /**
     * Creates a utility class for working with CompositeKeys.
     * @param queueIdByteLength The number of bytes to use when encoding/decoding
     *      the CompositeKey.  Valid number of bytes is 1 to 3.  If 1 byte, the
     *      queueId can range from 0-255, if 2 bytes can range from 0-65535, and
     *      if 3 bytes can range from 0-16,777,215.
     * @param itemIdByteLength The number of bytes to use when encoding/decoding
     *      the CompositeKey.  Valid number of bytes is 1 to 7.  If 1 byte, max
     *      value of 255 items.  If 2 bytes, max value of 65535 items.  If 3 bytes,
     *      max value of 16,777,215 items.  If 4 bytes, max value of 4,294,967,295 items.
     *      If 5 bytes, max value of 1,099,511,627,775 items.  If 6 bytes, max value
     *      of 281,474,976,710,655 items.  If 7 bytes, max value of 72,057,594,037,927,935 items.
     */
    public CompositeKeyUtil(int queueIdByteLength, int itemIdByteLength) {
        this.queueIdByteLength = queueIdByteLength;
        this.itemIdByteLength = itemIdByteLength;
        // these methods validate the lengths
        getMaxQueueId();
        getMaxItemId();
    }

    public int getQueueIdByteLength() {
        return this.queueIdByteLength;
    }

    public int getItemIdByteLength() {
        return this.itemIdByteLength;
    }

    public int getByteLength() {
        return (this.queueIdByteLength + this.itemIdByteLength);
    }

    /**
     * Based on configured number of bytes for queueId length, returns the maximum
     * possible value for a queueId.
     * @return The maximum possible value for a queueId based on configured number
     *      of bytes.
     */
    public int getMaxQueueId() {
        return getMaxQueueId(queueIdByteLength);
    }

    static public int getMaxQueueId(int byteLength) {
        if (byteLength == 1) {
            return 255;
        } else if (byteLength == 2) {
            return 65535;
        } else if (byteLength == 3) {
            return 16777215;
        } else {
            throw new IllegalArgumentException("Invalid byteLength for queueId (min=1, max=3)");
        }
    }

    static public int getQueueIdByteLength(int maxQueues) {
        for (int i = 1; i <= 3; i++) {
            int maxQueueSize = getMaxQueueId(i) + 1;
            if (maxQueueSize >= maxQueues) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Based on configured number of bytes for itemId length, returns the maximum
     * possible value for a itemId.  If 1 byte, this would return 255.  For the
     * total maximum number of elements, add 1 to find the count.
     * @return The maximum possible value for a itemId based on configured number
     *      of bytes.
     */
    public long getMaxItemId() {
        if (itemIdByteLength == 1) {
            return 255;
        } else if (itemIdByteLength == 2) {
            return 65535;
        } else if (itemIdByteLength == 3) {
            return 16777215;
        } else if (itemIdByteLength == 4) {
            return 4294967295L;
        } else if (itemIdByteLength == 5) {
            return 1099511627775L;
        } else if (itemIdByteLength == 6) {
            return 281474976710655L;
        } else if (itemIdByteLength == 7) {
            return 72057594037927935L;
        } else {
            throw new IllegalArgumentException("Invalid number of bytes configured for itemId (min=1, max=7)");
        }
    }
   
   
    static public long getMaxItemId(int byteLength) {
        if (byteLength == 1) {
            return 255;
        } else if (byteLength == 2) {
            return 65535;
        } else if (byteLength == 3) {
            return 16777215;
        } else if (byteLength == 4) {
            return 4294967295L;
        } else if (byteLength == 5) {
            return 1099511627775L;
        } else if (byteLength == 6) {
            return 281474976710655L;
        } else if (byteLength == 7) {
            return 72057594037927935L;
        } else {
            throw new IllegalArgumentException("Invalid number of bytes configured for itemId (min=1, max=7)");
        }
    }


    static public int getItemIdByteLength(long itemsPerQueue) {
        for (int i = 1; i <= 7; i++) {
            long maxItemsPerQueue = getMaxItemId(i) + 1;
            if (maxItemsPerQueue >= itemsPerQueue) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Gets the maximum number of items this composite key can store.  Internally,
     * this returns getMaxItemId() + 1.
     * @return The maximum number of items that can be represented by this key
     */
    public long getMaxItems() {
        return getMaxItemId() + 1;
    }

    public byte[] encode(CompositeKey key) {
        return encode(key.getQueueId(), key.getItemId());
    }

    public byte[] encode(int queueId, long itemId) {
        if (queueId < 0 || queueId > getMaxQueueId()) {
            throw new IllegalArgumentException("Invalid queueId value " + queueId + " (either negative or greater than " + getMaxQueueId());
        }
        if (itemId < 0 || itemId > getMaxItemId()) {
            throw new IllegalArgumentException("Invalid itemId value " + itemId + " (either negative or greater than " + getMaxItemId());
        }

        byte[] encoded = new byte[queueIdByteLength+itemIdByteLength];

        // shift queueId into byte array
        for (int i = 0; i < queueIdByteLength; i++) {
            encoded[i] = (byte)(queueId >>> ((queueIdByteLength-1-i) * 8));
        }

        // shift itemId into byte array
        for (int i = 0; i < itemIdByteLength; i++) {
            encoded[queueIdByteLength+i] = (byte)(itemId >>> ((itemIdByteLength-1-i) * 8));
        }

        return encoded;
    }

    public CompositeKey decode(byte[] encoded) {
        int queueId = decodeQueueId(encoded);
        long itemId = decodeItemId(encoded);
        return new CompositeKey(queueId, itemId);
    }

    public int decodeQueueId(byte[] encoded) {
        if (encoded == null) {
            throw new NullPointerException("Encoded byte array cannot be null");
        }

        if (encoded.length != getByteLength()) {
            throw new IllegalArgumentException("Encoded byte array must be " + getByteLength() + " bytes in length [actual=" + encoded.length + "]");
        }

        int queueId = 0;

        for (int i = 0; i < queueIdByteLength; i++) {
            queueId |= ((encoded[i] & 0xFF) << (queueIdByteLength-1-i) * 8);
        }

        return queueId;
    }

    public long decodeItemId(byte[] encoded) {
        if (encoded == null) {
            throw new NullPointerException("Encoded byte array cannot be null");
        }

        if (encoded.length != getByteLength()) {
            throw new IllegalArgumentException("Encoded byte array must be " + getByteLength() + " bytes in length [actual=" + encoded.length + "]");
        }

        long itemId = 0;

        for (int i = 0; i < itemIdByteLength; i++) {
            itemId |= ((encoded[i+queueIdByteLength] & 0xFF) << (itemIdByteLength-1-i) * 8);
        }

        return itemId;
    }

}
TOP

Related Classes of com.cloudhopper.mq.util.CompositeKeyUtil

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.