1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.di.impl.providers;
17
18 import java.util.Set;
19
20 import net.sf.jguiraffe.di.BeanProvider;
21 import net.sf.jguiraffe.di.Dependency;
22 import net.sf.jguiraffe.di.DependencyProvider;
23 import net.sf.jguiraffe.di.impl.HelperInvocations;
24 import net.sf.jguiraffe.di.impl.Invokable;
25
26 /**
27 * <p>
28 * A specialized life-cycle supporting {@link BeanProvider} implementation for
29 * creating <em>singleton</em> beans.
30 * </p>
31 * <p>
32 * When the {@code getBean()} method of an instance of this class is called for
33 * the first time, all dependencies are resolved, and a new bean instance is
34 * created (using the specified creation bean provider). Following calls to
35 * {@code getBean()} always return this same bean instance. In fact, this
36 * provider then behaves like a constant bean provider: it does not declare any
37 * dependencies any more and does not need any synchronization support (i.e. the
38 * {@code getLockID()} method will always return <b>null</b>). This means that
39 * providers of this type can be efficiently used in a multi-threaded
40 * environment once they are initialized.
41 * </p>
42 * <p>
43 * Instances of this class can also be initialized with an {@link Invokable} to
44 * be called when the bean is no more needed. This {@link Invokable} is
45 * triggered by the {@code shutdown()} method. This mechanism makes it possible
46 * to perform cleanup when a bean store is closed.
47 * </p>
48 *
49 * @author Oliver Heger
50 * @version $Id: SingletonBeanProvider.java 208 2012-02-11 20:57:33Z oheger $
51 */
52 public class SingletonBeanProvider extends LifeCycleBeanProvider
53 {
54 /** Stores the invokable to be called when the provider is shut down.*/
55 private final Invokable shutdownHandler;
56
57 /**
58 * Creates a new instance of {@code SingletonBeanProvider} and initializes
59 * it with the bean provider for creating a bean instance and {@code
60 * Invokable} objects for initializing and releasing the bean managed by
61 * this provider.
62 *
63 * @param createProvider the bean provider used for creating a new bean
64 * instance (must not be <b>null</b>)
65 * @param initInv the (optional) invocation object for performing
66 * initialization
67 * @param shutdownInv the (optional) {@code Invokable} object to be called
68 * on shutdown
69 * @throws IllegalArgumentException if the bean provider is undefined
70 */
71 public SingletonBeanProvider(BeanProvider createProvider,
72 Invokable initInv, Invokable shutdownInv)
73 {
74 super(createProvider, initInv);
75 shutdownHandler = shutdownInv;
76 }
77
78 /**
79 * Creates a new instance of {@code SingletonBeanProvider} and
80 * initializes it with the bean provider for creating a bean instance and
81 * the invocation object for performing initialization.
82 *
83 * @param createProvider the bean provider used for creating a new bean
84 * instance (must not be <b>null</b>)
85 * @param initinv the (optional) invocation object for performing
86 * initialization
87 * @throws IllegalArgumentException if the bean provider is undefined
88 */
89 public SingletonBeanProvider(BeanProvider createProvider, Invokable initinv)
90 {
91 super(createProvider, initinv);
92 shutdownHandler = null;
93 }
94
95 /**
96 * Creates a new instance of {@code SingletonBeanProvider} and
97 * initializes it with the bean provider for creating a bean instance.
98 *
99 * @param createProvider the bean provider used for creating a new bean
100 * instance (must not be <b>null</b>)
101 * @throws IllegalArgumentException if the bean provider is undefined
102 */
103 public SingletonBeanProvider(BeanProvider createProvider)
104 {
105 super(createProvider);
106 shutdownHandler = null;
107 }
108
109 /**
110 * Returns the {@code Invokable} object that is called when this provider is
111 * shut down. This can be <b>null</b> if no shutdown handler was set.
112 *
113 * @return the {@code Invokable} to be called on shutdown
114 */
115 public Invokable getShutdownHandler()
116 {
117 return shutdownHandler;
118 }
119
120 /**
121 * Returns the bean managed by this bean provider. This implementation will
122 * create a bean on first access and then always return this instance.
123 *
124 * @param dependencyProvider the dependency provider
125 * @return the bean managed by this provider
126 * @throws net.sf.jguiraffe.di.InjectionException if an error occurs
127 */
128 public Object getBean(DependencyProvider dependencyProvider)
129 {
130 return fetchBean(dependencyProvider);
131 }
132
133 /**
134 * Returns the dependencies of this bean provider. If already a bean has
135 * been created, this implementation returns <b>null</b> because there is
136 * no need any more for resolving dependencies.
137 *
138 * @return the dependencies of this bean provider
139 */
140 @Override
141 public Set<Dependency> getDependencies()
142 {
143 return hasBean() ? null : super.getDependencies();
144 }
145
146 /**
147 * Returns the ID of the locking transaction. As long as no bean has been
148 * created yet, this implementation behaves like the method of the base
149 * class. After that it will always return <b>null</b>, because from now on
150 * there is no need for synchronization any more.
151 *
152 * @return the ID of the locking transaction
153 */
154 @Override
155 public Long getLockID()
156 {
157 return hasBean() ? null : super.getLockID();
158 }
159
160 /**
161 * Tells this provider that it is no more needed. This implementation
162 * invokes the shutdown handler if a bean was already created.
163 *
164 * @param depProvider the {@code DependencyProvider}
165 */
166 @Override
167 public void shutdown(DependencyProvider depProvider)
168 {
169 if (hasBean())
170 {
171 fetchShutdownInvokable()
172 .invoke(depProvider, fetchBean(depProvider));
173 }
174 }
175
176 /**
177 * Fetches the {@code Invokable} for shutdown. This method never returns
178 * <b>null</b>. If a shutdown invokable is set, it is returned. Otherwise a
179 * dummy object is returned.
180 *
181 * @return the {@code Invokable} to be called on shutdown
182 */
183 Invokable fetchShutdownInvokable()
184 {
185 return (getShutdownHandler() != null) ? getShutdownHandler()
186 : HelperInvocations.NULL_INVOCATION;
187 }
188 }