1 24 25 package org.objectweb.cjdbc.common.sql.filters; 26 27 import java.sql.Date ; 28 import java.sql.Time ; 29 import java.sql.Timestamp ; 30 import java.util.ArrayList ; 31 import java.util.Random ; 32 33 import org.objectweb.cjdbc.common.util.Strings; 34 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 35 import org.objectweb.cjdbc.common.xml.XmlComponent; 36 37 43 public class MacrosHandler implements XmlComponent 44 { 45 46 public static final int UNKNOWN_INT_VALUE = -1; 47 48 public static final String UNKNOWN_STRING_VALUE = "unknown"; 49 50 51 private static final String MACRO_RAND = "rand()"; 52 53 54 public static final int RAND_OFF = 0; 55 56 public static final int RAND_INT = 1; 57 58 public static final int RAND_LONG = 2; 59 60 public static final int RAND_FLOAT = 3; 61 62 public static final int RAND_DOUBLE = 4; 63 64 private final Random randGenerator = new Random (); 65 66 private int replaceRand = RAND_FLOAT; 67 68 69 private static final String MACRO_NOW = "now()"; 70 71 private static final String MACRO_CURRENT_DATE = "current_date"; 72 73 private static final String MACRO_CURRENT_TIME = "current_time"; 74 75 private static final String MACRO_TIMEODFAY = "timeofday()"; 76 77 private static final String MACRO_CURRENT_TIMESTAMP = "current_timestamp"; 78 79 80 public static final int DATE_OFF = 0; 81 82 public static final int DATE_DATE = 1; 83 84 public static final int DATE_TIME = 2; 85 86 public static final int DATE_TIMESTAMP = 3; 87 88 private long clockResolution = 0; 89 private int now = DATE_TIMESTAMP; 90 private int currentDate = DATE_DATE; 91 private int currentTime = DATE_TIME; 92 private int timeOfDay = DATE_TIMESTAMP; 93 private int currentTimestamp = DATE_TIMESTAMP; 94 95 private boolean needsProcessing; 96 private boolean needsDateProcessing; 97 98 109 public MacrosHandler(int replaceRand, long clockResolution, int now, 110 int currentDate, int currentTime, int timeOfDay, int currentTimestamp) 111 { 112 if ((replaceRand < RAND_OFF) || (replaceRand > RAND_DOUBLE)) 113 throw new RuntimeException ("Invalid value for " + MACRO_RAND 114 + " macro replacement (" + replaceRand + ")"); 115 this.replaceRand = replaceRand; 116 if (clockResolution < 0) 117 throw new RuntimeException ( 118 "Invalid negative value for clock resolution in date macros"); 119 this.clockResolution = clockResolution; 120 if ((now < DATE_OFF) || (now > DATE_TIMESTAMP)) 121 throw new RuntimeException ("Invalid value for " + MACRO_NOW 122 + " macro replacement (" + now + ")"); 123 this.now = now; 124 if ((currentDate < DATE_OFF) || (currentDate > DATE_DATE)) 125 throw new RuntimeException ("Invalid value for " + MACRO_CURRENT_DATE 126 + " macro replacement (" + currentDate + ")"); 127 this.currentDate = currentDate; 128 if ((currentTime < DATE_OFF) || (currentTime > DATE_TIMESTAMP)) 129 throw new RuntimeException ("Invalid value for " + MACRO_CURRENT_TIME 130 + " macro replacement (" + currentTime + ")"); 131 this.currentTime = currentTime; 132 if ((timeOfDay < DATE_OFF) || (timeOfDay > DATE_TIMESTAMP)) 133 throw new RuntimeException ("Invalid value for " + MACRO_TIMEODFAY 134 + " macro replacement (" + timeOfDay + ")"); 135 this.timeOfDay = timeOfDay; 136 if ((currentTimestamp < DATE_OFF) || (currentTimestamp > DATE_TIMESTAMP)) 137 throw new RuntimeException ("Invalid value for " + MACRO_CURRENT_TIMESTAMP 138 + " macro replacement (" + currentTimestamp + ")"); 139 this.currentTimestamp = currentTimestamp; 140 needsDateProcessing = (now + currentDate + timeOfDay + currentTimestamp) > 0; 141 needsProcessing = needsDateProcessing || (replaceRand > 0); 142 } 143 144 150 public static final int getIntRandLevel(String randLevel) 151 { 152 if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_off)) 153 return RAND_OFF; 154 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_double)) 155 return RAND_DOUBLE; 156 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_float)) 157 return RAND_FLOAT; 158 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_int)) 159 return RAND_INT; 160 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_long)) 161 return RAND_LONG; 162 else 163 return UNKNOWN_INT_VALUE; 164 } 165 166 171 public String getXml() 172 { 173 StringBuffer sb = new StringBuffer (); 174 sb.append("<" + DatabasesXmlTags.ELT_MacroHandling + " " 175 + DatabasesXmlTags.ATT_rand + "=\"" + getStringRandLevel(replaceRand) 176 + "\" " + DatabasesXmlTags.ATT_now + "=\"" + getStringDateLevel(now) 177 + "\" " + DatabasesXmlTags.ATT_currentDate + "=\"" 178 + getStringDateLevel(currentDate) + "\" " 179 + DatabasesXmlTags.ATT_currentTime + "=\"" 180 + getStringDateLevel(currentTime) + "\" " 181 + DatabasesXmlTags.ATT_currentTimestamp + "=\"" 182 + getStringDateLevel(currentTimestamp) + "\" " 183 + DatabasesXmlTags.ATT_timeOfDay + "=\"" 184 + getStringDateLevel(timeOfDay) + "\" " 185 + DatabasesXmlTags.ATT_timeResolution + "=\"" + clockResolution + "\" " 186 + "/>"); 187 return sb.toString(); 188 } 189 190 196 public static final String getStringRandLevel(int randLevel) 197 { 198 switch (randLevel) 199 { 200 case RAND_OFF : 201 return DatabasesXmlTags.VAL_off; 202 case RAND_DOUBLE : 203 return DatabasesXmlTags.VAL_double; 204 case RAND_FLOAT : 205 return DatabasesXmlTags.VAL_float; 206 case RAND_INT : 207 return DatabasesXmlTags.VAL_int; 208 case RAND_LONG : 209 return DatabasesXmlTags.VAL_long; 210 default : 211 return UNKNOWN_STRING_VALUE; 212 } 213 } 214 215 221 public static final int getIntDateLevel(String dateLevel) 222 { 223 if (dateLevel.equals(DatabasesXmlTags.VAL_off)) 224 return DATE_OFF; 225 else if (dateLevel.equals(DatabasesXmlTags.VAL_date)) 226 return DATE_DATE; 227 else if (dateLevel.equals(DatabasesXmlTags.VAL_time)) 228 return DATE_TIME; 229 else if (dateLevel.equals(DatabasesXmlTags.VAL_timestamp)) 230 return DATE_TIMESTAMP; 231 else 232 return UNKNOWN_INT_VALUE; 233 } 234 235 241 public static final String getStringDateLevel(int dateLevel) 242 { 243 switch (dateLevel) 244 { 245 case DATE_OFF : 246 return DatabasesXmlTags.VAL_off; 247 case DATE_DATE : 248 return DatabasesXmlTags.VAL_date; 249 case DATE_TIME : 250 return DatabasesXmlTags.VAL_time; 251 case DATE_TIMESTAMP : 252 return DatabasesXmlTags.VAL_timestamp; 253 default : 254 return UNKNOWN_STRING_VALUE; 255 } 256 } 257 258 268 public String macroDate(String originalSql, String macroPattern, 269 int replacementPolicy, long currentClock, Integer [] idxs) 270 { 271 if (idxs == null) 272 idxs = getQuoteIndexes(originalSql); 273 String lower = originalSql.toLowerCase(); 274 int idx = lower.indexOf(macroPattern.toLowerCase()); 275 if (idx == -1 || !shouldReplaceMacro(idx, idxs)) 276 return originalSql; 277 278 String date; 279 switch (replacementPolicy) 280 { 281 case DATE_DATE : 282 date = "{d '" + new Date (currentClock).toString() + "'}"; 283 break; 284 case DATE_TIME : 285 date = "{t '" + new Time (currentClock).toString() + "'}"; 286 break; 287 case DATE_TIMESTAMP : 288 date = "{ts '" + new Timestamp (currentClock).toString() + "'}"; 289 break; 290 default : 291 throw new RuntimeException ( 292 "Unexpected replacement strategy for date macro (" 293 + replacementPolicy + ")"); 294 } 295 return Strings.replaceCasePreserving(originalSql, macroPattern, date); 296 } 297 298 305 public String macroRand(String originalSql, Integer [] idxs) 306 { 307 if (idxs == null) 308 idxs = getQuoteIndexes(originalSql); 309 String lower = originalSql.toLowerCase(); 310 int idx = lower.indexOf(MACRO_RAND); 311 if (idx > 0) 312 { 313 String rand; 314 StringBuffer sql = new StringBuffer (originalSql); 315 int shift = 0; 316 do 317 { 318 if (shouldReplaceMacro(idx, idxs)) 319 { 320 switch (replaceRand) 321 { 322 case RAND_INT : 323 rand = Integer.toString(randGenerator.nextInt()); 324 break; 325 case RAND_LONG : 326 rand = Long.toString(randGenerator.nextLong()); 327 break; 328 case RAND_FLOAT : 329 rand = Float.toString(randGenerator.nextFloat()); 330 break; 331 case RAND_DOUBLE : 332 rand = Double.toString(randGenerator.nextDouble()); 333 break; 334 default : 335 throw new RuntimeException ( 336 "Unexpected replacement strategy for rand() macro (" 337 + replaceRand + ")"); 338 } 339 sql = sql.replace(idx + shift, idx + shift + MACRO_RAND.length(), 340 rand); 341 shift += rand.length() - MACRO_RAND.length(); 342 } 343 idx = lower.indexOf(MACRO_RAND, idx + MACRO_RAND.length()); 344 } 345 while (idx > 0); 346 return sql.toString(); 347 } 348 else 349 { 350 return originalSql; 351 } 352 } 353 354 362 public final String processMacros(String sql) 363 { 364 if (!needsProcessing) 365 return sql; 366 if(sql==null) 367 return null; 368 Integer [] idxs = this.getQuoteIndexes(sql); 369 if (replaceRand > RAND_OFF) 370 sql = macroRand(sql, idxs); 371 if (!needsDateProcessing) 372 return sql; 373 long currentClock = System.currentTimeMillis(); 374 if (clockResolution > 0) 375 currentClock = currentClock - (currentClock % clockResolution); 376 if (now > DATE_OFF) 377 sql = macroDate(sql, MACRO_NOW, now, currentClock, idxs); 378 if (currentDate > DATE_OFF) 379 sql = macroDate(sql, MACRO_CURRENT_DATE, currentDate, currentClock, idxs); 380 if (currentTimestamp > DATE_OFF) 381 sql = macroDate(sql, MACRO_CURRENT_TIMESTAMP, currentTimestamp, 382 currentClock, idxs); 383 if (currentTime > DATE_OFF) 384 sql = macroDate(sql, MACRO_CURRENT_TIME, currentTime, currentClock, idxs); 385 if (timeOfDay > DATE_OFF) 386 sql = macroDate(sql, MACRO_TIMEODFAY, timeOfDay, currentClock, idxs); 387 388 return sql; 389 } 390 391 397 private Integer [] getQuoteIndexes(String sql) 398 { 399 ArrayList list = new ArrayList (); 400 for (int i = 0; i < sql.length(); i++) 401 { 402 char c = sql.charAt(i); 403 if (c == '\'') 404 list.add(new Integer (i)); 405 } 406 Integer [] intlist = new Integer [list.size()]; 407 return (Integer []) list.toArray(intlist); 408 } 409 410 419 private boolean shouldReplaceMacro(int idx, Integer [] list) 420 { 421 int count = 0; 422 while (count < list.length && list[count].intValue() < idx) 423 { 424 count++; 425 } 426 return count % 2 == 0; 427 } 428 429 } | Popular Tags |