1 22 23 package org.continuent.sequoia.controller.sql.macros; 24 25 import java.util.ArrayList ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.regex.Matcher ; 29 30 import org.continuent.sequoia.common.log.Trace; 31 import org.continuent.sequoia.common.xml.DatabasesXmlTags; 32 import org.continuent.sequoia.common.xml.XmlComponent; 33 import org.continuent.sequoia.controller.requests.AbstractRequest; 34 35 41 public class MacrosHandler implements XmlComponent 42 { 43 private List macros; 44 private Trace logger = Trace 45 .getLogger("org.continuent.sequoia.controller.RequestManager"); 46 47 50 public MacrosHandler() 51 { 52 macros = new ArrayList (); 53 } 54 55 61 public synchronized void addMacro(AbstractMacro macro) 62 { 63 if (macros.contains(macro)) 64 { 65 if (logger.isInfoEnabled()) 66 logger.info("Replacing macro " + macro.getMacroName()); 67 macros.set(macros.indexOf(macro), macro); 68 } 69 else 70 { 71 if (logger.isDebugEnabled()) 72 logger.debug("Adding macro processing for macro " 73 + macro.getMacroName()); 74 macros.add(macro); 75 } 76 } 77 78 84 public synchronized boolean removeMacro(AbstractMacro macro) 85 { 86 return macros.remove(macro); 87 } 88 89 94 public String getXml() 95 { 96 StringBuffer sb = new StringBuffer (); 97 sb.append("<" + DatabasesXmlTags.ELT_MacroHandling + ">"); 98 for (Iterator iter = macros.iterator(); iter.hasNext();) 99 { 100 AbstractMacro macro = (AbstractMacro) iter.next(); 101 sb.append(macro.getXml()); 102 } 103 sb.append("</" + DatabasesXmlTags.ELT_MacroHandling + ">"); 104 return sb.toString(); 105 } 106 107 114 public final void processMacros(AbstractRequest request) 115 { 116 if (macros.isEmpty() || request.getMacrosAreProcessed()) 117 return; 118 119 if (logger.isDebugEnabled()) 120 logger.debug("Processing macros in request " + request.getId() + " (" 121 + request + ")"); 122 123 request.setSqlOrTemplate(replaceMacrosInString(request.getSqlOrTemplate())); 125 126 if (request.getPreparedStatementParameters() != null) 128 request.setPreparedStatementParameters(replaceMacrosInString(request 129 .getPreparedStatementParameters())); 130 131 if (logger.isDebugEnabled()) 132 logger.debug("Macros processed in request " + request.getId() 133 + ", new request is: " + request); 134 } 135 136 144 private QuoteIndicesAndReplacedSql processMacro( 145 QuoteIndicesAndReplacedSql quotes, AbstractMacro macro, long currentClock) 146 { 147 Matcher m = macro.getMacroPattern().matcher(quotes.getReplacedSql()); 148 149 if (m.find()) 150 { StringBuffer sql = null; 152 int[] quoteIdxs = quotes.getQuoteIdxs(); 153 int[] doubleQuoteIdxs = quotes.getDoubleQuoteIdxs(); 154 155 do 156 { 157 if (shouldReplaceMacro(m.start(), quoteIdxs) 158 && shouldReplaceMacro(m.start(), doubleQuoteIdxs)) 159 { 160 if (sql == null) 161 sql = new StringBuffer (quotes.getReplacedSql().length()); 162 m.appendReplacement(sql, macro.generateMacroValue(currentClock)); 163 } 164 } 165 while (m.find()); 166 if (sql != null) 167 { 168 m.appendTail(sql); 169 quotes.setReplacedSql(sql.toString()); 170 } 171 } 172 return quotes; 173 } 174 175 181 private String replaceMacrosInString(String sql) 182 { 183 QuoteIndicesAndReplacedSql sqlWithQuotes = new QuoteIndicesAndReplacedSql( 184 sql); 185 186 long currentClock = System.currentTimeMillis(); 187 for (Iterator iter = macros.iterator(); iter.hasNext();) 188 { 189 AbstractMacro macro = (AbstractMacro) iter.next(); 190 sqlWithQuotes = processMacro(sqlWithQuotes, macro, currentClock); 191 } 192 193 return sqlWithQuotes.getReplacedSql(); 194 } 195 196 202 private int[] getQuoteIndexes(String sql) 203 { 204 ArrayList list = new ArrayList (); 205 for (int i = 0; i < sql.length(); i++) 206 { 207 switch (sql.charAt(i)) 208 { 209 case '\'' : 210 list.add(new Integer (i)); 211 break; 212 case '\\' : 213 i++; 214 break; 215 default : 216 break; 217 } 218 } 219 int[] intList = new int[list.size()]; 220 for (int i = 0; i < intList.length; i++) 221 intList[i] = ((Integer ) list.get(i)).intValue(); 222 return intList; 223 } 224 225 231 private int[] getDoubleQuoteIndexes(String sql) 232 { 233 ArrayList list = new ArrayList (); 234 for (int i = 0; i < sql.length(); i++) 235 { 236 switch (sql.charAt(i)) 237 { 238 case '"' : 239 list.add(new Integer (i)); 240 break; 241 case '\\' : 242 i++; 243 break; 244 default : 245 break; 246 } 247 } 248 int[] intList = new int[list.size()]; 249 for (int i = 0; i < intList.length; i++) 250 intList[i] = ((Integer ) list.get(i)).intValue(); 251 return intList; 252 } 253 254 263 private boolean shouldReplaceMacro(int idx, int[] list) 264 { 265 int count = 0; 266 while (count < list.length && list[count] < idx) 267 { 268 count++; 269 } 270 return count % 2 == 0; 271 } 272 273 private class QuoteIndicesAndReplacedSql 274 { 275 private int[] quoteIdxs; 276 private int[] doubleQuoteIdxs; 277 private String replacedSql; 278 private boolean requiresQuoteComputation; 279 280 285 public QuoteIndicesAndReplacedSql(String sql) 286 { 287 replacedSql = sql; 288 requiresQuoteComputation = true; 289 } 290 291 private void computeQuotes() 292 { 293 quoteIdxs = getQuoteIndexes(replacedSql); 294 doubleQuoteIdxs = getDoubleQuoteIndexes(replacedSql); 295 requiresQuoteComputation = false; 296 } 297 298 303 public final int[] getDoubleQuoteIdxs() 304 { 305 if (requiresQuoteComputation) 306 computeQuotes(); 307 return doubleQuoteIdxs; 308 } 309 310 315 public final int[] getQuoteIdxs() 316 { 317 if (requiresQuoteComputation) 318 computeQuotes(); 319 return quoteIdxs; 320 } 321 322 327 public final String getReplacedSql() 328 { 329 return replacedSql; 330 } 331 332 337 public final void setReplacedSql(String replacedSql) 338 { 339 this.replacedSql = replacedSql; 340 requiresQuoteComputation = true; 341 } 342 } 343 } | Popular Tags |