1 16 17 package org.springframework.aop.interceptor; 18 19 import java.util.Set ; 20 import java.util.regex.Matcher ; 21 import java.util.regex.Pattern ; 22 23 import org.aopalliance.intercept.MethodInvocation; 24 import org.apache.commons.logging.Log; 25 26 import org.springframework.core.Constants; 27 import org.springframework.util.Assert; 28 import org.springframework.util.ClassUtils; 29 import org.springframework.util.StopWatch; 30 import org.springframework.util.StringUtils; 31 32 73 public class CustomizableTraceInterceptor extends AbstractTraceInterceptor { 74 75 79 public static final String PLACEHOLDER_METHOD_NAME = "$[methodName]"; 80 81 86 public static final String PLACEHOLDER_TARGET_CLASS_NAME = "$[targetClassName]"; 87 88 93 public static final String PLACEHOLDER_TARGET_CLASS_SHORT_NAME = "$[targetClassShortName]"; 94 95 100 public static final String PLACEHOLDER_RETURN_VALUE = "$[returnValue]"; 101 102 107 public static final String PLACEHOLDER_ARGUMENT_TYPES = "$[argumentTypes]"; 108 109 115 public static final String PLACEHOLDER_ARGUMENTS = "$[arguments]"; 116 117 122 public static final String PLACEHOLDER_EXCEPTION = "$[exception]"; 123 124 128 public static final String PLACEHOLDER_INVOCATION_TIME = "$[invocationTime]"; 129 130 133 private static final String DEFAULT_ENTER_MESSAGE = 134 "Entering method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]"; 135 136 139 private static final String DEFAULT_EXIT_MESSAGE = 140 "Exiting method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]"; 141 142 145 private static final String DEFAULT_EXCEPTION_MESSAGE = 146 "Exception thrown in method '" + PLACEHOLDER_METHOD_NAME + "' of class [" + PLACEHOLDER_TARGET_CLASS_NAME + "]"; 147 148 151 private static final Pattern PATTERN = Pattern.compile("\\$\\[\\p{Alpha}+\\]"); 152 153 157 private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\$"); 158 159 162 private static final Set ALLOWED_PLACEHOLDERS = 163 new Constants(CustomizableTraceInterceptor.class).getValues("PLACEHOLDER_"); 164 165 166 169 private String enterMessage = DEFAULT_ENTER_MESSAGE; 170 171 174 private String exitMessage = DEFAULT_EXIT_MESSAGE; 175 176 179 private String exceptionMessage = DEFAULT_EXCEPTION_MESSAGE; 180 181 182 194 public void setEnterMessage(String enterMessage) throws IllegalArgumentException { 195 Assert.hasText(enterMessage, "'enterMessage' must not be empty"); 196 checkForInvalidPlaceholders(enterMessage); 197 Assert.doesNotContain(enterMessage, PLACEHOLDER_RETURN_VALUE, 198 "enterMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]"); 199 Assert.doesNotContain(enterMessage, PLACEHOLDER_EXCEPTION, 200 "enterMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]"); 201 Assert.doesNotContain(enterMessage, PLACEHOLDER_INVOCATION_TIME, 202 "enterMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]"); 203 this.enterMessage = enterMessage; 204 } 205 206 220 public void setExitMessage(String exitMessage) { 221 Assert.hasText(exitMessage, "'exitMessage' must not be empty"); 222 checkForInvalidPlaceholders(exitMessage); 223 Assert.doesNotContain(exitMessage, PLACEHOLDER_EXCEPTION, 224 "exitMessage cannot contain placeholder [" + PLACEHOLDER_EXCEPTION + "]"); 225 this.exitMessage = exitMessage; 226 } 227 228 241 public void setExceptionMessage(String exceptionMessage) { 242 Assert.hasText(exceptionMessage, "'exceptionMessage' must not be empty"); 243 checkForInvalidPlaceholders(exceptionMessage); 244 Assert.doesNotContain(exceptionMessage, PLACEHOLDER_RETURN_VALUE, 245 "exceptionMessage cannot contain placeholder [" + PLACEHOLDER_RETURN_VALUE + "]"); 246 Assert.doesNotContain(exceptionMessage, PLACEHOLDER_INVOCATION_TIME, 247 "exceptionMessage cannot contain placeholder [" + PLACEHOLDER_INVOCATION_TIME + "]"); 248 this.exceptionMessage = exceptionMessage; 249 } 250 251 252 261 protected Object invokeUnderTrace(MethodInvocation invocation, Log logger) throws Throwable { 262 String name = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName(); 263 StopWatch stopWatch = new StopWatch(name); 264 Object returnValue = null; 265 boolean exitThroughException = false; 266 try { 267 stopWatch.start(name); 268 writeToLog(logger, 269 replacePlaceholders(this.enterMessage, invocation, null, null, -1)); 270 returnValue = invocation.proceed(); 271 return returnValue; 272 } 273 catch (Throwable ex) { 274 if(stopWatch.isRunning()) { 275 stopWatch.stop(); 276 } 277 exitThroughException = true; 278 writeToLog(logger, 279 replacePlaceholders(this.exceptionMessage, invocation, null, ex, stopWatch.getTotalTimeMillis()), ex); 280 throw ex; 281 } 282 finally { 283 if (!exitThroughException) { 284 if(stopWatch.isRunning()) { 285 stopWatch.stop(); 286 } 287 writeToLog(logger, 288 replacePlaceholders(this.exitMessage, invocation, returnValue, null, stopWatch.getTotalTimeMillis())); 289 } 290 } 291 } 292 293 297 protected void writeToLog(Log logger, String message) { 298 writeToLog(logger, message, null); 299 } 300 301 307 protected void writeToLog(Log logger, String message, Throwable ex) { 308 if (ex != null) { 309 logger.trace(message, ex); 310 } 311 else { 312 logger.trace(message); 313 } 314 } 315 316 332 protected String replacePlaceholders(String message, MethodInvocation methodInvocation, 333 Object returnValue, Throwable throwable, long invocationTime) { 334 335 Matcher matcher = PATTERN.matcher(message); 336 337 StringBuffer output = new StringBuffer (); 338 while (matcher.find()) { 339 String match = matcher.group(); 340 if (PLACEHOLDER_METHOD_NAME.equals(match)) { 341 matcher.appendReplacement(output, methodInvocation.getMethod().getName()); 342 } 343 else if (PLACEHOLDER_TARGET_CLASS_NAME.equals(match)) { 344 String targetClassName = escape(methodInvocation.getThis().getClass().getName()); 345 matcher.appendReplacement(output, targetClassName); 346 } 347 else if (PLACEHOLDER_TARGET_CLASS_SHORT_NAME.equals(match)) { 348 matcher.appendReplacement(output, escape(ClassUtils.getShortName(methodInvocation.getThis().getClass()))); 349 } 350 else if (PLACEHOLDER_ARGUMENTS.equals(match)) { 351 matcher.appendReplacement(output, escape(StringUtils.arrayToCommaDelimitedString(methodInvocation.getArguments()))); 352 } 353 else if (PLACEHOLDER_ARGUMENT_TYPES.equals(match)) { 354 appendArgumentTypes(methodInvocation, matcher, output); 355 } 356 else if (PLACEHOLDER_RETURN_VALUE.equals(match)) { 357 appendReturnValue(methodInvocation, matcher, output, returnValue); 358 } 359 else if (throwable != null && PLACEHOLDER_EXCEPTION.equals(match)) { 360 matcher.appendReplacement(output, throwable.toString()); 361 } 362 else if (PLACEHOLDER_INVOCATION_TIME.equals(match)) { 363 matcher.appendReplacement(output, Long.toString(invocationTime)); 364 } 365 else { 366 throw new IllegalArgumentException ("Unknown placeholder [" + match + "]"); 368 } 369 } 370 matcher.appendTail(output); 371 372 return output.toString(); 373 } 374 375 384 private void appendReturnValue( 385 MethodInvocation methodInvocation, Matcher matcher, StringBuffer output, Object returnValue) { 386 387 if (methodInvocation.getMethod().getReturnType() == void.class) { 388 matcher.appendReplacement(output, "void"); 389 } 390 else if (returnValue == null) { 391 matcher.appendReplacement(output, "null"); 392 } 393 else { 394 matcher.appendReplacement(output, escape(returnValue.toString())); 395 } 396 } 397 398 408 private void appendArgumentTypes(MethodInvocation methodInvocation, Matcher matcher, StringBuffer output) { 409 Class [] argumentTypes = methodInvocation.getMethod().getParameterTypes(); 410 String [] argumentTypeShortNames = new String [argumentTypes.length]; 411 for (int i = 0; i < argumentTypeShortNames.length; i++) { 412 argumentTypeShortNames[i] = ClassUtils.getShortName(argumentTypes[i]); 413 } 414 matcher.appendReplacement(output, escape(StringUtils.arrayToCommaDelimitedString(argumentTypeShortNames))); 415 } 416 417 422 private void checkForInvalidPlaceholders(String message) throws IllegalArgumentException { 423 Matcher matcher = PATTERN.matcher(message); 424 while (matcher.find()) { 425 String match = matcher.group(); 426 if (!ALLOWED_PLACEHOLDERS.contains(match)) { 427 throw new IllegalArgumentException ("Placeholder [" + match + "] is not valid"); 428 } 429 } 430 } 431 432 435 private String escape(String input) { 436 Matcher matcher = ESCAPE_PATTERN.matcher(input); 437 StringBuffer output = new StringBuffer (input.length()); 438 while (matcher.find()) { 439 matcher.appendReplacement(output, ""); 440 output.append("\\").append(matcher.group()); 441 } 442 matcher.appendTail(output); 443 return output.toString(); 444 } 445 446 } 447 | Popular Tags |