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 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant * 009 *****************************************************************************/ 010 011 package org.picocontainer.defaults; 012 013 import org.picocontainer.ComponentAdapter; 014 import org.picocontainer.LifecycleManager; 015 import org.picocontainer.PicoContainer; 016 import org.picocontainer.PicoInitializationException; 017 import org.picocontainer.PicoIntrospectionException; 018 019 /** 020 * <p> 021 * {@link ComponentAdapter} implementation that caches the component instance. 022 * </p> 023 * <p> 024 * This adapter supports components with a lifecycle, as it is a {@link LifecycleManager lifecycle manager} 025 * which will apply the delegate's {@link LifecycleStrategy lifecycle strategy} to the cached component instance. 026 * The lifecycle state is maintained so that the component instance behaves in the expected way: 027 * it can't be started if already started, it can't be started or stopped if disposed, it can't 028 * be stopped if not started, it can't be disposed if already disposed. 029 * </p> 030 * 031 * @author Mauro Talevi 032 * @version $Revision: 2827 $ 033 */ 034 public class CachingComponentAdapter extends DecoratingComponentAdapter implements LifecycleManager { 035 036 private ObjectReference instanceReference; 037 private boolean disposed; 038 private boolean started; 039 private boolean delegateHasLifecylce; 040 041 public CachingComponentAdapter(ComponentAdapter delegate) { 042 this(delegate, new SimpleReference()); 043 } 044 045 public CachingComponentAdapter(ComponentAdapter delegate, ObjectReference instanceReference) { 046 super(delegate); 047 this.instanceReference = instanceReference; 048 this.disposed = false; 049 this.started = false; 050 this.delegateHasLifecylce = delegate instanceof LifecycleStrategy 051 && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation()); 052 } 053 054 public Object getComponentInstance(PicoContainer container) 055 throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException { 056 Object instance = instanceReference.get(); 057 if (instance == null) { 058 instance = super.getComponentInstance(container); 059 instanceReference.set(instance); 060 } 061 return instance; 062 } 063 064 /** 065 * Flushes the cache. 066 * If the component instance is started is will stop and dispose it before 067 * flushing the cache. 068 */ 069 public void flush() { 070 Object instance = instanceReference.get(); 071 if ( instance != null && delegateHasLifecylce && started ) { 072 stop(instance); 073 dispose(instance); 074 } 075 instanceReference.set(null); 076 } 077 078 /** 079 * Starts the cached component instance 080 * {@inheritDoc} 081 */ 082 public void start(PicoContainer container) { 083 if ( delegateHasLifecylce ){ 084 if (disposed) throw new IllegalStateException("Already disposed"); 085 if (started) throw new IllegalStateException("Already started"); 086 start(getComponentInstance(container)); 087 started = true; 088 } 089 } 090 091 /** 092 * Stops the cached component instance 093 * {@inheritDoc} 094 */ 095 public void stop(PicoContainer container) { 096 if ( delegateHasLifecylce ){ 097 if (disposed) throw new IllegalStateException("Already disposed"); 098 if (!started) throw new IllegalStateException("Not started"); 099 stop(getComponentInstance(container)); 100 started = false; 101 } 102 } 103 104 /** 105 * Disposes the cached component instance 106 * {@inheritDoc} 107 */ 108 public void dispose(PicoContainer container) { 109 if ( delegateHasLifecylce ){ 110 if (disposed) throw new IllegalStateException("Already disposed"); 111 dispose(getComponentInstance(container)); 112 disposed = true; 113 } 114 } 115 116 public boolean hasLifecycle() { 117 return delegateHasLifecylce; 118 } 119 120 }