001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.replication.common;
028    
029    /**
030     * Class used to represent Change Numbers.
031     */
032    public class ChangeNumber implements java.io.Serializable,
033                                         java.lang.Comparable<ChangeNumber>
034    {
035      private static final long serialVersionUID = -8802722277749190740L;
036      private long timeStamp;
037      private int seqnum;
038      private short serverId;
039    
040      /**
041       * Create a new ChangeNumber from a String.
042       *
043       * @param str the string from which to create a ChangeNumber
044       */
045      public ChangeNumber(String str)
046      {
047        String temp = str.substring(0, 16);
048        timeStamp = Long.parseLong(temp, 16);
049    
050        temp = str.substring(16, 20);
051        serverId = Short.parseShort(temp, 16);
052    
053        temp = str.substring(20, 28);
054        seqnum = Integer.parseInt(temp, 16);
055      }
056    
057      /**
058       * Create a new ChangeNumber.
059       *
060       * @param time time for the ChangeNumber
061       * @param seq sequence number
062       * @param id identity of server
063       */
064      public ChangeNumber(long time, int seq, short id)
065      {
066        serverId = id;
067        timeStamp = time;
068        seqnum = seq;
069      }
070    
071      /**
072       * Getter for the time.
073       * @return the time
074       */
075      public long getTime()
076      {
077        return timeStamp;
078      }
079    
080      /**
081       * Get the timestamp associated to this ChangeNumber in seconds.
082       * @return timestamp associated to this ChangeNumber in seconds
083       */
084      public long getTimeSec()
085      {
086        return timeStamp/1000;
087      }
088    
089      /**
090       * Getter for the sequence number.
091       * @return the sequence number
092       */
093      public int getSeqnum()
094      {
095        return seqnum;
096      }
097    
098      /**
099       * Getter for the server ID.
100       * @return the server ID
101       */
102      public short getServerId()
103      {
104        return serverId;
105      }
106    
107    
108      /**
109       * {@inheritDoc}
110       */
111      public boolean equals(Object obj)
112      {
113        if (obj instanceof ChangeNumber)
114        {
115          ChangeNumber cn = (ChangeNumber) obj;
116          if ((this.seqnum == cn.seqnum)  &&
117              (this.serverId == cn.serverId) &&
118              (this.timeStamp == cn.timeStamp) )
119            return true;
120          else
121            return false;
122        }
123        else
124          return false;
125      }
126    
127      /**
128       * {@inheritDoc}
129       */
130      @Override
131      public int hashCode()
132      {
133        return this.seqnum + this.serverId + Long.valueOf(timeStamp).hashCode();
134      }
135    
136      /**
137       * Convert the ChangeNumber to a printable String.
138       * @return the string
139       */
140      public String toString()
141      {
142        return String.format("%016x%04x%08x", timeStamp, serverId, seqnum);
143      }
144    
145      /**
146       * Compares 2 ChangeNumber.
147       * @param CN1 the first ChangeNumber to compare
148       * @param CN2 the second ChangeNumber to compare
149       * @return value 0 if changeNumber matches, negative if first
150       * changeNumber is smaller, positive otherwise
151       */
152      public static int compare(ChangeNumber CN1, ChangeNumber CN2)
153      {
154        if (CN1 == null)
155        {
156          if (CN2 == null)
157            return 0;
158          else
159            return -1;
160        }
161        else if (CN2 == null)
162          return 1;
163        else if (CN1.timeStamp < CN2.timeStamp)
164          return -1;
165        else if (CN2.timeStamp < CN1.timeStamp)
166          return 1;
167        else
168        {
169          // timestamps are equals compare seqnums
170          if (CN1.seqnum < CN2.seqnum)
171            return -1;
172          else if (CN2.seqnum < CN1.seqnum)
173            return 1;
174          else
175          {
176            // timestamp and seqnum are equals compare serverIds
177            if (CN1.serverId < CN2.serverId)
178              return -1;
179            else if (CN2.serverId < CN1.serverId)
180              return 1;
181    
182            // if we get here ChangeNumber are equals
183            return 0;
184          }
185    
186        }
187      }
188    
189      /**
190       * Computes the difference in number of changes between 2
191       * change numbers.
192       * @param op1 the first ChangeNumber
193       * @param op2 the second ChangeNumber
194       * @return the difference
195       */
196      public static int diffSeqNum(ChangeNumber op1, ChangeNumber op2)
197      {
198        int totalCount = 0;
199        int max = op1.getSeqnum();
200        if (op2 != null)
201        {
202          int current = op2.getSeqnum();
203          if (current == max)
204          {
205          }
206          else if (current < max)
207          {
208            totalCount += max - current;
209          }
210          else
211          {
212            totalCount += Integer.MAX_VALUE - (current - max) + 1;
213          }
214        }
215        else
216        {
217          totalCount += max;
218        }
219        return totalCount;
220      }
221    
222      /**
223       * check if the current Object is strictly older than ChangeNumber
224       * given in parameter.
225       * @param CN the Changenumber to compare with
226       * @return true if strictly older, false if younger or same
227       */
228      public Boolean older(ChangeNumber CN)
229      {
230        if (compare(this, CN) < 0)
231          return true;
232    
233        return false;
234      }
235    
236      /**
237       * check if the current Object is older than ChangeNumber
238       * given in parameter.
239       * @param CN the Changenumber to compare with
240       * @return true if older or equal, false if younger
241       */
242      public Boolean olderOrEqual(ChangeNumber CN)
243      {
244        if (compare(this, CN) <= 0)
245          return true;
246    
247        return false;
248      }
249    
250      /**
251       * Check if the current Object is newer than ChangeNumber.
252       * @param CN the Changenumber to compare with
253       * @return true if newer
254       */
255      public boolean newerOrEquals(ChangeNumber CN)
256      {
257        if (compare(this, CN) >= 0)
258          return true;
259    
260        return false;
261      }
262    
263      /**
264       * Check if the current Object is strictly newer than ChangeNumber.
265       * @param CN the Changenumber to compare with
266       * @return true if strictly newer
267       */
268      public boolean newer(ChangeNumber CN)
269      {
270        if (compare(this, CN) > 0)
271          return true;
272    
273        return false;
274      }
275    
276      /**
277       * Compares this object with the specified object for order.
278       * @param cn the ChangeNumber to compare with.
279       * @return a negative integer, zero, or a positive integer as this object
280       *         is less than, equal to, or greater than the specified object.
281       */
282      public int compareTo(ChangeNumber cn)
283      {
284        return compare(this, cn);
285      }
286    }