001 /***************************************************************************** 002 * Copyright (C) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original Code By Centerline Computers, Inc. * 009 *****************************************************************************/ 010 011 package org.picocontainer.gems.containers; 012 013 import java.io.ObjectInputStream; 014 import java.io.ObjectOutputStream; 015 import java.io.Serializable; 016 import java.util.Collection; 017 import java.util.List; 018 019 import org.apache.log4j.Logger; 020 import org.picocontainer.ComponentAdapter; 021 import org.picocontainer.MutablePicoContainer; 022 import org.picocontainer.Parameter; 023 import org.picocontainer.PicoContainer; 024 import org.picocontainer.PicoVerificationException; 025 import org.picocontainer.PicoVisitor; 026 027 /** 028 * Decorates a MutablePicoContainer to provide extensive tracing capabilities 029 * for all function calls into the Picocontainers. 030 * <p> 031 * By default, this class uses <tt>org.picocontainer.PicoContainer</tt> as its 032 * logging category, however, this may be changed by providing the logger in its 033 * alternate constructor. 034 * </p> 035 * <p> 036 * Start and Stop events are logged under <tt>info</tt> priority, as are all 037 * conditions where querying for an object returns a null object (e.g., 038 * getComponentAdapter(Object) returns null). All other functions use 039 * <tt>debug</tt> priority. 040 * </p> 041 * <p> 042 * If used in nanocontainer, you can add wrap your PicoContainer with the 043 * Log4jTracingContainerDecorator: (Groovy Example) 044 * </p> 045 * 046 * <pre> 047 * pico = builder.container(parent: parent) { 048 * //component(.....) 049 * //And others. 050 * } 051 * 052 * //Wrap the underlying NanoContainer with a Decorated Pico. 053 * pico = new org.picocontainer.gems.containers.Log4jTracingContainerDecorator (pico.getPico()) 054 * </pre> 055 * 056 * @author Michael Rimov 057 * @since Version 1.3 058 */ 059 public class Log4jTracingContainerDecorator implements MutablePicoContainer, Serializable { 060 061 /** 062 * Wrapped container. 063 */ 064 private final MutablePicoContainer delegate; 065 066 /** 067 * Logger instance used for writing events. 068 */ 069 private transient Logger logger; 070 071 /** 072 * Default typical wrapper that wraps another MutablePicoContainer. 073 * 074 * @param delegate 075 * Container to be decorated. 076 * @throws NullPointerException 077 * if delegate is null. 078 */ 079 public Log4jTracingContainerDecorator(final MutablePicoContainer delegate) { 080 this(delegate, Logger.getLogger(PicoContainer.class)); 081 } 082 083 /** 084 * Alternate constructor that allows specification of the Logger to use. 085 * 086 * @param delegate 087 * Container to be decorated. 088 * @param logger 089 * specific Log4j Logger to use. 090 * @throws NullPointerException 091 * if delegate or logger is null. 092 */ 093 public Log4jTracingContainerDecorator(final MutablePicoContainer delegate, final Logger logger) { 094 if (delegate == null) { 095 throw new NullPointerException("delegate"); 096 } 097 098 if (logger == null) { 099 throw new NullPointerException("logger"); 100 } 101 102 this.delegate = delegate; 103 this.logger = logger; 104 } 105 106 /** 107 * Standard message handling for cases when a null object is returned for a 108 * given key. 109 * 110 * @param componentKey 111 * @param target 112 */ 113 protected void onKeyDoesntExistInContainer(final Object componentKey, final Logger target) { 114 logger.info("Could not find component " + ((componentKey != null) ? componentKey.toString() : " null ") 115 + " in container or parent container."); 116 } 117 118 /** 119 * {@inheritDoc} 120 * 121 * @param visitor 122 * @see org.picocontainer.PicoContainer#accept(org.picocontainer.PicoVisitor) 123 */ 124 public void accept(final PicoVisitor visitor) { 125 if (logger.isDebugEnabled()) { 126 logger.debug("Visiting Container " + delegate + " with visitor " + visitor); 127 } 128 delegate.accept(visitor); 129 } 130 131 /** 132 * {@inheritDoc} 133 * 134 * @param child 135 * @return 136 * @see org.picocontainer.MutablePicoContainer#addChildContainer(org.picocontainer.PicoContainer) 137 */ 138 public boolean addChildContainer(final PicoContainer child) { 139 if (logger.isDebugEnabled()) { 140 logger.debug("Adding child container: " + child + " to container " + delegate); 141 } 142 return delegate.addChildContainer(child); 143 } 144 145 /** 146 * {@inheritDoc} 147 * 148 * @see org.picocontainer.Disposable#dispose() 149 */ 150 public void dispose() { 151 if (logger.isDebugEnabled()) { 152 logger.debug("Disposing container " + delegate); 153 } 154 delegate.dispose(); 155 } 156 157 /** 158 * {@inheritDoc} 159 * 160 * @param componentKey 161 * @return 162 * @see org.picocontainer.PicoContainer#getComponentAdapter(java.lang.Object) 163 */ 164 public ComponentAdapter getComponentAdapter(final Object componentKey) { 165 if (logger.isDebugEnabled()) { 166 logger.debug("Locating component adapter with key " + componentKey); 167 } 168 169 ComponentAdapter adapter = delegate.getComponentAdapter(componentKey); 170 if (adapter == null) { 171 onKeyDoesntExistInContainer(componentKey, logger); 172 } 173 return adapter; 174 } 175 176 /** 177 * {@inheritDoc} 178 * 179 * @param componentType 180 * @return ComponentAdapter or null. 181 * @see org.picocontainer.PicoContainer#getComponentAdapterOfType(java.lang.Class) 182 */ 183 public ComponentAdapter getComponentAdapterOfType(final Class componentType) { 184 if (logger.isDebugEnabled()) { 185 logger.debug("Locating component adapter with type " + componentType); 186 } 187 188 ComponentAdapter ca = delegate.getComponentAdapterOfType(componentType); 189 190 if (ca == null) { 191 onKeyDoesntExistInContainer(ca, logger); 192 } 193 return ca; 194 } 195 196 /** 197 * {@inheritDoc} 198 * 199 * @return Collection or null. 200 * @see org.picocontainer.PicoContainer#getComponentAdapters() 201 */ 202 public Collection getComponentAdapters() { 203 if (logger.isDebugEnabled()) { 204 logger.debug("Grabbing all component adapters for container: " + delegate); 205 } 206 return delegate.getComponentAdapters(); 207 } 208 209 /** 210 * {@inheritDoc} 211 * 212 * @param componentType 213 * @return List of ComponentAdapters 214 * @see org.picocontainer.PicoContainer#getComponentAdaptersOfType(java.lang.Class) 215 */ 216 public List getComponentAdaptersOfType(final Class componentType) { 217 if (logger.isDebugEnabled()) { 218 logger.debug("Grabbing all component adapters for container: " + delegate + " of type: " 219 + componentType.getName()); 220 } 221 return delegate.getComponentAdaptersOfType(componentType); 222 } 223 224 /** 225 * {@inheritDoc} 226 * 227 * @param componentKey 228 * @return 229 * @see org.picocontainer.PicoContainer#getComponentInstance(java.lang.Object) 230 */ 231 public Object getComponentInstance(final Object componentKey) { 232 233 if (logger.isDebugEnabled()) { 234 logger.debug("Attempting to load component instance with key: " + componentKey + " for container " 235 + delegate); 236 237 } 238 239 Object result = delegate.getComponentInstance(componentKey); 240 if (result == null) { 241 onKeyDoesntExistInContainer(componentKey, logger); 242 } 243 244 return result; 245 } 246 247 /** 248 * {@inheritDoc} 249 * 250 * @param componentType 251 * @return 252 * @see org.picocontainer.PicoContainer#getComponentInstanceOfType(java.lang.Class) 253 */ 254 public Object getComponentInstanceOfType(final Class componentType) { 255 if (logger.isDebugEnabled()) { 256 logger.debug("Attempting to load component instance with type: " + componentType + " for container " 257 + delegate); 258 259 } 260 261 Object result = delegate.getComponentInstanceOfType(componentType); 262 if (result == null) { 263 if (logger.isInfoEnabled()) { 264 logger.info("No component of type " + componentType.getName() + " was found in container: " + delegate); 265 } 266 } 267 268 return result; 269 } 270 271 /** 272 * {@inheritDoc} 273 * 274 * @return 275 * @see org.picocontainer.PicoContainer#getComponentInstances() 276 */ 277 public List getComponentInstances() { 278 if (logger.isDebugEnabled()) { 279 logger.debug("Retrieving all component instances for container " + delegate); 280 } 281 return delegate.getComponentInstances(); 282 } 283 284 /** 285 * {@inheritDoc} 286 * 287 * @param componentType 288 * @return 289 * @see org.picocontainer.PicoContainer#getComponentInstancesOfType(java.lang.Class) 290 */ 291 public List getComponentInstancesOfType(final Class componentType) { 292 if (logger.isDebugEnabled()) { 293 logger.debug("Loading all component instances of type " + componentType + " for container " + delegate); 294 } 295 List result = delegate.getComponentInstancesOfType(componentType); 296 if (result == null || result.size() == 0) { 297 if (logger.isInfoEnabled()) { 298 logger.info("Could not find any components " + " in container or parent container."); 299 } 300 } 301 302 return result; 303 } 304 305 /** 306 * {@inheritDoc} 307 * 308 * @return 309 * @see org.picocontainer.PicoContainer#getParent() 310 */ 311 public PicoContainer getParent() { 312 if (logger.isDebugEnabled()) { 313 logger.debug("Retrieving the parent for container " + delegate); 314 } 315 316 return delegate.getParent(); 317 } 318 319 /** 320 * {@inheritDoc} 321 * 322 * @return 323 * @see org.picocontainer.MutablePicoContainer#makeChildContainer() 324 */ 325 public MutablePicoContainer makeChildContainer() { 326 if (logger.isDebugEnabled()) { 327 logger.debug("Making child container for container " + delegate); 328 } 329 330 // Wrap the new delegate 331 return new Log4jTracingContainerDecorator(delegate.makeChildContainer()); 332 } 333 334 /** 335 * {@inheritDoc} 336 * 337 * @param componentAdapter 338 * @return 339 * @see org.picocontainer.MutablePicoContainer#registerComponent(org.picocontainer.ComponentAdapter) 340 */ 341 public ComponentAdapter registerComponent(final ComponentAdapter componentAdapter) { 342 if (logger.isDebugEnabled()) { 343 logger.debug("Registering component adapter " + componentAdapter); 344 } 345 346 return delegate.registerComponent(componentAdapter); 347 } 348 349 /** 350 * {@inheritDoc} 351 * 352 * @param componentImplementation 353 * @return 354 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Class) 355 */ 356 public ComponentAdapter registerComponentImplementation(final Class componentImplementation) { 357 if (logger.isDebugEnabled()) { 358 logger.debug("Registering component implementation " + componentImplementation.getName()); 359 } 360 361 return delegate.registerComponentImplementation(componentImplementation); 362 } 363 364 /** 365 * {@inheritDoc} 366 * 367 * @param componentKey 368 * @param componentImplementation 369 * @param parameters 370 * @return 371 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Object, 372 * java.lang.Class, org.picocontainer.Parameter[]) 373 */ 374 public ComponentAdapter registerComponentImplementation(final Object componentKey, 375 final Class componentImplementation, final Parameter[] parameters) { 376 377 if (logger.isDebugEnabled()) { 378 logger.debug("Registering component implementation with key " + componentKey + " and implementation " 379 + componentImplementation.getName() + " using parameters " + parameters); 380 } 381 382 return delegate.registerComponentImplementation(componentKey, componentImplementation, parameters); 383 } 384 385 /** 386 * {@inheritDoc} 387 * 388 * @param componentKey 389 * @param componentImplementation 390 * @return 391 * @see org.picocontainer.MutablePicoContainer#registerComponentImplementation(java.lang.Object, 392 * java.lang.Class) 393 */ 394 public ComponentAdapter registerComponentImplementation(final Object componentKey, 395 final Class componentImplementation) { 396 if (logger.isDebugEnabled()) { 397 logger.debug("Registering component implementation with key " + componentKey + " and implementation " 398 + componentImplementation.getName()); 399 } 400 401 return delegate.registerComponentImplementation(componentKey, componentImplementation); 402 } 403 404 /** 405 * {@inheritDoc} 406 * 407 * @param componentKey 408 * @param componentInstance 409 * @return 410 * @see org.picocontainer.MutablePicoContainer#registerComponentInstance(java.lang.Object, 411 * java.lang.Object) 412 */ 413 public ComponentAdapter registerComponentInstance(final Object componentKey, final Object componentInstance) { 414 if (logger.isDebugEnabled()) { 415 logger.debug("Registering component instance with key " + componentKey + " and instance " 416 + componentInstance + "(class: " 417 + ((componentInstance != null) ? componentInstance.getClass().getName() : " null ")); 418 } 419 420 return delegate.registerComponentInstance(componentKey, componentInstance); 421 } 422 423 /** 424 * {@inheritDoc} 425 * 426 * @param componentInstance 427 * @return 428 * @see org.picocontainer.MutablePicoContainer#registerComponentInstance(java.lang.Object) 429 */ 430 public ComponentAdapter registerComponentInstance(final Object componentInstance) { 431 if (logger.isDebugEnabled()) { 432 logger.debug("Registering component instance " + componentInstance + "(class: " 433 + ((componentInstance != null) ? componentInstance.getClass().getName() : " null ")); 434 } 435 436 return delegate.registerComponentInstance(componentInstance); 437 } 438 439 /** 440 * {@inheritDoc} 441 * 442 * @param child 443 * @return 444 * @see org.picocontainer.MutablePicoContainer#removeChildContainer(org.picocontainer.PicoContainer) 445 */ 446 public boolean removeChildContainer(final PicoContainer child) { 447 if (logger.isDebugEnabled()) { 448 logger.debug("Removing child container: " + child + " from parent: " + delegate); 449 } 450 return delegate.removeChildContainer(child); 451 } 452 453 /** 454 * {@inheritDoc} 455 * 456 * @see org.picocontainer.Startable#start() 457 */ 458 public void start() { 459 if (logger.isInfoEnabled()) { 460 logger.info("Starting Container " + delegate); 461 } 462 463 delegate.start(); 464 } 465 466 /** 467 * {@inheritDoc} 468 * 469 * @see org.picocontainer.Startable#stop() 470 */ 471 public void stop() { 472 if (logger.isInfoEnabled()) { 473 logger.info("Stopping Container " + delegate); 474 } 475 delegate.stop(); 476 } 477 478 /** 479 * {@inheritDoc} 480 * 481 * @param componentKey 482 * @return 483 * @see org.picocontainer.MutablePicoContainer#unregisterComponent(java.lang.Object) 484 */ 485 public ComponentAdapter unregisterComponent(final Object componentKey) { 486 if (logger.isDebugEnabled()) { 487 logger.debug("Unregistering component " + componentKey + " from container " + delegate); 488 } 489 490 return delegate.unregisterComponent(componentKey); 491 } 492 493 /** 494 * {@inheritDoc} 495 * 496 * @param componentInstance 497 * @return 498 * @see org.picocontainer.MutablePicoContainer#unregisterComponentByInstance(java.lang.Object) 499 */ 500 public ComponentAdapter unregisterComponentByInstance(final Object componentInstance) { 501 if (logger.isDebugEnabled()) { 502 logger.debug("Unregistering component by instance (" + componentInstance + ") from container " + delegate); 503 } 504 505 return delegate.unregisterComponentByInstance(componentInstance); 506 } 507 508 /** 509 * {@inheritDoc} 510 * 511 * @throws PicoVerificationException 512 * @deprecated 513 * @see org.picocontainer.PicoContainer#verify() 514 */ 515 public void verify() throws PicoVerificationException { 516 logger.info("Verifying container"); 517 logger.warn("Using deprecated function PicoContainer.verify(). " 518 + "Please use VerifyingVisitor instead."); 519 delegate.verify(); 520 } 521 522 /** 523 * Retrieves the logger instance used by this decorator. 524 * 525 * @return Logger instance. 526 */ 527 public Logger getLoggerUsed() { 528 return this.logger; 529 } 530 531 private void readObject(final ObjectInputStream s) throws java.io.IOException, java.lang.ClassNotFoundException { 532 533 s.defaultReadObject(); 534 String loggerName = s.readUTF(); 535 logger = Logger.getLogger(loggerName); 536 } 537 538 private void writeObject(final ObjectOutputStream s) throws java.io.IOException { 539 s.defaultWriteObject(); 540 s.writeUTF(logger.getName()); 541 } 542 543 }