1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.spring;
35
36 import java.io.File;
37 import java.io.FilenameFilter;
38 import java.util.ArrayList;
39 import java.util.Date;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 import javax.servlet.ServletContext;
45
46 import org.apache.commons.lang3.StringUtils;
47 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
48 import org.springframework.context.ApplicationContext;
49 import org.springframework.context.support.AbstractApplicationContext;
50 import org.springframework.web.context.support.GenericWebApplicationContext;
51
52 import fr.paris.lutece.portal.service.init.LuteceInitException;
53 import fr.paris.lutece.portal.service.plugin.Plugin;
54 import fr.paris.lutece.portal.service.plugin.PluginEvent;
55 import fr.paris.lutece.portal.service.plugin.PluginEventListener;
56 import fr.paris.lutece.portal.service.plugin.PluginService;
57 import fr.paris.lutece.portal.service.util.AppLogService;
58 import fr.paris.lutece.portal.service.util.AppPathService;
59
60
61
62
63
64
65 public final class SpringContextService implements PluginEventListener
66 {
67 private static final String PROTOCOL_FILE = "file:";
68 private static final String PATH_CONF = "/WEB-INF/conf/";
69 private static final String DIR_PLUGINS = "plugins/";
70 private static final String DIR_OVERRIDE = "override/";
71 private static final String DIR_OVERRIDE_PLUGINS = DIR_OVERRIDE + DIR_PLUGINS;
72 private static final String SUFFIX_CONTEXT_FILE = "_context.xml";
73 private static final String FILE_CORE_CONTEXT = "core_context.xml";
74 private static ApplicationContext _context;
75 private static Map<Class, List> _mapBeansOfType = new HashMap<>( );
76 private static SpringContextServicepringContextService.html#SpringContextService">SpringContextService _instance = new SpringContextService( );
77
78
79 private SpringContextService( )
80 {
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94 public static <T> T getBean( String strName )
95 {
96 return (T) _context.getBean( strName );
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110 @Deprecated
111 public static Object getPluginBean( String strPluginName, String strName )
112 {
113 return _context.getBean( strName );
114 }
115
116
117
118
119
120
121
122
123
124
125 public static boolean isBeanEnabled( String strBeanName )
126 {
127 String strPrefix = getPrefix( strBeanName );
128 return strPrefix == null || isEnabled( strPrefix );
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142 public static void init( ServletContext servletContext ) throws LuteceInitException
143 {
144 try
145 {
146
147 PluginService.registerPluginEventListener( _instance );
148
149
150 Date dateBegin = new Date( );
151
152
153 String strConfPath = AppPathService.getAbsolutePathFromRelativePath( PATH_CONF );
154 String strContextFile = PROTOCOL_FILE + strConfPath + FILE_CORE_CONTEXT;
155
156 GenericWebApplicationContext gwac = new GenericWebApplicationContext( servletContext );
157 gwac.setId( getContextName( servletContext ) );
158
159 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader( gwac );
160 xmlReader.loadBeanDefinitions( strContextFile );
161
162 AppLogService.info( "Context file loaded : {}", FILE_CORE_CONTEXT );
163
164
165
166
167
168
169 String strConfPluginsPath = strConfPath + DIR_PLUGINS;
170 File dirConfPlugins = new File( strConfPluginsPath );
171 FilenameFilter filterContext = new ContextFileFilter( );
172 String [ ] filesContext = dirConfPlugins.list( filterContext );
173
174 loadContexts( filesContext, strConfPluginsPath, xmlReader );
175
176
177 AppLogService.info( "Loading plugins context overrides" );
178
179 String strCoreContextOverrideFile = strConfPath + DIR_OVERRIDE + FILE_CORE_CONTEXT;
180 File fileCoreContextOverride = new File( strCoreContextOverrideFile );
181
182 if ( fileCoreContextOverride.exists( ) )
183 {
184 AppLogService.debug( "Context file loaded : core_context" );
185 xmlReader.loadBeanDefinitions( PROTOCOL_FILE + strCoreContextOverrideFile );
186 }
187 else
188 {
189 AppLogService.debug( "No core_context override found" );
190 }
191
192
193 String strConfPluginsOverridePath = strConfPath + DIR_OVERRIDE_PLUGINS;
194 File dirConfOverridePlugins = new File( strConfPluginsOverridePath );
195
196 if ( dirConfOverridePlugins.exists( ) )
197 {
198 String [ ] filesOverrideContext = dirConfOverridePlugins.list( filterContext );
199 loadContexts( filesOverrideContext, strConfPluginsOverridePath, xmlReader );
200 }
201
202 gwac.refresh( );
203
204 _context = gwac;
205
206 AppLogService.info( "Spring context loaded in {} ms", ( ) -> ( new Date( ).getTime( ) - dateBegin.getTime( ) ) );
207 }
208 catch( Exception e )
209 {
210 AppLogService.error( "Error initializing Spring Context Service {}", e.getMessage( ), e );
211 throw new LuteceInitException( "Error initializing Spring Context Service", e );
212 }
213 }
214
215
216
217
218
219
220
221
222 private static String getContextName( ServletContext servletContext )
223 {
224 String name = "lutece";
225
226 if ( servletContext != null )
227 {
228 String contextName = servletContext.getServletContextName( );
229
230 if ( contextName == null )
231 {
232 contextName = servletContext.getContextPath( );
233 }
234
235 if ( StringUtils.isNotBlank( contextName ) )
236 {
237 name = contextName;
238 }
239 }
240
241 return name;
242 }
243
244
245
246
247
248
249
250
251
252
253
254 private static void loadContexts( String [ ] filesContext, String strConfPluginsPath, XmlBeanDefinitionReader xmlReader )
255 {
256 if ( filesContext != null )
257 {
258 for ( String fileContext : filesContext )
259 {
260 String [ ] file = {
261 PROTOCOL_FILE + strConfPluginsPath + fileContext
262 };
263
264
265 try
266 {
267 xmlReader.loadBeanDefinitions( file );
268 AppLogService.info( "Context file loaded : {}", fileContext );
269 }
270 catch( Exception e )
271 {
272 AppLogService.error( "Unable to load Spring context file : {} - cause : {}", fileContext, e.getMessage( ), e );
273 }
274 }
275 }
276 }
277
278
279
280
281
282
283 public static ApplicationContext getContext( )
284 {
285 return _context;
286 }
287
288
289
290
291
292
293
294
295
296
297 public static <T> List<T> getBeansOfType( Class<T> classDef )
298 {
299
300 List<T> list = _mapBeansOfType.get( classDef );
301
302 if ( list != null )
303 {
304 return new ArrayList<>( list );
305 }
306
307
308 list = new ArrayList<>( );
309
310 Map<String, T> map = _context.getBeansOfType( classDef );
311 String [ ] sBeanNames = map.keySet( ).toArray( new String [ map.size( )] );
312
313 for ( String strBeanName : sBeanNames )
314 {
315 String strPluginPrefix = getPrefix( strBeanName );
316
317 if ( ( strPluginPrefix == null ) || ( isEnabled( strPluginPrefix ) ) )
318 {
319 list.add( map.get( strBeanName ) );
320 }
321 }
322
323 _mapBeansOfType.put( classDef, new ArrayList<>( list ) );
324
325 return list;
326 }
327
328
329
330
331
332
333
334
335 private static String getPrefix( String strBeanName )
336 {
337 int nPos = strBeanName.indexOf( '.' );
338
339 if ( nPos > 0 )
340 {
341 return strBeanName.substring( 0, nPos );
342 }
343
344 return null;
345 }
346
347
348
349
350
351
352
353
354 private static boolean isEnabled( String strPrefix )
355 {
356 Plugin plugin = PluginService.getPlugin( strPrefix );
357
358 return ( plugin != null ) && plugin.isInstalled( );
359 }
360
361
362
363
364 @Override
365 public void processPluginEvent( PluginEvent event )
366 {
367
368 if ( ( event.getEventType( ) == PluginEvent.PLUGIN_INSTALLED || event.getEventType( ) == PluginEvent.PLUGIN_UNINSTALLED )
369 && !_mapBeansOfType.isEmpty( ) )
370 {
371 _mapBeansOfType.clear( );
372 AppLogService.info( "SpringService cache cleared due to a plugin installation change - Plugin : {}", event.getPlugin( ).getName( ) );
373 }
374 }
375
376
377
378
379
380
381 public static void shutdown( )
382 {
383 if ( _context != null )
384 {
385 ( (AbstractApplicationContext) _context ).close( );
386 }
387 }
388
389
390
391
392 static class ContextFileFilter implements FilenameFilter
393 {
394
395
396
397
398
399
400
401
402
403 @Override
404 public boolean accept( File file, String strName )
405 {
406 return strName.endsWith( SUFFIX_CONTEXT_FILE );
407 }
408 }
409 }