View Javadoc
1   package fr.ifremer.quadrige3.core.service;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.quadrige3.core.security.SecurityContext;
27  import fr.ifremer.quadrige3.core.service.technical.CacheService;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.springframework.beans.factory.access.BeanFactoryLocator;
31  import org.springframework.beans.factory.access.BeanFactoryReference;
32  import org.springframework.context.ApplicationContext;
33  import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
34  import org.springframework.context.support.AbstractApplicationContext;
35  
36  import java.io.Closeable;
37  
38  /**
39   * Locates and provides all available application services.
40   */
41  public class ServiceLocator implements Closeable {
42  
43      /* Logger */
44      private static final Log log = LogFactory.getLog(ServiceLocator.class);
45  
46      /**
47       * The default bean reference factory location.
48       */
49      private static final String DEFAULT_BEAN_REFERENCE_LOCATION = "beanRefFactory.xml";
50  
51      /**
52       * The default bean reference factory ID.
53       */
54      private static final String DEFAULT_BEAN_REFERENCE_ID = "beanRefFactory";
55  
56      /**
57       * The shared instance of this ServiceLocator.
58       */
59      private static ServiceLocator instance = new ServiceLocator();
60  
61      /**
62       * Indicates if the spring context is open or not.
63       */
64      private boolean open = false;
65  
66      /**
67       * <p>Constructor for ServiceLocator.</p>
68       */
69      protected ServiceLocator() {
70          // shouldn't be instantiated
71          init(null, null);
72      }
73  
74      /**
75       * <p>Constructor for ServiceLocator.</p>
76       *
77       * @param beanFactoryReferenceLocation a {@link java.lang.String} object.
78       * @param beanRefFactoryReferenceId    a {@link java.lang.String} object.
79       */
80      protected ServiceLocator(String beanFactoryReferenceLocation,
81                               String beanRefFactoryReferenceId) {
82          init(beanFactoryReferenceLocation, beanRefFactoryReferenceId);
83      }
84  
85      /**
86       * replace the default shared instance of this Class
87       *
88       * @param newInstance the new shared service locator instance.
89       */
90      public static void setInstance(ServiceLocator newInstance) {
91          instance = newInstance;
92      }
93  
94      /**
95       * Gets the shared instance of this Class
96       *
97       * @return the shared service locator instance.
98       */
99      public static ServiceLocator instance() {
100         return instance;
101     }
102 
103     /**
104      * The bean factory reference instance.
105      */
106     private BeanFactoryReference beanFactoryReference;
107 
108     /**
109      * The bean factory reference location.
110      */
111     private String beanFactoryReferenceLocation;
112 
113     /**
114      * The bean factory reference id.
115      */
116     private String beanRefFactoryReferenceId;
117 
118     /**
119      * <p>initQuadrigeDefault.</p>
120      */
121     public static void initQuadrigeDefault() {
122         instance.init(null, null);
123         ServiceLocator.setInstance(instance);
124     }
125 
126     /**
127      * Initializes the Spring application context from the given <code>beanFactoryReferenceLocation</code>. If <code>null</code> is
128      * specified for the <code>beanFactoryReferenceLocation</code> then the
129      * default application context will be used.
130      *
131      * @param beanFactoryReferenceLocation the location of the beanRefFactory reference.
132      * @param beanRefFactoryReferenceId    a {@link java.lang.String} object.
133      */
134     public synchronized void init(String beanFactoryReferenceLocation,
135                                   String beanRefFactoryReferenceId) {
136         // Log if default values are overridden
137         if (log.isDebugEnabled() && beanFactoryReferenceLocation != null && beanRefFactoryReferenceId != null) {
138             log.debug(String.format("Initializing ServiceLocator to use Spring bean factory [%s] at: %s", beanRefFactoryReferenceId,
139                     beanFactoryReferenceLocation));
140         }
141 
142         this.beanFactoryReferenceLocation =
143                 beanFactoryReferenceLocation == null ?
144                         DEFAULT_BEAN_REFERENCE_LOCATION :
145                         beanFactoryReferenceLocation;
146         this.beanRefFactoryReferenceId = beanRefFactoryReferenceId == null ?
147                 DEFAULT_BEAN_REFERENCE_ID :
148                 beanRefFactoryReferenceId;
149         this.beanFactoryReference = null;
150     }
151 
152     /**
153      * Initializes the Spring application context from the given <code>beanFactoryReferenceLocation</code>. If <code>null</code> is
154      * specified for the <code>beanFactoryReferenceLocation</code> then the
155      * default application context will be used.
156      *
157      * @param beanFactoryReferenceLocation the location of the beanRefFactory reference.
158      */
159     public synchronized void init(String beanFactoryReferenceLocation) {
160         this.beanFactoryReferenceLocation = beanFactoryReferenceLocation == null ?
161                 DEFAULT_BEAN_REFERENCE_LOCATION :
162                 beanFactoryReferenceLocation;
163         this.beanFactoryReference = null;
164     }
165 
166     /**
167      * Shuts down the ServiceLocator and releases any used resources.
168      */
169     public synchronized void shutdown() {
170         // Do not try to close if not already opened
171         if (!open) {
172             return;
173         }
174         if (log.isDebugEnabled()) {
175             log.debug("Close Spring application context");
176         }
177 
178         ((AbstractApplicationContext) getContext()).close();
179         if (beanFactoryReference != null) {
180             beanFactoryReference.release();
181             beanFactoryReference = null;
182         }
183         open = false;
184     }
185 
186     /**
187      * Get a service.
188      *
189      * @param name        name of the service (i.e name of the spring bean)
190      * @param serviceType type of service
191      * @param <S>         type of the service
192      * @return the instantiated service
193      */
194     public <S> S getService(String name, Class<S> serviceType) {
195         return getContext().getBean(name, serviceType);
196     }
197 
198     /**
199      * Gets an instance of {@link fr.ifremer.quadrige3.core.service.technical.CacheService}.
200      *
201      * @return a {@link fr.ifremer.quadrige3.core.service.technical.CacheService} object.
202      */
203     public final CacheService getCacheService() {
204         return getService("cacheService", CacheService.class);
205     }
206 
207     /**
208      * <p>isOpen.</p>
209      *
210      * @return {@code true} if spring context is open, {@code false} otherwise.
211      * @since 3.5.2
212      */
213     public boolean isOpen() {
214         return open;
215     }
216 
217     /**
218      * Gets the Spring ApplicationContext.
219      *
220      * @return a {@link org.springframework.context.ApplicationContext} object.
221      */
222     protected synchronized ApplicationContext getContext() {
223         if (beanFactoryReference == null) {
224             if (log.isDebugEnabled() && beanFactoryReferenceLocation != null && beanRefFactoryReferenceId != null) {
225                 log.debug(String.format("Starting Spring application context using bean factory [%s] from file: %s", beanRefFactoryReferenceId,
226                         beanFactoryReferenceLocation));
227             }
228             BeanFactoryLocator beanFactoryLocator =
229                     ContextSingletonBeanFactoryLocator.getInstance(
230                             beanFactoryReferenceLocation);
231             beanFactoryReference = beanFactoryLocator
232                     .useBeanFactory(beanRefFactoryReferenceId);
233 
234             open = true;
235         }
236         return (ApplicationContext) beanFactoryReference.getFactory();
237     }
238 
239     /**
240      * {@inheritDoc}
241      */
242     @Override
243     public void close() {
244         shutdown();
245     }
246 
247     /**
248      * <p>getDatabaseSchemaService.</p>
249      *
250      * @return a {@link fr.ifremer.quadrige3.core.service.DatabaseSchemaService} object.
251      */
252     public DatabaseSchemaService getDatabaseSchemaService() {
253         return getService("databaseSchemaService", DatabaseSchemaService.class);
254     }
255 
256     /**
257      * <p>getSecurityContext.</p>
258      *
259      * @return a {@link fr.ifremer.quadrige3.core.security.SecurityContext} object.
260      */
261     public SecurityContext getSecurityContext() {
262         return getService("securityContext", SecurityContext.class);
263     }
264 
265 }