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 }