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 */
027 @SuppressWarnings("serial")
028 public class Stored<T> extends AbstractBehavior<T> {
029
030 private final ObjectReference<Instance<T>> instanceReference;
031 private final ComponentLifecycle lifecycleDelegate;
032
033 public Stored(ComponentAdapter<T> delegate, ObjectReference<Instance<T>> reference) {
034 super(delegate);
035 instanceReference = reference;
036 this.lifecycleDelegate = hasLifecycle(delegate)
037 ? new RealComponentLifecycle<T>() : new NoComponentLifecycle<T>();
038 }
039
040 private void guardInstRef() {
041 if (instanceReference.get() == null) {
042 instanceReference.set(new Instance<T>());
043 }
044 }
045
046 public boolean componentHasLifecycle() {
047 return lifecycleDelegate.componentHasLifecycle();
048 }
049
050 /**
051 * Disposes the cached component instance
052 * {@inheritDoc}
053 */
054 public void dispose(PicoContainer container) {
055 lifecycleDelegate.dispose(container);
056 }
057
058 /**
059 * Retrieves the stored reference. May be null if it has
060 * never been set, or possibly if the reference has been
061 * flushed.
062 *
063 * @return the stored object or null.
064 */
065 public T getStoredObject() {
066 guardInstRef();
067 return instanceReference.get().instance;
068 }
069
070 /**
071 * Flushes the cache.
072 * If the component instance is started is will stop and dispose it before
073 * flushing the cache.
074 */
075 public void flush() {
076 Instance<T> inst = instanceReference.get();
077 if (inst != null) {
078 Object instance = inst.instance;
079 if (instance != null && instanceReference.get().started) {
080 stop(instance);
081 dispose(instance);
082 }
083 instanceReference.set(null);
084 }
085 }
086
087 public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
088 guardInstRef();
089 T instance = instanceReference.get().instance;
090 if (instance == null) {
091 instance = super.getComponentInstance(container, into);
092 instanceReference.get().instance = instance;
093 }
094 return instance;
095 }
096
097 public String getDescriptor() {
098 return "Stored" + getLifecycleDescriptor();
099 }
100
101 protected String getLifecycleDescriptor() {
102 return (lifecycleDelegate.componentHasLifecycle() ? "+Lifecycle" : "");
103 }
104
105 /**
106 * Starts the cached component instance
107 * {@inheritDoc}
108 */
109 public void start(PicoContainer container) {
110 lifecycleDelegate.start(container);
111 }
112
113 /**
114 * Stops the cached component instance
115 * {@inheritDoc}
116 */
117 public void stop(PicoContainer container) {
118 lifecycleDelegate.stop(container);
119 }
120
121 public boolean isStarted() {
122 return lifecycleDelegate.isStarted();
123 }
124
125 private class RealComponentLifecycle<T> implements ComponentLifecycle<T>, Serializable {
126
127 public void start(PicoContainer container) {
128 guardInstRef();
129 guardAlreadyDisposed();
130 guardStartState(true, "already started");
131 // Lazily make the component if applicable
132 Stored.this.start(getComponentInstance(container, NOTHING.class));
133 instanceReference.get().started = true;
134 }
135
136 public void stop(PicoContainer container) {
137 guardInstRef();
138 guardAlreadyDisposed();
139 guardNotInstantiated();
140 guardStartState(false, "not started");
141 Stored.this.stop(instanceReference.get().instance);
142 instanceReference.get().started = false;
143
144 }
145
146 public void dispose(PicoContainer container) {
147 guardInstRef();
148 Instance<?> instance = instanceReference.get();
149 if (instance.instance != null) {
150 guardAlreadyDisposed();
151 Stored.this.dispose(instance.instance);
152 instance.disposed = true;
153 }
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 }