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 }