View Javadoc

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 }