1 11 12 package org.jivesoftware.database; 13 14 import org.jivesoftware.util.JiveConstants; 15 import org.jivesoftware.util.Log; 16 17 import java.sql.Connection ; 18 import java.sql.PreparedStatement ; 19 import java.sql.ResultSet ; 20 import java.sql.SQLException ; 21 import java.util.Map ; 22 import java.util.concurrent.ConcurrentHashMap ; 23 24 46 public class SequenceManager { 47 48 private static final String LOAD_ID = 49 "SELECT id FROM jiveID WHERE idType=?"; 50 51 private static final String UPDATE_ID = 52 "UPDATE jiveID SET id=? WHERE idType=? AND id=?"; 53 54 private static final String VERIFY_TYPE = "SELECT 1 FROM jiveID WHERE idType = ?"; 55 56 private static Map <Integer ,SequenceManager> managers = new ConcurrentHashMap <Integer ,SequenceManager>(); 58 59 static { 60 new SequenceManager(JiveConstants.ROSTER, 5); 61 new SequenceManager(JiveConstants.OFFLINE, 1); 62 new SequenceManager(JiveConstants.MUC_ROOM, 1); 63 } 64 65 71 public static long nextID(int type) { 72 if (managers.containsKey(type)) { 73 return managers.get(type).nextUniqueID(); 74 } 75 else { 76 if(isValidType(type)) { 79 SequenceManager manager = new SequenceManager(type, 1); 80 return manager.nextUniqueID(); 81 } 82 83 throw new IllegalArgumentException ("Invalid type"); 84 } 85 } 86 87 105 public static long nextID(Object o) { 106 JiveID id = o.getClass().getAnnotation(JiveID.class); 107 108 if(id == null) { 109 Log.error("Annotation JiveID must be defined in the class "+o.getClass()); 110 throw new IllegalArgumentException ( 111 "Annotation JiveID must be defined in the class "+o.getClass()); 112 } 113 114 return nextID(id.value()); 115 } 116 117 124 public static void setBlockSize(int type, int blockSize) { 125 if (managers.containsKey(type)) { 126 managers.get(type).blockSize = blockSize; 127 } 128 else { 129 if(isValidType(type)) { 131 new SequenceManager(type, blockSize); 132 } else { 133 throw new IllegalArgumentException ("Invalid type"); 134 } 135 } 136 } 137 138 private int type; 139 private long currentID; 140 private long maxID; 141 private int blockSize; 142 143 149 public SequenceManager(int seqType, int size) { 150 managers.put(seqType, this); 151 this.type = seqType; 152 this.blockSize = size; 153 currentID = 0l; 154 maxID = 0l; 155 } 156 157 161 public synchronized long nextUniqueID() { 162 if (!(currentID < maxID)) { 163 getNextBlock(5); 165 } 166 long id = currentID; 167 currentID++; 168 return id; 169 } 170 171 181 private void getNextBlock(int count) { 182 if (count == 0) { 183 Log.error("Failed at last attempt to obtain an ID, aborting..."); 184 return; 185 } 186 187 Connection con = null; 188 PreparedStatement pstmt = null; 189 boolean abortTransaction = false; 190 boolean success = false; 191 192 try { 193 con = DbConnectionManager.getTransactionConnection(); 194 pstmt = con.prepareStatement(LOAD_ID); 196 pstmt.setInt(1, type); 197 ResultSet rs = pstmt.executeQuery(); 198 if (!rs.next()) { 199 throw new SQLException ("Loading the current ID failed. The " + 200 "jiveID table may not be correctly populated."); 201 } 202 long currentID = rs.getLong(1); 203 rs.close(); 204 pstmt.close(); 205 206 long newID = currentID + blockSize; 208 pstmt = con.prepareStatement(UPDATE_ID); 212 pstmt.setLong(1, newID); 213 pstmt.setInt(2, type); 214 pstmt.setLong(3, currentID); 215 success = pstmt.executeUpdate() == 1; 219 if (success) { 220 this.currentID = currentID; 221 this.maxID = newID; 222 } 223 } 224 catch (SQLException e) { 225 Log.error(e); 226 abortTransaction = true; 227 } 228 finally { 229 try { if (pstmt != null) { pstmt.close(); } } 230 catch (Exception e) { Log.error(e); } 231 DbConnectionManager.closeTransactionConnection(con, abortTransaction); 232 } 233 234 if (!success) { 235 Log.error("WARNING: failed to obtain next ID block due to " + 236 "thread contention. Trying again..."); 237 try { 239 Thread.sleep(75); 240 } 241 catch (InterruptedException ie) { 242 } 243 getNextBlock(count - 1); 244 } 245 } 246 247 248 254 private static boolean isValidType(int type) { 255 256 boolean isValid = false; 257 258 Connection con = null; 259 PreparedStatement pstmt = null; 260 try { 261 con = DbConnectionManager.getConnection(); 262 pstmt = con.prepareStatement(VERIFY_TYPE); 263 pstmt.setInt(1, type); 264 265 ResultSet rs = pstmt.executeQuery(); 266 if(rs.next()) { 267 isValid = true; 268 } 269 } 270 catch (SQLException sqle) { 271 Log.error(sqle); 272 } 273 finally { 274 try { if (pstmt != null) { pstmt.close(); } } 275 catch (Exception e) { Log.error(e); } 276 try { if (con != null) { con.close(); } } 277 catch (Exception e) { Log.error(e); } 278 } 279 280 return isValid; 281 } 282 283 } 284 | Popular Tags |