/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.svc; import password.pwm.PwmApplication; import password.pwm.PwmEnvironment; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmException; import password.pwm.error.PwmUnrecoverableException; import password.pwm.health.HealthMonitor; import password.pwm.http.servlet.resource.ResourceServletService; import password.pwm.http.state.SessionStateService; import password.pwm.ldap.LdapConnectionService; import password.pwm.ldap.search.UserSearchEngine; import password.pwm.svc.cache.CacheService; import password.pwm.svc.event.AuditService; import password.pwm.svc.intruder.IntruderManager; import password.pwm.svc.report.ReportService; import password.pwm.svc.sessiontrack.SessionTrackService; import password.pwm.svc.shorturl.UrlShortenerService; import password.pwm.svc.stats.StatisticsManager; import password.pwm.svc.token.TokenService; import password.pwm.svc.wordlist.SeedlistManager; import password.pwm.svc.wordlist.SharedHistoryManager; import password.pwm.svc.wordlist.WordlistManager; import password.pwm.util.VersionChecker; import password.pwm.util.db.DatabaseAccessorImpl; import password.pwm.util.java.TimeDuration; import password.pwm.util.logging.PwmLogger; import password.pwm.util.operations.CrService; import password.pwm.util.operations.OtpService; import password.pwm.util.queue.EmailQueueManager; import password.pwm.util.queue.SmsQueueManager; import password.pwm.util.secure.SecureService; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class PwmServiceManager { private static final PwmLogger LOGGER = PwmLogger.forClass(PwmServiceManager.class); private final PwmApplication pwmApplication; private final Map<Class<? extends PwmService>, PwmService> runningServices = new HashMap<>(); private boolean initialized; public enum PwmServiceClassEnum { SecureService( SecureService.class, true), LdapConnectionService( LdapConnectionService.class, true), DatabaseAccessorImpl( DatabaseAccessorImpl.class, true), SharedHistoryManager( SharedHistoryManager.class, false), AuditService( AuditService.class, false), StatisticsManager( StatisticsManager.class, false), WordlistManager( WordlistManager.class, false), SeedlistManager( SeedlistManager.class, false), EmailQueueManager( EmailQueueManager.class, false), SmsQueueManager( SmsQueueManager.class, false), UrlShortenerService( UrlShortenerService.class, false), TokenService( TokenService.class, false), VersionChecker( VersionChecker.class, false), IntruderManager( IntruderManager.class, false), CrService( CrService.class, true), OtpService( OtpService.class, false), CacheService( CacheService.class, true), HealthMonitor( HealthMonitor.class, false), ReportService( ReportService.class, true), ResourceServletService( ResourceServletService.class, false), SessionTrackService( SessionTrackService.class, false), SessionStateSvc( SessionStateService.class, false), UserSearchEngine( UserSearchEngine.class, true), ; private final Class<? extends PwmService> clazz; private final boolean internalRuntime; PwmServiceClassEnum(final Class<? extends PwmService> clazz, final boolean internalRuntime) { this.clazz = clazz; this.internalRuntime = internalRuntime; } public boolean isInternalRuntime() { return internalRuntime; } static List<Class<? extends PwmService>> allClasses() { final List<Class<? extends PwmService>> pwmServiceClasses = new ArrayList<>(); for (final PwmServiceClassEnum enumClass : values()) { pwmServiceClasses.add(enumClass.getPwmServiceClass()); } return Collections.unmodifiableList(pwmServiceClasses); } public Class<? extends PwmService> getPwmServiceClass() { return clazz; } } public PwmServiceManager(final PwmApplication pwmApplication) { this.pwmApplication = pwmApplication; } public PwmService getService(final Class<? extends PwmService> serviceClass) { return runningServices.get(serviceClass); } public void initAllServices() throws PwmUnrecoverableException { final boolean internalRuntimeInstance = pwmApplication.getPwmEnvironment().isInternalRuntimeInstance() || pwmApplication.getPwmEnvironment().getFlags().contains(PwmEnvironment.ApplicationFlag.CommandLineInstance); for (final PwmServiceClassEnum serviceClassEnum : PwmServiceClassEnum.values()) { boolean startService = true; if (internalRuntimeInstance && !serviceClassEnum.isInternalRuntime()) { startService = false; } if (startService) { final Class<? extends PwmService> serviceClass = serviceClassEnum.getPwmServiceClass(); final PwmService newServiceInstance = initService(serviceClass); runningServices.put(serviceClass, newServiceInstance); } } initialized = true; } private PwmService initService(final Class<? extends PwmService> serviceClass) throws PwmUnrecoverableException { final Instant startTime = Instant.now(); final PwmService newServiceInstance; final String serviceName = serviceClass.getName(); try { final Object newInstance = serviceClass.newInstance(); newServiceInstance = (PwmService) newInstance; } catch (Exception e) { final String errorMsg = "unexpected error instantiating service class '" + serviceName + "', error: " + e.toString(); LOGGER.fatal(errorMsg, e); throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_STARTUP_ERROR, errorMsg)); } try { LOGGER.debug("initializing service " + serviceName); newServiceInstance.init(pwmApplication); final TimeDuration startupDuration = TimeDuration.fromCurrent(startTime); LOGGER.debug("completed initialization of service " + serviceName + " in " + startupDuration.asCompactString() + ", status=" + newServiceInstance.status()); } catch (PwmException e) { LOGGER.warn("error instantiating service class '" + serviceName + "', service will remain unavailable, error: " + e.getMessage()); } catch (Exception e) { String errorMsg = "unexpected error instantiating service class '" + serviceName + "', cannot load, error: " + e.getMessage(); if (e.getCause() != null) { errorMsg += ", cause: " + e.getCause(); } LOGGER.fatal(errorMsg); throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_STARTUP_ERROR, errorMsg)); } return newServiceInstance; } public void shutdownAllServices() { if (!initialized) { return; } final List<Class<? extends PwmService>> reverseServiceList = new ArrayList<>(PwmServiceClassEnum.allClasses()); Collections.reverse(reverseServiceList); for (final Class<? extends PwmService> serviceClass : reverseServiceList) { if (runningServices.containsKey(serviceClass)) { shutDownService(serviceClass); } } initialized = false; } private void shutDownService(final Class<? extends PwmService> serviceClass) { LOGGER.trace("closing service " + serviceClass.getName()); final PwmService loopService = runningServices.get(serviceClass); LOGGER.trace("successfully closed service " + serviceClass.getName()); try { loopService.close(); } catch (Exception e) { LOGGER.error("error closing " + loopService.getClass().getSimpleName() + ": " + e.getMessage(), e); } } public List<PwmService> getRunningServices() { return Collections.unmodifiableList(new ArrayList<>(this.runningServices.values())); } }