AppInit.java
/*
* Copyright (c) 2002-2022, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.portal.service.init;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.servlet.ServletContext;
import fr.paris.lutece.portal.service.admin.AdminAuthenticationService;
import fr.paris.lutece.portal.service.admin.AdminUserService;
import fr.paris.lutece.portal.service.content.ContentPostProcessorService;
import fr.paris.lutece.portal.service.content.ContentService;
import fr.paris.lutece.portal.service.daemon.AppDaemonService;
import fr.paris.lutece.portal.service.database.AppConnectionService;
import fr.paris.lutece.portal.service.datastore.CoreDataKeys;
import fr.paris.lutece.portal.service.datastore.DatastoreService;
import fr.paris.lutece.portal.service.fileimage.FileImageService;
import fr.paris.lutece.portal.service.filter.FilterService;
import fr.paris.lutece.portal.service.html.XmlTransformerCacheService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.mailinglist.AdminMailingListService;
import fr.paris.lutece.portal.service.plugin.PluginService;
import fr.paris.lutece.portal.service.portal.PortalService;
import fr.paris.lutece.portal.service.search.IndexationService;
import fr.paris.lutece.portal.service.security.SecurityService;
import fr.paris.lutece.portal.service.servlet.ServletService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.template.AppTemplateService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.util.bean.BeanUtil;
import fr.paris.lutece.util.html.HtmlTemplate;
/**
* This class initializes all the application services
*
* @since 1.1
*/
public final class AppInit
{
private static final String PROPERTY_AUTOINIT = "autoInit";
private static final String PROPERTY_INIT_WEBAPP_PROD_URL = "init.webapp.prod.url";
private static final String PROPERTY_SENDMAIL_SUBJECT = "portal.system.log4j.sendmail.subject";
private static final String PROPERTY_SITE_NAME = "lutece.name";
private static final String MARK_WEBAPP_HOME = "webapp_home";
private static final String MARK_PROD_URL = "lutece_prod_url";
private static final String MARK_SENDMAIL_SUBJECT = "sendmail_subject";
private static final String MARK_AUTOINIT = "autoinit";
private static final String PATH_CONFIG = "/WEB-INF/conf/";
private static final String FILE_PROPERTIES_CONFIG = "config.properties";
private static final String FILE_PROPERTIES_DATABASE = "db.properties";
private static final String PATH_TEMPLATES = "/WEB-INF/templates/";
private static final String CONFIG_PROPERTIES_TEMPLATE = "admin/system/config_properties.html";
private static boolean _bInitSuccessfull;
private static String _strLoadingFailureCause;
private static String _strLoadingFailureDetails;
/**
* Constructor
*/
private AppInit( )
{
}
/**
* Initializes all the application services (used for junit tests)
*
* @param strConfPath
* The relative path to the config files
*/
public static void initServices( String strConfPath )
{
initServices( null, strConfPath, null );
}
/**
* Initializes all the application services
*
* @param context
* The servlet context
* @param strConfPath
* The relative path to the config files
* @param strRealPath
* The real path to the config files
*/
public static void initServices( ServletContext context, String strConfPath, String strRealPath )
{
try
{
long lStart = System.currentTimeMillis( );
Thread.currentThread( ).setName( "Lutece-MainThread" );
// Initializes the properties download files containing the variables used by
// the application
AppPropertiesService.init( strConfPath );
// Initializes the template services from the servlet context information
AppTemplateService.init( PATH_TEMPLATES );
// Initializes the Datastore Service
DatastoreService.init( );
if ( strRealPath != null )
{
// Initializes the properties download files containing the
// variables used by the application
initProperties( strRealPath );
}
AppLogService.info( " {} {} {} ...\n", AppInfo.LUTECE_BANNER_VERSION, "Starting version", AppInfo.getVersion( ) );
// BeanUtil initialization, considering Lutèce availables locales and date
// format properties
BeanUtil.init( );
// Initializes the connection pools
AppConnectionService.init( strConfPath, FILE_PROPERTIES_DATABASE, "portal" );
AppLogService.info( "Creating connexions pool 'portal'." );
//Initializes early initialization services.
StartUpServiceManager.initializeEarlyInitializationServices( );
// Spring ApplicationContext initialization
AppLogService.info( "Loading context files ..." );
SpringContextService.init( context );
// Initialize and run StartUp services
AppLogService.info( "Running extra startup services ..." );
StartUpServiceManager.init( );
// XmlTransformer service cache manager
XmlTransformerCacheService.init( );
AdminMailingListService.init( );
// Initializes Search Engine Indexation Service
IndexationService.init( );
// Initializes PluginService
AppLogService.info( "Initializing plugins ..." );
PluginService.init( );
// Initializes FilterService and ServletService
AppLogService.info( "Initializing plugins filters ..." );
FilterService.init( context );
AppLogService.info( "Initializing plugins servlets ..." );
ServletService.init( context );
// Trace Contents services loading
traceContentServicesLoading( );
// Initializes the SecurityService
SecurityService.init( );
// Initializes plugins autoincludes - needs to be launched before the daemons
// (indexer could fail)
AppTemplateService.initAutoIncludes( );
// Initializes the daemons service
AppDaemonService.init( );
// Initializes the admin authentication module
AdminAuthenticationService.init( );
// Initialize FileImageService
FileImageService.init( );
// Initialize AdminUserService
AdminUserService.init( );
// Process post startup services
AppLogService.info( "Running post startup services ..." );
PostStartUpServiceManager.init( );
// Initialize Content Post Processor Service
ContentPostProcessorService.init( );
_bInitSuccessfull = true;
logStartupTime( );
// Start datastore's cache after all processes that may use Datastore
DatastoreService.startCache( );
long lEnd = System.currentTimeMillis( );
long lTime = 1 + ( lEnd - lStart ) / 1000;
String strBaseUrl = getBaseUrl( context );
StringBuilder sbBanner = new StringBuilder( );
sbBanner.append( AppInfo.LUTECE_BANNER_SERVER ).append( " started successfully in " ).append( lTime ).append( "s !!!\n" )
.append( "\n Front office " ).append( strBaseUrl ).append( AppPathService.getPortalUrl( ) ).append( "\n Back office " )
.append( strBaseUrl ).append( AppPathService.getAdminMenuUrl( ) ).append( "\n" );
AppLogService.info( sbBanner.toString( ) );
}
catch( LuteceInitException e )
{
_strLoadingFailureCause = e.getMessage( );
Throwable cause = e.getCause( );
while ( cause != null )
{
_strLoadingFailureDetails = cause.getMessage( );
cause = cause.getCause( );
}
}
}
/**
* Get a base url to display in start logs
*
* @param context
* the servlet context
* @return the base url
*/
private static String getBaseUrl( ServletContext context )
{
StringBuilder sbBaseUrl = new StringBuilder( "http(s)://server:port" );
if ( context != null )
{
sbBaseUrl.append( context.getContextPath( ) );
}
return sbBaseUrl.append( '/' ).toString( );
}
/**
* Tells if Lutece Startup was successful
*
* @return True, if no error, otherwise false
*/
public static boolean isWebappSuccessfullyLoaded( )
{
return _bInitSuccessfull;
}
/**
* Returns the cause of the startup failure
*
* @return the cause of the startup failure
*/
public static String getLoadingFailureCause( )
{
return _strLoadingFailureCause;
}
/**
* Returns details of the startup failure
*
* @return details of the startup failure
*/
public static String getLoadingFailureDetails( )
{
return _strLoadingFailureDetails;
}
/**
* Traces Content Services loading
*/
private static void traceContentServicesLoading( )
{
for ( ContentService cs : PortalService.getContentServicesList( ) )
{
AppLogService.info( "Content Service '{}' is loaded {} ", cs.getName( ), ( cs.isCacheEnable( ) ? " [ cache enable ] " : " [ cache disable ] " ) );
}
}
/**
* Initializes the config.properties file after first installation
*
* @param strRealPath
* The real path to the configuration file
*/
private static void initProperties( String strRealPath )
{
Map<String, Object> model = new HashMap<>( );
Properties p = new Properties( );
try ( FileInputStream fis = new FileInputStream( strRealPath + PATH_CONFIG + FILE_PROPERTIES_CONFIG ) )
{
p.load( fis );
}
catch( Exception e )
{
AppLogService.error( e.getMessage( ), e );
}
if ( Boolean.parseBoolean( p.getProperty( PROPERTY_AUTOINIT ) ) )
{
Object [ ] params = {
AppPropertiesService.getProperty( PROPERTY_SITE_NAME )
};
String strSendMailSubject = I18nService.getLocalizedString( PROPERTY_SENDMAIL_SUBJECT, params, I18nService.getDefaultLocale( ) );
model.put( MARK_SENDMAIL_SUBJECT, strSendMailSubject );
model.put( MARK_WEBAPP_HOME, AppPathService.getWebAppPath( ) );
model.put( MARK_PROD_URL, p.getProperty( PROPERTY_INIT_WEBAPP_PROD_URL ) );
model.put( MARK_AUTOINIT, Boolean.FALSE.toString( ) );
HtmlTemplate configTemplate = AppTemplateService.getTemplate( CONFIG_PROPERTIES_TEMPLATE, Locale.getDefault( ), model );
// reset configuration cache to avoid configuration caching before macros are
// set. See LUTECE-1460
AppTemplateService.resetConfiguration( );
try ( FileWriter fw = new FileWriter( strRealPath + PATH_CONFIG + FILE_PROPERTIES_CONFIG ) )
{
fw.write( configTemplate.getHtml( ) );
}
catch( Exception io )
{
AppLogService.error( "Error reading file", io );
}
}
}
/**
* Log startup time.
*/
private static void logStartupTime( )
{
String strStartupTime = DateFormat.getDateTimeInstance( ).format( new Date( ) );
DatastoreService.setDataValue( CoreDataKeys.KEY_STARTUP_TIME, strStartupTime );
}
}