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 }