Package com.arjuna.ats.arjuna.common

Source Code of com.arjuna.ats.arjuna.common.Uid

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
/*
* Copyright (C) 1998, 1999, 2000, 2001,
*
* Arjuna Solutions Limited,
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: Uid.java 2342 2006-03-30 13:06:17Z  $
*/

package com.arjuna.ats.arjuna.common;

import com.arjuna.ats.arjuna.utils.Utility;

import java.lang.Cloneable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.Serializable;
import java.io.PrintStream;

import com.arjuna.ats.arjuna.exceptions.FatalError;
import java.io.IOException;
import java.net.UnknownHostException;
import java.lang.StringIndexOutOfBoundsException;
import java.lang.NumberFormatException;
import java.lang.CloneNotSupportedException;
import java.util.concurrent.atomic.AtomicInteger;

import com.arjuna.ats.arjuna.logging.tsLogger;

/**
* Implements a unique identity class. Since 4.9 each instance is immutable.
*
* @author Mark Little (mark@arjuna.com)
* @version $Id: Uid.java 2342 2006-03-30 13:06:17Z $
* @since 1.0.
* @message com.arjuna.ats.arjuna.common.Uid_1
*          [com.arjuna.ats.arjuna.common.Uid_1] - cannot get local host.
* @message com.arjuna.ats.arjuna.common.Uid_2
*          [com.arjuna.ats.arjuna.common.Uid_2] - Uid.Uid string constructor
*          could not create nullUid
* @message com.arjuna.ats.arjuna.common.Uid_3
*          [com.arjuna.ats.arjuna.common.Uid_3] - Uid general parsing error:
*          {0}
* @message com.arjuna.ats.arjuna.common.Uid_4
*          [com.arjuna.ats.arjuna.common.Uid_4] - Uid.Uid string constructor
*          could not create nullUid for incorrect string: {0}
* @message com.arjuna.ats.arjuna.common.Uid_5
*          [com.arjuna.ats.arjuna.common.Uid_5] - Uid.Uid string constructor
*          incorrect: {0}
* @message com.arjuna.ats.arjuna.common.Uid_6
*          [com.arjuna.ats.arjuna.common.Uid_6] - Uid.generateHash called for
*          invalid Uid. Will ignore.
* @message com.arjuna.ats.arjuna.common.Uid_7
*          [com.arjuna.ats.arjuna.common.Uid_7] - nullUid error for
* @message com.arjuna.ats.arjuna.common.Uid_8
*          [com.arjuna.ats.arjuna.common.Uid_8] - Invalid string:
* @message com.arjuna.ats.arjuna.common.Uid_9
*          [com.arjuna.ats.arjuna.common.Uid_9] - Invalid Uid object.
* @message com.arjuna.ats.arjuna.common.Uid_10
*          [com.arjuna.ats.arjuna.common.Uid_10] - Cannot unpack into nullUid!
* @message com.arjuna.ats.arjuna.common.Uid_11
*          [com.arjuna.ats.arjuna.common.Uid_11] - Uid.Uid recreate constructor
*          could not recreate Uid!
* @message com.arjuna.ats.arjuna.common.Uid_npe
*          [com.arjuna.ats.arjuna.common.Uid_npe] - Uid.Uid string constructor {0} caught other throwable: {1}
* @message com.arjuna.ats.arjuna.common.Uid_getbytes
*          [com.arjuna.ats.arjuna.common.Uid_getbytes] - Exception thrown getting bytes!
* @message com.arjuna.ats.arjuna.common.Uid_bytes
*          [com.arjuna.ats.arjuna.common.Uid_bytes] - Exception thrown creating Uid from bytes!
*/

public class Uid implements Cloneable, Serializable
{
    private static final long serialVersionUID = 7808395904206530189L;

    /**
     * Create a new instance.
     */

    public Uid()
    {
        hostAddr = null;
        process = 0;
        sec = 0;
        other = 0;
        _hashValue = -1;
        _valid = false;
        _stringForm = null;
        _byteForm = null;

        try
        {
            hostAddr = Utility.hostInetAddr(); /* calculated only once */
            process = Utility.getpid();

            if (Uid.initTime == 0)
                Uid.initTime = (int) (System.currentTimeMillis() / 1000);

            sec = Uid.initTime;

            other = Uid.getValue();

            _valid = true;

            generateHash();
        }
        catch (UnknownHostException e)
        {
            if (tsLogger.arjLoggerI18N.isWarnEnabled())
                tsLogger.arjLoggerI18N
                        .warn("com.arjuna.ats.arjuna.common.Uid_1");
            _valid = false;
        }
    }

    /**
     * Create a copy of the specified identifier.
     */

    public Uid(Uid copyFrom)
    {
        copy(copyFrom);
    }

    public Uid (byte[] byteForm)
    {
        hostAddr = new long[2];
        _hashValue = -1;
        _stringForm = null;
        _byteForm = null;
       
        try
        {
            ByteArrayInputStream ba = new ByteArrayInputStream(byteForm);
            DataInputStream ds = new DataInputStream(ba);
           
            hostAddr[0] = ds.readLong();
            hostAddr[1] = ds.readLong();
            process = ds.readInt();
            sec = ds.readInt();
            other = ds.readInt();
           
            _valid = true;
        }
        catch (final Throwable ex)
        {
            if (tsLogger.arjLoggerI18N.isWarnEnabled())
                tsLogger.arjLoggerI18N
                        .warn("com.arjuna.ats.arjuna.common.Uid_bytes", ex);
           
            _valid = false;
        }
       
        generateHash();
    }
   
    /**
     * Create Uid from string representation. If the string does not represent a
     * valid Uid then the instance will be set to nullUid.
     */

    public Uid(String uidString)
    {
        this(uidString, true);
    }

    /**
     * Create Uid from string representation. boolean arg says whether to give
     * up if an error is detected or to simply replace with nullUid.
     */

    public Uid(String uidString, boolean errsOk)
    {
        char theBreakChar = Uid.getBreakChar(uidString);

        hostAddr = new long[2];
        process = 0;
        sec = 0;
        other = 0;
        _hashValue = -1;
        _valid = false;
        _stringForm = null;
        _byteForm = null;
       
        if (uidString.length() > 0)
        {
            int startIndex = 0;
            int endIndex = 0;
            String s = null;

            try
            {
                while (uidString.charAt(endIndex) != theBreakChar)
                    endIndex++;

                s = uidString.substring(startIndex, endIndex);
                hostAddr[0] = Utility.hexStringToLong(s);

                startIndex = endIndex + 1;
                endIndex++;
                while (uidString.charAt(endIndex) != theBreakChar)
                    endIndex++;

                s = uidString.substring(startIndex, endIndex);
                hostAddr[1] = Utility.hexStringToLong(s);

                startIndex = endIndex + 1;
                endIndex++;

                while (uidString.charAt(endIndex) != theBreakChar)
                    endIndex++;

                s = uidString.substring(startIndex, endIndex);
                process = (int) Utility.hexStringToLong(s);

                startIndex = endIndex + 1;
                endIndex++;

                while (uidString.charAt(endIndex) != theBreakChar)
                    endIndex++;

                s = uidString.substring(startIndex, endIndex);
                sec = (int) Utility.hexStringToLong(s);

                s = uidString.substring(endIndex + 1, uidString.length());
                other = (int) Utility.hexStringToLong(s);

                _valid = true;

                generateHash();
            }
            catch (NumberFormatException e)
            {
                if (!errsOk)
                {
                    if (tsLogger.arjLoggerI18N.isWarnEnabled())
                    {
                        tsLogger.arjLoggerI18N.warn(
                                "com.arjuna.ats.arjuna.common.Uid_3",
                                new Object[]
                                { uidString }, e);
                    }
                }

                _valid = false;
            }
            catch (StringIndexOutOfBoundsException e)
            {
                if (!errsOk)
                {
                    if (tsLogger.arjLoggerI18N.isWarnEnabled())
                    {
                        tsLogger.arjLoggerI18N.warn(
                                "com.arjuna.ats.arjuna.common.Uid_3", new Object[]
                                { uidString }, e);
                    }
                }

                _valid = false;
            }
            catch (final Throwable ex)
            {
                if (tsLogger.arjLoggerI18N.isWarnEnabled())
                {
                    tsLogger.arjLoggerI18N.warn(
                            "com.arjuna.ats.arjuna.common.Uid_npe", new Object[]
                            { uidString }, ex);
                }

                _valid = false;
            }
        }
        else
        {
            this.copy(Uid.nullUid());
        }

        if (!_valid)
        {
            if (errsOk)
            {
                try
                {
                    this.copy(Uid.nullUid());
                }
                catch (Exception e)
                {
                    if (tsLogger.arjLoggerI18N.isFatalEnabled())
                    {
                        tsLogger.arjLoggerI18N.fatal(
                                "com.arjuna.ats.arjuna.common.Uid_4",
                                new Object[]
                                { uidString });
                    }

                    throw new FatalError(tsLogger.log_mesg
                            .getString("com.arjuna.ats.arjuna.common.Uid_2"), e);
                }
            }
            else
            {
                if (tsLogger.arjLoggerI18N.isFatalEnabled())
                {
                    tsLogger.arjLoggerI18N.fatal(
                            "com.arjuna.ats.arjuna.common.Uid_5", new Object[]
                            { uidString });
                }

                throw new FatalError(tsLogger.log_mesg
                        .getString("com.arjuna.ats.arjuna.common.Uid_3")
                        + uidString);
            }
        }
    }

    public Uid(long[] addr, int processId, int time, int incr)
    {
        try
        {
            hostAddr = new long[2];
            hostAddr[0] = addr[0];
            hostAddr[1] = addr[1];

            process = processId;
            sec = time;
            other = incr;

            _valid = true;

            generateHash();
        }
        catch (Throwable ex)
        {
            _valid = false;

            throw new FatalError(tsLogger.log_mesg
                    .getString("com.arjuna.ats.arjuna.common.Uid_11")
                    + ex);
        }
    }

    /**
     * Override Object.hashCode. We always return a positive value.
     */

    /*
     * generateHash should have been called by now.
     */

    public int hashCode ()
    {
        return _hashValue;
    }

    /**
     * Print a human-readable form of the Uid.
     */

    public void print (PrintStream strm)
    {
        strm.print("<Uid:" + this.toString() + ">");
    }

    public String stringForm ()
    {
        // no need to synchronize since object is immutable

        if (_stringForm == null)
            _stringForm = Utility.longToHexString(hostAddr[0]) + Uid.breakChar
                    + Utility.longToHexString(hostAddr[1]) + Uid.breakChar
                    + Utility.intToHexString(process) + Uid.breakChar
                    + Utility.intToHexString(sec) + Uid.breakChar
                    + Utility.intToHexString(other);

        return _stringForm;
    }

    /**
     * @return a string representation of the Uid with all : replaced by _ so
     *         that the name may be used as a file name.
     */

    public String fileStringForm ()
    {
        return Utility.longToHexString(hostAddr[0]) + Uid.fileBreakChar
                + Utility.longToHexString(hostAddr[1]) + Uid.fileBreakChar
                + Utility.intToHexString(process) + Uid.fileBreakChar
                + Utility.intToHexString(sec) + Uid.fileBreakChar
                + Utility.intToHexString(other);
    }
   
    /**
     * Get the byte representation of the Uid. Useful for packing and creating other
     * representations of transaction ids.
     *
     * @return the byte array. Cached once created.
     */
   
    public byte[] getBytes ()
    {
        /*
         * We should only really be doing this once, so overhead should
         * be negligible.
         */
       
        if (_byteForm == null)
        {
            ByteArrayOutputStream ba = new ByteArrayOutputStream(UID_SIZE);
            DataOutputStream ds = new DataOutputStream(ba);
           
            try
            {
                ds.writeLong(hostAddr[0]);
                ds.writeLong(hostAddr[1]);
                ds.writeInt(process);
                ds.writeInt(sec);
                ds.writeInt(other);
                //_byteForm = stringForm().getBytes("UTF-8");
               
                _byteForm = ba.toByteArray();
            }
            catch (final Throwable ex)
            {
                if (tsLogger.arjLoggerI18N.isWarnEnabled())
                    tsLogger.arjLoggerI18N
                            .warn("com.arjuna.ats.arjuna.common.Uid_getbytes", ex);
               
                _byteForm = null;
            }
        }

        return _byteForm;
    }

    /**
     * Same as stringForm()
     */

    public String toString ()
    {
        return stringForm();
    }

    // return the process id value in hex form.
    // The internal format is Uids mostly should not be exposed, but some
    // recovery/expiry code need this.
    public String getHexPid ()
    {
        return Utility.intToHexString(process);
    }

    /**
     * Create a copy of this instance.
     */

    public Object clone () throws CloneNotSupportedException
    {
        return new Uid(this);
    }

    /**
     * Copy the specified Uid over this instance.
     */

    private void copy (Uid toCopy)
    {
        if (toCopy == this)
            return;

        hostAddr = toCopy.hostAddr;
        process = toCopy.process;
        sec = toCopy.sec;
        other = toCopy.other;
        _hashValue = toCopy._hashValue;
        _valid = toCopy._valid;
    }

    /**
     * Uid comparisons.
     */

    /**
     * Override Object.equals
     */

    public boolean equals (Object o)
    {
        if (o instanceof Uid)
            return this.equals((Uid) o);
        else
            return false;
    }

    public boolean equals (Uid u)
    {
        if (u == null)
            return false;

        if (u == this)
            return true;

        return ((other == u.other) && (sec == u.sec) && (process == u.process)
                && (hostAddr[0] == u.hostAddr[0]) && (hostAddr[1] == u.hostAddr[1]));
    }

    public boolean notEquals (Uid u)
    {
        if (u == null)
            return true;

        if (u == this)
            return false;

        return ((other != u.other) || (sec != u.sec) || (process != u.process)
                || (hostAddr[0] != u.hostAddr[0]) || (hostAddr[1] != u.hostAddr[1]));
    }

    public boolean lessThan (Uid u)
    {
        if (u == null)
            return false;

        if (u == this)
            return false;

        if (this.equals(u))
            return false;

        if (LAST_RESOURCE_UID.equals(this))
            return false;

        if (LAST_RESOURCE_UID.equals(u))
            return true;

        if ((hostAddr[0] < u.hostAddr[0]) && (hostAddr[1] < u.hostAddr[1]))
            return true;
        else
        {
            if ((hostAddr[0] == u.hostAddr[0])
                    && (hostAddr[1] == u.hostAddr[1]))
            {
                if (process < u.process)
                    return true;
                else if (process == u.process)
                {
                    if (sec < u.sec)
                        return true;
                    else if ((sec == u.sec) && (other < u.other))
                        return true;
                }
            }
        }

        return false;
    }

    public boolean greaterThan (Uid u)
    {
        if (u == null)
            return false;

        if (u == this)
            return false;

        if (this.equals(u))
            return false;

        if (LAST_RESOURCE_UID.equals(this))
            return true;

        if (LAST_RESOURCE_UID.equals(u))
            return false;

        if ((hostAddr[0] > u.hostAddr[0]) && (hostAddr[1] > u.hostAddr[1]))
            return true;
        else
        {
            if ((hostAddr[0] == u.hostAddr[0])
                    && (hostAddr[1] == u.hostAddr[0]))
            {
                if (process > u.process)
                    return true;
                else if (process == u.process)
                {
                    if (sec > u.sec)
                        return true;
                    else if ((sec == u.sec) && (other > u.other))
                        return true;
                }
            }
        }

        return false;
    }

    /**
     * Is the Uid valid?
     */

    public final boolean valid ()
    {
        return _valid;
    }

    /**
     * Return a null Uid (0:0:0:0:0)
     */

    public static final Uid nullUid ()
    {
        return NIL_UID;
    }

    /**
     * Return a last resource Uid (0:0:0:0:1)
     */
    public static final Uid lastResourceUid ()
    {
        return LAST_RESOURCE_UID;
    }

    /**
     * Return the maximum Uid (7fffffff:7fffffff:7fffffff:7fffffff:7fffffff)
     */
    public static final Uid maxUid ()
    {
        return MAX_UID;
    }

    /**
     * Return the minimum Uid
     * (-80000000:-80000000:-80000000:-80000000:-80000000)
     */
    public static final Uid minUid ()
    {
        return MIN_UID;
    }

    /*
     * Serialization methods. Similar to buffer packing. If the Uid is invalid
     * the an IOException is thrown.
     * @since JTS 2.1.
     */

    private void writeObject (java.io.ObjectOutputStream out)
            throws IOException
    {
        if (_valid)
        {
            out.writeLong(hostAddr[0]);
            out.writeLong(hostAddr[1]);
            out.writeInt(process);
            out.writeInt(sec);
            out.writeInt(other);
        }
        else
            throw new IOException("Invalid Uid object.");
    }

    /*
     * Serialization methods. Similar to buffer unpacking. If the
     * unserialization fails then an IOException is thrown.
     * @since JTS 2.1.
     */

    private void readObject (java.io.ObjectInputStream in) throws IOException,
            ClassNotFoundException
    {
        try
        {
            hostAddr[0] = in.readLong();
            hostAddr[1] = in.readLong();
            process = in.readInt();
            sec = in.readInt();
            other = in.readInt();

            _valid = true; // should not be able to pack an invalid Uid.

            generateHash();
        }
        catch (IOException e)
        {
            _valid = false;

            throw e;
        }
    }

    private static final int MAX_SEQ_VALUE = 0x40000000; // 2^30, which is a bit
                                                         // conservative.

    private static int getValue ()
    {
        int value = 0;
        do
        {
            value = uidsCreated.getAndIncrement();
            if (value == MAX_SEQ_VALUE)
            {
                uidsCreated.set(0);
                initTime = (int) (System.currentTimeMillis() / 1000);
            }
        }
        while (value >= MAX_SEQ_VALUE);

        return value;
    }

    /*
     * Is an idempotent operation, so can be called more than once without
     * adverse effect.
     */

    private final void generateHash ()
    {
        if (_valid)
        {
            if (true)
                _hashValue = (int) hostAddr[0] ^ (int) hostAddr[1] ^ process
                        ^ sec ^ other;
            else
            {
                int g = 0;
                String p = toString();
                int len = p.length();
                int index = 0;

                if (len > 0)
                {
                    while (len-- > 0)
                    {
                        _hashValue = (_hashValue << 4)
                                + (int) (p.charAt(index));
                        g = _hashValue & 0xf0000000;

                        if (g > 0)
                        {
                            _hashValue = _hashValue ^ (g >> 24);
                            _hashValue = _hashValue ^ g;
                        }

                        index++;
                    }
                }
            }

            if (_hashValue < 0)
                _hashValue = -_hashValue;
        }
        else
        {
            if (tsLogger.arjLoggerI18N.isWarnEnabled())
                tsLogger.arjLoggerI18N
                        .warn("com.arjuna.ats.arjuna.common.Uid_6");
        }
    }

    /*
     * Since we may be given a Uid from the file system (which uses '_' to
     * separate fields, we need to be able to convert.
     */

    private static final char getBreakChar (String uidString)
    {
        if (uidString == null)
            return Uid.breakChar;

        if (uidString.indexOf(fileBreakChar) != -1)
            return Uid.fileBreakChar;
        else
            return Uid.breakChar;
    }

    protected volatile long[] hostAddr; // representation of ipv6 address (and
                                        // ipv4)

    protected volatile int process;

    protected volatile int sec;

    protected volatile int other;

    private volatile int _hashValue;

    private volatile boolean _valid;

    private volatile String _stringForm;
   
    private volatile byte[] _byteForm;

    private static final AtomicInteger uidsCreated = new AtomicInteger();

    private static volatile int initTime;

    private static final char breakChar = ':';

    private static final char fileBreakChar = '_';

    private static final Uid NIL_UID = new Uid("0:0:0:0:0");

    private static final Uid LAST_RESOURCE_UID = new Uid("0:0:0:0:1");

    private static final Uid MAX_UID = new Uid(
            "7fffffff:7fffffff:7fffffff:7fffffff:7fffffff");

    private static final Uid MIN_UID = new Uid(
            "-80000000:-80000000:-80000000:-80000000:-80000000");
   
    private static final int UID_SIZE = 2*8 + 3*4; // in bytes
}
TOP

Related Classes of com.arjuna.ats.arjuna.common.Uid

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.