src/org/objectweb/cjdbc/common/sql/filters/MacrosHandler.java

説明を見る。
00001 00025 package org.objectweb.cjdbc.common.sql.filters; 00026 00027 import java.sql.Date; 00028 import java.sql.Time; 00029 import java.sql.Timestamp; 00030 import java.util.ArrayList; 00031 import java.util.Random; 00032 00033 import org.objectweb.cjdbc.common.util.Strings; 00034 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 00035 import org.objectweb.cjdbc.common.xml.XmlComponent; 00036 00043 public class MacrosHandler implements XmlComponent 00044 { 00046 public static final int UNKNOWN_INT_VALUE = -1; 00048 public static final String UNKNOWN_STRING_VALUE = "unknown"; 00049 00051 private static final String MACRO_RAND = "rand()"; 00052 00054 public static final int RAND_OFF = 0; 00056 public static final int RAND_INT = 1; 00058 public static final int RAND_LONG = 2; 00060 public static final int RAND_FLOAT = 3; 00062 public static final int RAND_DOUBLE = 4; 00063 00064 private final Random randGenerator = new Random(); 00065 00066 private int replaceRand = RAND_FLOAT; 00067 00069 private static final String MACRO_NOW = "now()"; 00071 private static final String MACRO_CURRENT_DATE = "current_date"; 00073 private static final String MACRO_CURRENT_TIME = "current_time"; 00075 private static final String MACRO_TIMEODFAY = "timeofday()"; 00077 private static final String MACRO_CURRENT_TIMESTAMP = "current_timestamp"; 00078 00080 public static final int DATE_OFF = 0; 00082 public static final int DATE_DATE = 1; 00084 public static final int DATE_TIME = 2; 00086 public static final int DATE_TIMESTAMP = 3; 00087 00088 private long clockResolution = 0; 00089 private int now = DATE_TIMESTAMP; 00090 private int currentDate = DATE_DATE; 00091 private int currentTime = DATE_TIME; 00092 private int timeOfDay = DATE_TIMESTAMP; 00093 private int currentTimestamp = DATE_TIMESTAMP; 00094 00095 private boolean needsProcessing; 00096 private boolean needsDateProcessing; 00097 00109 public MacrosHandler(int replaceRand, long clockResolution, int now, 00110 int currentDate, int currentTime, int timeOfDay, int currentTimestamp) 00111 { 00112 if ((replaceRand < RAND_OFF) || (replaceRand > RAND_DOUBLE)) 00113 throw new RuntimeException("Invalid value for " + MACRO_RAND 00114 + " macro replacement (" + replaceRand + ")"); 00115 this.replaceRand = replaceRand; 00116 if (clockResolution < 0) 00117 throw new RuntimeException( 00118 "Invalid negative value for clock resolution in date macros"); 00119 this.clockResolution = clockResolution; 00120 if ((now < DATE_OFF) || (now > DATE_TIMESTAMP)) 00121 throw new RuntimeException("Invalid value for " + MACRO_NOW 00122 + " macro replacement (" + now + ")"); 00123 this.now = now; 00124 if ((currentDate < DATE_OFF) || (currentDate > DATE_DATE)) 00125 throw new RuntimeException("Invalid value for " + MACRO_CURRENT_DATE 00126 + " macro replacement (" + currentDate + ")"); 00127 this.currentDate = currentDate; 00128 if ((currentTime < DATE_OFF) || (currentTime > DATE_TIMESTAMP)) 00129 throw new RuntimeException("Invalid value for " + MACRO_CURRENT_TIME 00130 + " macro replacement (" + currentTime + ")"); 00131 this.currentTime = currentTime; 00132 if ((timeOfDay < DATE_OFF) || (timeOfDay > DATE_TIMESTAMP)) 00133 throw new RuntimeException("Invalid value for " + MACRO_TIMEODFAY 00134 + " macro replacement (" + timeOfDay + ")"); 00135 this.timeOfDay = timeOfDay; 00136 if ((currentTimestamp < DATE_OFF) || (currentTimestamp > DATE_TIMESTAMP)) 00137 throw new RuntimeException("Invalid value for " + MACRO_CURRENT_TIMESTAMP 00138 + " macro replacement (" + currentTimestamp + ")"); 00139 this.currentTimestamp = currentTimestamp; 00140 needsDateProcessing = (now + currentDate + timeOfDay + currentTimestamp) > 0; 00141 needsProcessing = needsDateProcessing || (replaceRand > 0); 00142 } 00143 00150 public static final int getIntRandLevel(String randLevel) 00151 { 00152 if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_off)) 00153 return RAND_OFF; 00154 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_double)) 00155 return RAND_DOUBLE; 00156 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_float)) 00157 return RAND_FLOAT; 00158 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_int)) 00159 return RAND_INT; 00160 else if (randLevel.equalsIgnoreCase(DatabasesXmlTags.VAL_long)) 00161 return RAND_LONG; 00162 else 00163 return UNKNOWN_INT_VALUE; 00164 } 00165 00171 public String getXml() 00172 { 00173 StringBuffer sb = new StringBuffer(); 00174 sb.append("<" + DatabasesXmlTags.ELT_MacroHandling + " " 00175 + DatabasesXmlTags.ATT_rand + "=\"" + getStringRandLevel(replaceRand) 00176 + "\" " + DatabasesXmlTags.ATT_now + "=\"" + getStringDateLevel(now) 00177 + "\" " + DatabasesXmlTags.ATT_currentDate + "=\"" 00178 + getStringDateLevel(currentDate) + "\" " 00179 + DatabasesXmlTags.ATT_currentTime + "=\"" 00180 + getStringDateLevel(currentTime) + "\" " 00181 + DatabasesXmlTags.ATT_currentTimestamp + "=\"" 00182 + getStringDateLevel(currentTimestamp) + "\" " 00183 + DatabasesXmlTags.ATT_timeOfDay + "=\"" 00184 + getStringDateLevel(timeOfDay) + "\" " 00185 + DatabasesXmlTags.ATT_timeResolution + "=\"" + clockResolution + "\" " 00186 + "/>"); 00187 return sb.toString(); 00188 } 00189 00196 public static final String getStringRandLevel(int randLevel) 00197 { 00198 switch (randLevel) 00199 { 00200 case RAND_OFF : 00201 return DatabasesXmlTags.VAL_off; 00202 case RAND_DOUBLE : 00203 return DatabasesXmlTags.VAL_double; 00204 case RAND_FLOAT : 00205 return DatabasesXmlTags.VAL_float; 00206 case RAND_INT : 00207 return DatabasesXmlTags.VAL_int; 00208 case RAND_LONG : 00209 return DatabasesXmlTags.VAL_long; 00210 default : 00211 return UNKNOWN_STRING_VALUE; 00212 } 00213 } 00214 00221 public static final int getIntDateLevel(String dateLevel) 00222 { 00223 if (dateLevel.equals(DatabasesXmlTags.VAL_off)) 00224 return DATE_OFF; 00225 else if (dateLevel.equals(DatabasesXmlTags.VAL_date)) 00226 return DATE_DATE; 00227 else if (dateLevel.equals(DatabasesXmlTags.VAL_time)) 00228 return DATE_TIME; 00229 else if (dateLevel.equals(DatabasesXmlTags.VAL_timestamp)) 00230 return DATE_TIMESTAMP; 00231 else 00232 return UNKNOWN_INT_VALUE; 00233 } 00234 00241 public static final String getStringDateLevel(int dateLevel) 00242 { 00243 switch (dateLevel) 00244 { 00245 case DATE_OFF : 00246 return DatabasesXmlTags.VAL_off; 00247 case DATE_DATE : 00248 return DatabasesXmlTags.VAL_date; 00249 case DATE_TIME : 00250 return DatabasesXmlTags.VAL_time; 00251 case DATE_TIMESTAMP : 00252 return DatabasesXmlTags.VAL_timestamp; 00253 default : 00254 return UNKNOWN_STRING_VALUE; 00255 } 00256 } 00257 00268 public String macroDate(String originalSql, String macroPattern, 00269 int replacementPolicy, long currentClock, Integer[] idxs) 00270 { 00271 if (idxs == null) 00272 idxs = getQuoteIndexes(originalSql); 00273 String lower = originalSql.toLowerCase(); 00274 int idx = lower.indexOf(macroPattern.toLowerCase()); 00275 if (idx == -1 || !shouldReplaceMacro(idx, idxs)) 00276 return originalSql; 00277 00278 String date; 00279 switch (replacementPolicy) 00280 { 00281 case DATE_DATE : 00282 date = "{d '" + new Date(currentClock).toString() + "'}"; 00283 break; 00284 case DATE_TIME : 00285 date = "{t '" + new Time(currentClock).toString() + "'}"; 00286 break; 00287 case DATE_TIMESTAMP : 00288 date = "{ts '" + new Timestamp(currentClock).toString() + "'}"; 00289 break; 00290 default : 00291 throw new RuntimeException( 00292 "Unexpected replacement strategy for date macro (" 00293 + replacementPolicy + ")"); 00294 } 00295 return Strings.replaceCasePreserving(originalSql, macroPattern, date); 00296 } 00297 00305 public String macroRand(String originalSql, Integer[] idxs) 00306 { 00307 if (idxs == null) 00308 idxs = getQuoteIndexes(originalSql); 00309 String lower = originalSql.toLowerCase(); 00310 int idx = lower.indexOf(MACRO_RAND); 00311 if (idx > 0) 00312 { 00313 String rand; 00314 StringBuffer sql = new StringBuffer(originalSql); 00315 int shift = 0; 00316 do 00317 { 00318 if (shouldReplaceMacro(idx, idxs)) 00319 { 00320 switch (replaceRand) 00321 { 00322 case RAND_INT : 00323 rand = Integer.toString(randGenerator.nextInt()); 00324 break; 00325 case RAND_LONG : 00326 rand = Long.toString(randGenerator.nextLong()); 00327 break; 00328 case RAND_FLOAT : 00329 rand = Float.toString(randGenerator.nextFloat()); 00330 break; 00331 case RAND_DOUBLE : 00332 rand = Double.toString(randGenerator.nextDouble()); 00333 break; 00334 default : 00335 throw new RuntimeException( 00336 "Unexpected replacement strategy for rand() macro (" 00337 + replaceRand + ")"); 00338 } 00339 sql = sql.replace(idx + shift, idx + shift + MACRO_RAND.length(), 00340 rand); 00341 shift += rand.length() - MACRO_RAND.length(); 00342 } 00343 idx = lower.indexOf(MACRO_RAND, idx + MACRO_RAND.length()); 00344 } 00345 while (idx > 0); 00346 return sql.toString(); 00347 } 00348 else 00349 { 00350 return originalSql; 00351 } 00352 } 00353 00362 public final String processMacros(String sql) 00363 { 00364 if (!needsProcessing) 00365 return sql; 00366 if(sql==null) 00367 return null; 00368 Integer[] idxs = this.getQuoteIndexes(sql); 00369 if (replaceRand > RAND_OFF) 00370 sql = macroRand(sql, idxs); 00371 if (!needsDateProcessing) 00372 return sql; 00373 long currentClock = System.currentTimeMillis(); 00374 if (clockResolution > 0) 00375 currentClock = currentClock - (currentClock % clockResolution); 00376 if (now > DATE_OFF) 00377 sql = macroDate(sql, MACRO_NOW, now, currentClock, idxs); 00378 if (currentDate > DATE_OFF) 00379 sql = macroDate(sql, MACRO_CURRENT_DATE, currentDate, currentClock, idxs); 00380 if (currentTimestamp > DATE_OFF) 00381 sql = macroDate(sql, MACRO_CURRENT_TIMESTAMP, currentTimestamp, 00382 currentClock, idxs); 00383 if (currentTime > DATE_OFF) 00384 sql = macroDate(sql, MACRO_CURRENT_TIME, currentTime, currentClock, idxs); 00385 if (timeOfDay > DATE_OFF) 00386 sql = macroDate(sql, MACRO_TIMEODFAY, timeOfDay, currentClock, idxs); 00387 00388 return sql; 00389 } 00390 00397 private Integer[] getQuoteIndexes(String sql) 00398 { 00399 ArrayList list = new ArrayList(); 00400 for (int i = 0; i < sql.length(); i++) 00401 { 00402 char c = sql.charAt(i); 00403 if (c == '\'') 00404 list.add(new Integer(i)); 00405 } 00406 Integer[] intlist = new Integer[list.size()]; 00407 return (Integer[]) list.toArray(intlist); 00408 } 00409 00419 private boolean shouldReplaceMacro(int idx, Integer[] list) 00420 { 00421 int count = 0; 00422 while (count < list.length && list[count].intValue() < idx) 00423 { 00424 count++; 00425 } 00426 return count % 2 == 0; 00427 } 00428 00429 }

CJDBCversion1.0.4に対してTue Oct 12 15:15:57 2004に生成されました。 doxygen 1.3.8