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 *****************************************************************************/
009 package org.picocontainer.behaviors;
010
011 import org.picocontainer.ComponentAdapter;
012 import org.picocontainer.LifecycleStrategy;
013 import org.picocontainer.ObjectReference;
014 import org.picocontainer.PicoCompositionException;
015 import org.picocontainer.PicoContainer;
016 import org.picocontainer.ComponentLifecycle;
017
018 import java.lang.reflect.Type;
019 import java.io.Serializable;
020
021 /**
022 * behaviour for all behaviours wishing to store
023 * their component in "awkward places" ( object references )
024 *
025 * @author Konstantin Pribluda
026 * @param <T>
027 */
028 @SuppressWarnings("serial")
029 public class Stored<T> extends AbstractBehavior<T> {
030
031 private final ObjectReference<Instance<T>> instanceReference;
032 private final ComponentLifecycle lifecycleDelegate;
033
034 public Stored(ComponentAdapter<T> delegate, ObjectReference<Instance<T>> reference) {
035 super(delegate);
036 instanceReference = reference;
037 this.lifecycleDelegate = hasLifecycle(delegate)
038 ? new RealComponentLifecycle<T>() : new NoComponentLifecycle<T>();
039 }
040
041 private void guardInstRef() {
042 if (instanceReference.get() == null) {
043 instanceReference.set(new Instance());
044 }
045 }
046
047 public boolean componentHasLifecycle() {
048 return lifecycleDelegate.componentHasLifecycle();
049 }
050
051 /**
052 * Disposes the cached component instance
053 * {@inheritDoc}
054 */
055 public void dispose(PicoContainer container) {
056 lifecycleDelegate.dispose(container);
057 }
058
059 /**
060 * Retrieves the stored reference. May be null if it has
061 * never been set, or possibly if the reference has been
062 * flushed.
063 *
064 * @return the stored object or null.
065 */
066 public T getStoredObject() {
067 guardInstRef();
068 return instanceReference.get().instance;
069 }
070
071 /**
072 * Flushes the cache.
073 * If the component instance is started is will stop and dispose it before
074 * flushing the cache.
075 */
076 public void flush() {
077 Instance<T> inst = instanceReference.get();
078 if (inst != null) {
079 Object instance = inst.instance;
080 if (instance != null && instanceReference.get().started) {
081 stop(instance);
082 dispose(instance);
083 }
084 instanceReference.set(null);
085 }
086 }
087
088 public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
089 guardInstRef();
090 T instance = instanceReference.get().instance;
091 if (instance == null) {
092 instance = super.getComponentInstance(container, into);
093 instanceReference.get().instance = instance;
094 }
095 return instance;
096 }
097
098 public String getDescriptor() {
099 return "Stored" + getLifecycleDescriptor();
100 }
101
102 protected String getLifecycleDescriptor() {
103 return (lifecycleDelegate.componentHasLifecycle() ? "+Lifecycle" : "");
104 }
105
106 /**
107 * Starts the cached component instance
108 * {@inheritDoc}
109 */
110 public void start(PicoContainer container) {
111 lifecycleDelegate.start(container);
112 }
113
114 /**
115 * Stops the cached component instance
116 * {@inheritDoc}
117 */
118 public void stop(PicoContainer container) {
119 lifecycleDelegate.stop(container);
120
121 }
122
123 public boolean isStarted() {
124 return lifecycleDelegate.isStarted();
125 }
126
127 private class RealComponentLifecycle<T> implements ComponentLifecycle<T>, Serializable {
128
129 public void start(PicoContainer container) {
130 guardInstRef();
131 guardAlreadyDisposed();
132 guardStartState(true, "already started");
133 // Lazily make the component if applicable
134 Stored.this.start(getComponentInstance(container, NOTHING.class));
135 instanceReference.get().started = true;
136 }
137
138 public void stop(PicoContainer container) {
139 guardInstRef();
140 guardAlreadyDisposed();
141 guardNotInstantiated();
142 guardStartState(false, "not started");
143 Stored.this.stop(instanceReference.get().instance);
144 instanceReference.get().started = false;
145
146 }
147
148 public void dispose(PicoContainer container) {
149 guardInstRef();
150 guardNotInstantiated();
151 guardAlreadyDisposed();
152 Stored.this.dispose(instanceReference.get().instance);
153 instanceReference.get().disposed = true;
154 }
155
156
157 private void guardNotInstantiated() {
158 if (instanceReference.get().instance == null)
159 throw new IllegalStateException("'" + getComponentKey() + "' not instantiated");
160 }
161
162 private void guardStartState(boolean unexpectedStartState, String message) {
163 if (instanceReference.get().started == unexpectedStartState)
164 throw new IllegalStateException("'" + getComponentKey() + "' " + message);
165 }
166
167 private void guardAlreadyDisposed() {
168 if (instanceReference.get().disposed)
169 throw new IllegalStateException("'" + getComponentKey() + "' already disposed");
170 }
171
172 public boolean componentHasLifecycle() {
173 return true;
174 }
175
176 public boolean isStarted() {
177 guardInstRef();
178 return instanceReference.get().started;
179 }
180 }
181
182 private static class NoComponentLifecycle<T> implements ComponentLifecycle<T>, Serializable {
183 public void start(PicoContainer container) {
184 }
185
186 public void stop(PicoContainer container) {
187 }
188
189 public void dispose(PicoContainer container) {
190 }
191
192 public boolean componentHasLifecycle() {
193 return false;
194 }
195
196 public boolean isStarted() {
197 return false;
198 }
199 }
200
201 private static boolean hasLifecycle(ComponentAdapter delegate) {
202 return delegate instanceof LifecycleStrategy
203 && ((LifecycleStrategy) delegate).hasLifecycle(delegate.getComponentImplementation());
204 }
205
206 public static class Instance<T> implements Serializable {
207 private T instance;
208 protected boolean started;
209 protected boolean disposed;
210 }
211
212
213
214 }