001    /*
002    Copyright (c) 1996-2012, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    package org.hd.d.pg2k.svrCore.vars;
030    
031    import java.io.InvalidObjectException;
032    import java.io.ObjectInputValidation;
033    import java.io.ObjectStreamException;
034    import java.io.Serializable;
035    
036    import org.hd.d.pg2k.svrCore.MemoryTools;
037    import org.hd.d.pg2k.svrCore.Rnd;
038    
039    
040    /**Immutable globally-unique instance ID for a JVM participating in a set of SystemVariables.
041     * This is the key to a globalmap variable,
042     * and each participating system should have just one such value,
043     * probably generated by a data pipeline endpoint.
044     * <p>
045     * Internally, this is a randomly-generated (non-negative) long value.
046     */
047    public final class InstanceID implements Serializable,
048                                             ObjectInputValidation,
049                                             MemoryTools.Internable,
050                                             Comparable<InstanceID>
051        {
052        /**Create a new, unique instance ID; never null.
053         * This is immediately intern()ed so that there will never be more than
054         * one copy of each unique InstanceID in memory at any one time
055         * (except transiently during deserialisation).
056         */
057        public static InstanceID createInstanceID()
058            {
059            return(MemoryTools.intern(new InstanceID()));
060            }
061    
062        /**Create a new instance with a new/unique ID from a cryptographically-good random-number source. */
063        private InstanceID()
064            {
065            // Guaranteed non-negative new ID.
066            ID = (Rnd.goodRnd.nextLong() >>> 1);
067            }
068    
069        /**Unique (positive) long ID from a cryptographically-good random-number source. */
070        private final long ID;
071    
072        /**Long representation of ID; non-negative. */
073        public long longValue()
074            {
075            return(ID);
076            }
077    
078        /**String representation of ID as a non-negative base-36 number. */
079        @Override
080        public String toString()
081            {
082            return(Long.toString(ID, Character.MAX_RADIX));
083            }
084    
085        /**Comparable ordering is on ID value alone in numeric ID order. */
086        public int compareTo(final InstanceID other)
087            {
088            if(ID < other.ID) { return(-1); }
089            if(ID > other.ID) { return(+1); }
090            return(0);
091            }
092    
093        /**Equality is based on the whole ID.
094         * But in fact due to instance control we can in fact use ==
095         * at least as an optimisation!
096         */
097        @Override
098        public boolean equals(final Object obj)
099            {
100            if(this == obj) { return(true); }
101            if(!(obj instanceof InstanceID)) { return(false); }
102            final InstanceID other = (InstanceID) obj;
103    
104            // Compare the ID values.
105            return(ID == other.ID);
106            }
107    
108        /**The hash is derived from the ID.
109         * This implementation just uses the hash of the name.
110         */
111        @Override
112        public int hashCode()
113            {
114            return((int) ID);
115            }
116    
117        /**Deserialise: validate and eliminate duplicates coming off the wire.
118         * Ensures that there is never more than one copy of any given
119         * InstanceID value in memory (other than transiently).
120         *
121         * @return identical, de-duped, non-null instance
122         */
123        protected Object readResolve()
124            throws ObjectStreamException
125            {
126            validateObject();
127            return(MemoryTools.intern(this));
128            }
129    
130        /**Check for legal state. */
131        public void validateObject()
132            throws InvalidObjectException
133            {
134            if(ID < 0)
135                { throw new InvalidObjectException("bad object: negative ID"); }
136            }
137    
138        /**Unique Serialisation class ID generated by http://random&#46;hd&#46;org/. */
139        private static final long serialVersionUID = -2320309863687936784L;
140        }