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 }