View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.init;
35  
36  import java.io.FileInputStream;
37  import java.io.FileWriter;
38  import java.text.DateFormat;
39  import java.util.Date;
40  import java.util.HashMap;
41  import java.util.Locale;
42  import java.util.Map;
43  import java.util.Properties;
44  
45  import javax.servlet.ServletContext;
46  
47  import fr.paris.lutece.portal.service.admin.AdminAuthenticationService;
48  import fr.paris.lutece.portal.service.admin.AdminUserService;
49  import fr.paris.lutece.portal.service.content.ContentPostProcessorService;
50  import fr.paris.lutece.portal.service.content.ContentService;
51  import fr.paris.lutece.portal.service.daemon.AppDaemonService;
52  import fr.paris.lutece.portal.service.database.AppConnectionService;
53  import fr.paris.lutece.portal.service.datastore.CoreDataKeys;
54  import fr.paris.lutece.portal.service.datastore.DatastoreService;
55  import fr.paris.lutece.portal.service.fileimage.FileImageService;
56  import fr.paris.lutece.portal.service.filter.FilterService;
57  import fr.paris.lutece.portal.service.html.XmlTransformerCacheService;
58  import fr.paris.lutece.portal.service.i18n.I18nService;
59  import fr.paris.lutece.portal.service.mailinglist.AdminMailingListService;
60  import fr.paris.lutece.portal.service.plugin.PluginService;
61  import fr.paris.lutece.portal.service.portal.PortalService;
62  import fr.paris.lutece.portal.service.search.IndexationService;
63  import fr.paris.lutece.portal.service.security.SecurityService;
64  import fr.paris.lutece.portal.service.servlet.ServletService;
65  import fr.paris.lutece.portal.service.spring.SpringContextService;
66  import fr.paris.lutece.portal.service.template.AppTemplateService;
67  import fr.paris.lutece.portal.service.util.AppLogService;
68  import fr.paris.lutece.portal.service.util.AppPathService;
69  import fr.paris.lutece.portal.service.util.AppPropertiesService;
70  import fr.paris.lutece.util.bean.BeanUtil;
71  import fr.paris.lutece.util.html.HtmlTemplate;
72  
73  /**
74   * This class initializes all the application services
75   * 
76   * @since 1.1
77   */
78  public final class AppInit
79  {
80      private static final String PROPERTY_AUTOINIT = "autoInit";
81      private static final String PROPERTY_INIT_WEBAPP_PROD_URL = "init.webapp.prod.url";
82      private static final String PROPERTY_SENDMAIL_SUBJECT = "portal.system.log4j.sendmail.subject";
83      private static final String PROPERTY_SITE_NAME = "lutece.name";
84      private static final String MARK_WEBAPP_HOME = "webapp_home";
85      private static final String MARK_PROD_URL = "lutece_prod_url";
86      private static final String MARK_SENDMAIL_SUBJECT = "sendmail_subject";
87      private static final String MARK_AUTOINIT = "autoinit";
88      private static final String PATH_CONFIG = "/WEB-INF/conf/";
89      private static final String FILE_PROPERTIES_CONFIG = "config.properties";
90      private static final String FILE_PROPERTIES_DATABASE = "db.properties";
91      private static final String PATH_TEMPLATES = "/WEB-INF/templates/";
92      private static final String CONFIG_PROPERTIES_TEMPLATE = "admin/system/config_properties.html";
93      private static boolean _bInitSuccessfull;
94      private static String _strLoadingFailureCause;
95      private static String _strLoadingFailureDetails;
96  
97      /**
98       * Constructor
99       */
100     private AppInit( )
101     {
102     }
103 
104     /**
105      * Initializes all the application services (used for junit tests)
106      * 
107      * @param strConfPath
108      *            The relative path to the config files
109      */
110     public static void initServices( String strConfPath )
111     {
112         initServices( null, strConfPath, null );
113     }
114 
115     /**
116      * Initializes all the application services
117      * 
118      * @param context
119      *            The servlet context
120      * @param strConfPath
121      *            The relative path to the config files
122      * @param strRealPath
123      *            The real path to the config files
124      */
125     public static void initServices( ServletContext context, String strConfPath, String strRealPath )
126     {
127         try
128         {
129             long lStart = System.currentTimeMillis( );
130 
131             Thread.currentThread( ).setName( "Lutece-MainThread" );
132             // Initializes the properties download files containing the variables used by
133             // the application
134             AppPropertiesService.init( strConfPath );
135 
136             // Initializes the template services from the servlet context information
137             AppTemplateService.init( PATH_TEMPLATES );
138 
139             // Initializes the Datastore Service
140             DatastoreService.init( );
141 
142             if ( strRealPath != null )
143             {
144                 // Initializes the properties download files containing the
145                 // variables used by the application
146                 initProperties( strRealPath );
147             }
148 
149             AppLogService.info( " {} {} {} ...\n", AppInfo.LUTECE_BANNER_VERSION, "Starting  version", AppInfo.getVersion( ) );
150 
151             // BeanUtil initialization, considering Lutèce availables locales and date
152             // format properties
153             BeanUtil.init( );
154 
155             // Initializes the connection pools
156             AppConnectionService.init( strConfPath, FILE_PROPERTIES_DATABASE, "portal" );
157             AppLogService.info( "Creating connexions pool 'portal'." );
158            
159             //Initializes early initialization services.
160             StartUpServiceManager.initializeEarlyInitializationServices( );
161             // Spring ApplicationContext initialization
162             AppLogService.info( "Loading context files ..." );
163             SpringContextService.init( context );
164 
165             // Initialize and run StartUp services
166             AppLogService.info( "Running extra startup services ..." );
167             StartUpServiceManager.init( );
168 
169             // XmlTransformer service cache manager
170             XmlTransformerCacheService.init( );
171 
172             AdminMailingListService.init( );
173 
174             // Initializes Search Engine Indexation Service
175             IndexationService.init( );
176 
177             // Initializes PluginService
178             AppLogService.info( "Initializing plugins ..." );
179             PluginService.init( );
180 
181             // Initializes FilterService and ServletService
182             AppLogService.info( "Initializing plugins filters ..." );
183             FilterService.init( context );
184             AppLogService.info( "Initializing plugins servlets ..." );
185             ServletService.init( context );
186 
187             // Trace Contents services loading
188             traceContentServicesLoading( );
189 
190             // Initializes the SecurityService
191             SecurityService.init( );
192 
193             // Initializes plugins autoincludes - needs to be launched before the daemons
194             // (indexer could fail)
195             AppTemplateService.initAutoIncludes( );
196 
197             // Initializes the daemons service
198             AppDaemonService.init( );
199 
200             // Initializes the admin authentication module
201             AdminAuthenticationService.init( );
202 
203             // Initialize FileImageService
204             FileImageService.init( );
205 
206             // Initialize AdminUserService
207             AdminUserService.init( );
208 
209             // Process post startup services
210             AppLogService.info( "Running post startup services ..." );
211             PostStartUpServiceManager.init( );
212 
213             // Initialize Content Post Processor Service
214             ContentPostProcessorService.init( );
215 
216             _bInitSuccessfull = true;
217 
218             logStartupTime( );
219 
220             // Start datastore's cache after all processes that may use Datastore
221             DatastoreService.startCache( );
222 
223             long lEnd = System.currentTimeMillis( );
224             long lTime = 1 + ( lEnd - lStart ) / 1000;
225 
226             String strBaseUrl = getBaseUrl( context );
227             StringBuilder sbBanner = new StringBuilder( );
228             sbBanner.append( AppInfo.LUTECE_BANNER_SERVER ).append( "  started successfully in " ).append( lTime ).append( "s !!!\n" )
229                     .append( "\n   Front office " ).append( strBaseUrl ).append( AppPathService.getPortalUrl( ) ).append( "\n   Back office  " )
230                     .append( strBaseUrl ).append( AppPathService.getAdminMenuUrl( ) ).append( "\n" );
231             AppLogService.info( sbBanner.toString( ) );
232         }
233         catch( LuteceInitException e )
234         {
235             _strLoadingFailureCause = e.getMessage( );
236 
237             Throwable cause = e.getCause( );
238 
239             while ( cause != null )
240             {
241                 _strLoadingFailureDetails = cause.getMessage( );
242                 cause = cause.getCause( );
243             }
244         }
245     }
246 
247     /**
248      * Get a base url to display in start logs
249      * 
250      * @param context
251      *            the servlet context
252      * @return the base url
253      */
254     private static String getBaseUrl( ServletContext context )
255     {
256         StringBuilder sbBaseUrl = new StringBuilder( "http(s)://server:port" );
257         if ( context != null )
258         {
259             sbBaseUrl.append( context.getContextPath( ) );
260         }
261         return sbBaseUrl.append( '/' ).toString( );
262     }
263 
264     /**
265      * Tells if Lutece Startup was successful
266      * 
267      * @return True, if no error, otherwise false
268      */
269     public static boolean isWebappSuccessfullyLoaded( )
270     {
271         return _bInitSuccessfull;
272     }
273 
274     /**
275      * Returns the cause of the startup failure
276      * 
277      * @return the cause of the startup failure
278      */
279     public static String getLoadingFailureCause( )
280     {
281         return _strLoadingFailureCause;
282     }
283 
284     /**
285      * Returns details of the startup failure
286      * 
287      * @return details of the startup failure
288      */
289     public static String getLoadingFailureDetails( )
290     {
291         return _strLoadingFailureDetails;
292     }
293 
294     /**
295      * Traces Content Services loading
296      */
297     private static void traceContentServicesLoading( )
298     {
299         for ( ContentService cs : PortalService.getContentServicesList( ) )
300         {
301             AppLogService.info( "Content Service '{}' is loaded {} ", cs.getName( ), ( cs.isCacheEnable( ) ? " [ cache enable ] " : " [ cache disable ] " ) );
302         }
303     }
304 
305     /**
306      * Initializes the config.properties file after first installation
307      *
308      * @param strRealPath
309      *            The real path to the configuration file
310      */
311     private static void initProperties( String strRealPath )
312     {
313         Map<String, Object> model = new HashMap<>( );
314         Properties p = new Properties( );
315 
316         try ( FileInputStream fis = new FileInputStream( strRealPath + PATH_CONFIG + FILE_PROPERTIES_CONFIG ) )
317         {
318             p.load( fis );
319         }
320         catch( Exception e )
321         {
322             AppLogService.error( e.getMessage( ), e );
323         }
324 
325         if ( Boolean.parseBoolean( p.getProperty( PROPERTY_AUTOINIT ) ) )
326         {
327             Object [ ] params = {
328                     AppPropertiesService.getProperty( PROPERTY_SITE_NAME )
329             };
330             String strSendMailSubject = I18nService.getLocalizedString( PROPERTY_SENDMAIL_SUBJECT, params, I18nService.getDefaultLocale( ) );
331             model.put( MARK_SENDMAIL_SUBJECT, strSendMailSubject );
332             model.put( MARK_WEBAPP_HOME, AppPathService.getWebAppPath( ) );
333             model.put( MARK_PROD_URL, p.getProperty( PROPERTY_INIT_WEBAPP_PROD_URL ) );
334             model.put( MARK_AUTOINIT, Boolean.FALSE.toString( ) );
335 
336             HtmlTemplate configTemplate = AppTemplateService.getTemplate( CONFIG_PROPERTIES_TEMPLATE, Locale.getDefault( ), model );
337             // reset configuration cache to avoid configuration caching before macros are
338             // set. See LUTECE-1460
339             AppTemplateService.resetConfiguration( );
340 
341             try ( FileWriter fw = new FileWriter( strRealPath + PATH_CONFIG + FILE_PROPERTIES_CONFIG ) )
342             {
343                 fw.write( configTemplate.getHtml( ) );
344             }
345             catch( Exception io )
346             {
347                 AppLogService.error( "Error reading file", io );
348             }
349         }
350     }
351 
352     /**
353      * Log startup time.
354      */
355     private static void logStartupTime( )
356     {
357         String strStartupTime = DateFormat.getDateTimeInstance( ).format( new Date( ) );
358         DatastoreService.setDataValue( CoreDataKeys.KEY_STARTUP_TIME, strStartupTime );
359     }
360 }