View Javadoc
1   package fr.ifremer.quadrige2.core.service;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 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.quadrige2.core.security.SecurityContext;
27  import fr.ifremer.quadrige2.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  import java.io.IOException;
38  
39  /**
40   * Locates and provides all available application services.
41   */
42  public class ServiceLocator implements Closeable {
43  
44      /* Logger */
45      private static final Log log = LogFactory.getLog(ServiceLocator.class);
46  
47      /**
48       * The default bean reference factory location.
49       */
50      private static final String DEFAULT_BEAN_REFERENCE_LOCATION = "beanRefFactory.xml";
51  
52      /**
53       * The default bean reference factory ID.
54       */
55      private static final String DEFAULT_BEAN_REFERENCE_ID = "beanRefFactory";
56  
57      /**
58       * The shared instance of this ServiceLocator.
59       */
60      private static ServiceLocator instance = new ServiceLocator();
61  
62      /**
63       * Indicates if the spring context is open or not.
64       */
65      private boolean open = false;
66  
67      /**
68       * <p>Constructor for ServiceLocator.</p>
69       */
70      protected ServiceLocator() {
71          // shouldn't be instantiated
72          init(null, null);
73      }
74  
75      /**
76       * <p>Constructor for ServiceLocator.</p>
77       *
78       * @param beanFactoryReferenceLocation a {@link java.lang.String} object.
79       * @param beanRefFactoryReferenceId    a {@link java.lang.String} object.
80       */
81      protected ServiceLocator(String beanFactoryReferenceLocation,
82                               String beanRefFactoryReferenceId) {
83          init(beanFactoryReferenceLocation, beanRefFactoryReferenceId);
84      }
85  
86      /**
87       * replace the default shared instance of this Class
88       *
89       * @param newInstance the new shared service locator instance.
90       */
91      public static void setInstance(ServiceLocator newInstance) {
92          instance = newInstance;
93      }
94  
95      /**
96       * Gets the shared instance of this Class
97       *
98       * @return the shared service locator instance.
99       */
100     public static ServiceLocator instance() {
101         return instance;
102     }
103 
104     /**
105      * The bean factory reference instance.
106      */
107     private BeanFactoryReference beanFactoryReference;
108 
109     /**
110      * The bean factory reference location.
111      */
112     private String beanFactoryReferenceLocation;
113 
114     /**
115      * The bean factory reference id.
116      */
117     private String beanRefFactoryReferenceId;
118 
119     /**
120      * <p>initQuadrige2Default.</p>
121      */
122     public static void initQuadrige2Default() {
123         instance.init(null, null);
124         ServiceLocator.setInstance(instance);
125     }
126 
127     /**
128      * Initializes the Spring application context from the given <code>beanFactoryReferenceLocation</code>. If <code>null</code> is
129      * specified for the <code>beanFactoryReferenceLocation</code> then the
130      * default application context will be used.
131      *
132      * @param beanFactoryReferenceLocation the location of the beanRefFactory reference.
133      * @param beanRefFactoryReferenceId    a {@link java.lang.String} object.
134      */
135     public synchronized void init(String beanFactoryReferenceLocation,
136                                   String beanRefFactoryReferenceId) {
137         // Log if default values are overrided
138         if (log.isDebugEnabled() && beanFactoryReferenceLocation != null && beanRefFactoryReferenceId != null) {
139             log.debug(String.format("Initializing ServiceLocator to use Spring bean factory [%s] at: %s", beanRefFactoryReferenceId,
140                     beanFactoryReferenceLocation));
141         }
142 
143         this.beanFactoryReferenceLocation =
144                 beanFactoryReferenceLocation == null ?
145                         DEFAULT_BEAN_REFERENCE_LOCATION :
146                         beanFactoryReferenceLocation;
147         this.beanRefFactoryReferenceId = beanRefFactoryReferenceId == null ?
148                 DEFAULT_BEAN_REFERENCE_ID :
149                 beanRefFactoryReferenceId;
150         this.beanFactoryReference = null;
151     }
152 
153     /**
154      * Initializes the Spring application context from the given <code>beanFactoryReferenceLocation</code>. If <code>null</code> is
155      * specified for the <code>beanFactoryReferenceLocation</code> then the
156      * default application context will be used.
157      *
158      * @param beanFactoryReferenceLocation the location of the beanRefFactory reference.
159      */
160     public synchronized void init(String beanFactoryReferenceLocation) {
161         this.beanFactoryReferenceLocation = beanFactoryReferenceLocation == null ?
162                 DEFAULT_BEAN_REFERENCE_LOCATION :
163                 beanFactoryReferenceLocation;
164         this.beanFactoryReference = null;
165     }
166 
167     /**
168      * Shuts down the ServiceLocator and releases any used resources.
169      */
170     public synchronized void shutdown() {
171         // Do not try to close if not already opened
172         if (!open) {
173             return;
174         }
175         if (log.isDebugEnabled()) {
176             log.debug("Close Spring application context");
177         }
178 
179         ((AbstractApplicationContext) getContext()).close();
180         if (beanFactoryReference != null) {
181             beanFactoryReference.release();
182             beanFactoryReference = null;
183         }
184         open = false;
185     }
186 
187     /**
188      * Get a service.
189      *
190      * @param name        name of the service (i.e name of the srping bean)
191      * @param serviceType type of service
192      * @param <S>         type of the service
193      * @return the instanciated service
194      */
195     public <S> S getService(String name, Class<S> serviceType) {
196         return getContext().getBean(name, serviceType);
197     }
198 
199     /**
200      * Gets an instance of {@link fr.ifremer.quadrige2.core.service.technical.CacheService}.
201      *
202      * @return a {@link fr.ifremer.quadrige2.core.service.technical.CacheService} object.
203      */
204     public final CacheService getCacheService() {
205         return getService("cacheService", CacheService.class);
206     }
207 
208     /**
209      * <p>isOpen.</p>
210      *
211      * @return {@code true} if spring context is open, {@code false} otherwise.
212      * @since 3.5.2
213      */
214     public boolean isOpen() {
215         return open;
216     }
217 
218     /**
219      * Gets the Spring ApplicationContext.
220      *
221      * @return a {@link org.springframework.context.ApplicationContext} object.
222      */
223     protected synchronized ApplicationContext getContext() {
224         if (beanFactoryReference == null) {
225             if (log.isDebugEnabled() && beanFactoryReferenceLocation != null && beanRefFactoryReferenceId != null) {
226                 log.debug(String.format("Starting Spring application context using bean factory [%s] from file: %s", beanRefFactoryReferenceId,
227                         beanFactoryReferenceLocation));
228             }
229             BeanFactoryLocator beanFactoryLocator =
230                     ContextSingletonBeanFactoryLocator.getInstance(
231                             beanFactoryReferenceLocation);
232             beanFactoryReference = beanFactoryLocator
233                     .useBeanFactory(beanRefFactoryReferenceId);
234 
235             open = true;
236         }
237         return (ApplicationContext) beanFactoryReference.getFactory();
238     }
239 
240     /**
241      * {@inheritDoc}
242      */
243     @Override
244     public void close() throws IOException {
245         shutdown();
246     }
247 
248     /**
249      * <p>getDatabaseSchemaService.</p>
250      *
251      * @return a {@link fr.ifremer.quadrige2.core.service.DatabaseSchemaService} object.
252      */
253     public DatabaseSchemaService getDatabaseSchemaService() {
254         return getService("databaseSchemaService", DatabaseSchemaService.class);
255     }
256 
257     /**
258      * <p>getSecurityContext.</p>
259      *
260      * @return a {@link fr.ifremer.quadrige2.core.security.SecurityContext} object.
261      */
262     public SecurityContext getSecurityContext() {
263         return getService("securityContext", SecurityContext.class);
264     }
265 
266 }