1 19 20 package com.sslexplorer.boot; 21 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.io.OutputStream ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.regex.Matcher ; 30 import java.util.regex.Pattern ; 31 32 import org.apache.commons.logging.Log; 33 import org.apache.commons.logging.LogFactory; 34 35 64 65 public class ReplacementEngine { 66 67 final static Log log = LogFactory.getLog(ReplacementEngine.class); 68 69 private final StringBuffer inputBuffer = new StringBuffer (); 71 private final StringBuffer workBuffer = new StringBuffer (); 72 private List replacementsList = new ArrayList (); 73 private boolean caseSensitive = true; 74 private boolean dotAll = false; 75 private static PatternPool patternPool; 76 private String charset; 77 private Encoder encoder; 78 79 82 public ReplacementEngine() { 83 patternPool = new PatternPool(); 84 } 85 86 93 public void setEncoder(Encoder encoder) { 94 this.encoder = encoder; 95 } 96 97 102 public void setEncoding(String charset) { 103 this.charset = charset; 104 } 105 106 111 public static PatternPool getPatternPool() { 112 if (patternPool == null) { 113 patternPool = new PatternPool(); 114 } 115 return patternPool; 116 } 117 118 123 public void setDotAll(boolean dotAll) { 124 this.dotAll = dotAll; 125 } 126 127 132 public void setCaseSensitive(boolean caseSensitive) { 133 this.caseSensitive = caseSensitive; 134 } 135 136 144 public synchronized void addPattern(String pattern, Replacer replacer, String replacementPattern) { 145 replacementsList.add(new ReplaceOp(replacer, pattern, replacementPattern)); 148 } 149 150 157 public synchronized String replace(String input) { 158 Iterator it = replacementsList.iterator(); 159 160 inputBuffer.setLength(0); 161 inputBuffer.append(input); 162 163 workBuffer.setLength(0); 164 workBuffer.ensureCapacity(input.length()); 165 166 if (log.isDebugEnabled()) 167 log.debug("Starting replacement on string on " + input.length() + " characters"); 168 169 while (it.hasNext()) { 170 ReplaceOp op = (ReplaceOp) it.next(); 171 172 if (log.isDebugEnabled()) 173 log.debug("Replacemnt " + op.replacePattern + " [" + op.pattern + "]"); 174 175 Pattern p = getPatternPool().getPattern(op.pattern, caseSensitive, dotAll); 176 177 if (log.isDebugEnabled()) 178 log.debug("Got pattern from pool"); 179 180 try { 181 replaceInto(p, op.replacePattern, op.replacer, inputBuffer, workBuffer); 182 if (log.isDebugEnabled()) 183 log.debug("Replacement complete"); 184 } catch (Throwable t) { 185 if (log.isDebugEnabled()) 186 log.debug("Error replacing.", t); 187 } finally { 188 if (log.isDebugEnabled()) 189 log.debug("Releasing pattern from pool."); 190 patternPool.releasePattern(p); 191 } 192 inputBuffer.setLength(0); 193 inputBuffer.append(workBuffer); 194 } 195 if (log.isDebugEnabled()) 196 log.debug("Finished replacing. Returning string of " +inputBuffer.length() + "characters"); 197 return (inputBuffer.toString()); 198 } 199 200 214 public long replace(InputStream in, OutputStream out) throws IOException { 215 if (log.isDebugEnabled()) 216 log.debug("Replacing using streams, reading stream into memory"); 217 StringBuffer str = new StringBuffer (4096); 218 byte[] buf = new byte[32768]; 219 int read; 220 while ((read = in.read(buf)) > -1) { 221 str.append(charset == null ? new String (buf, 0, read) : new String (buf, 0, read, charset)); 222 if (log.isDebugEnabled()) 223 log.debug("Got block of " + read + ", waiting for next one"); 224 } 225 if (log.isDebugEnabled()) 226 log.debug("Read all blocks, performing replacement"); 227 byte[] b = charset == null ? replace(str.toString()).getBytes() : replace(str.toString()).getBytes(charset); 228 if (log.isDebugEnabled()) 229 log.debug("Writing replaced content back (" + b.length + " bytes)"); 230 out.write(b); 231 return b.length; 232 } 233 234 236 private void replaceInto(Pattern pattern, String replacementPattern, Replacer replacer, StringBuffer input, StringBuffer work) { 237 work.ensureCapacity(input.length()); 238 work.setLength(0); 239 if (log.isDebugEnabled()) 240 log.debug("Getting matcher"); 241 Matcher m = pattern.matcher(input); 242 log.debug("Got matcher, finding first occurence."); 243 while (m.find()) { 244 if (log.isDebugEnabled()) 245 log.debug("Found occurence"); 246 String repl = replacer.getReplacement(pattern, m, replacementPattern); 247 if (repl != null) { 248 if (log.isDebugEnabled()) 249 log.debug("Found replacement, appending"); 250 if(encoder == null) { 251 m.appendReplacement(work, Util.escapeForRegexpReplacement(repl)); 252 } 253 else { 254 m.appendReplacement(work, encoder.encode(Util.escapeForRegexpReplacement(repl))); 255 } 256 } 257 } 258 if (log.isDebugEnabled()) 259 log.debug("Processed matches, appending replacement."); 260 m.appendTail(work); 261 } 262 263 265 class ReplaceOp { 266 String pattern; 267 Replacer replacer; 268 String replacePattern; 269 270 ReplaceOp(Replacer replacer, String pattern, String replacePattern) { 271 this.replacer = replacer; 272 this.pattern = pattern; 273 this.replacePattern = replacePattern; 274 } 275 } 276 277 282 public static class PatternPool { 283 private HashMap patterns; 284 private HashMap locks; 285 286 PatternPool() { 287 patterns = new HashMap (); 288 locks = new HashMap (); 289 } 290 291 308 public Pattern getPattern(String pattern, boolean caseSensitive, boolean dotAll) { 309 String cacheKey = pattern + "_" + caseSensitive + "_" + dotAll; 310 List pool = null; 311 synchronized (patterns) { 312 pool = (List ) patterns.get(cacheKey); 313 if (pool == null) { 314 pool = new ArrayList (); 315 patterns.put(cacheKey, pool); 316 } 317 } 318 synchronized (pool) { 319 while (true) { 320 if (pool.size() < 10) { 321 Pattern p = Pattern.compile(pattern, (!caseSensitive ? Pattern.CASE_INSENSITIVE : 0) 322 + (dotAll ? Pattern.DOTALL : 0)); 323 pool.add(p); 324 locks.put(p, p); 325 if (log.isDebugEnabled()) 326 log.debug("Created new pattern and locked"); 327 return p; 328 } else { 329 for (Iterator i = pool.listIterator(); i.hasNext();) { 330 Pattern p = (Pattern ) i.next(); 331 if (!locks.containsKey(p)) { 332 if (log.isDebugEnabled()) 333 log.debug("Found a free pattern"); 334 locks.put(p, p); 335 return p; 336 } 337 } 338 synchronized (locks) { 339 try { 340 if (log.isDebugEnabled()) 341 log.debug("No free patterns, waiting for one to become available"); 342 locks.wait(); 343 } catch (Exception e) { 344 } 345 } 346 } 347 } 348 } 349 } 350 351 357 public void releasePattern(Pattern pattern) { 358 synchronized (locks) { 359 locks.remove(pattern); 360 locks.notifyAll(); 361 } 362 } 363 } 364 365 public interface Encoder { 366 public String encode(String decoded); 367 } 368 369 } | Popular Tags |