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 }