package com.constellio.app.services.factories;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.constellio.app.api.cmis.binding.global.CmisCacheManager;
import com.constellio.app.conf.AppLayerConfiguration;
import com.constellio.app.extensions.AppLayerExtensions;
import com.constellio.app.extensions.impl.DefaultPagesComponentsExtension;
import com.constellio.app.modules.complementary.ESRMRobotsModule;
import com.constellio.app.modules.es.ConstellioESModule;
import com.constellio.app.modules.rm.ConstellioRMModule;
import com.constellio.app.modules.rm.model.labelTemplate.LabelTemplateManager;
import com.constellio.app.modules.robots.ConstellioRobotsModule;
import com.constellio.app.modules.tasks.TaskModule;
import com.constellio.app.services.appManagement.AppManagementService;
import com.constellio.app.services.appManagement.AppManagementServiceException;
import com.constellio.app.services.collections.CollectionsManager;
import com.constellio.app.services.extensions.ConstellioModulesManagerImpl;
import com.constellio.app.services.extensions.plugins.ConstellioPluginConfigurationManager;
import com.constellio.app.services.extensions.plugins.ConstellioPluginManager;
import com.constellio.app.services.extensions.plugins.JSPFConstellioPluginManager;
import com.constellio.app.services.metadata.AppSchemasServices;
import com.constellio.app.services.migrations.ConstellioEIM;
import com.constellio.app.services.migrations.MigrationServices;
import com.constellio.app.services.records.SystemCheckManager;
import com.constellio.app.services.recovery.UpgradeAppRecoveryService;
import com.constellio.app.services.recovery.UpgradeAppRecoveryServiceImpl;
import com.constellio.app.services.schemasDisplay.SchemasDisplayManager;
import com.constellio.app.services.systemSetup.SystemGlobalConfigsManager;
import com.constellio.app.ui.application.NavigatorConfigurationService;
import com.constellio.app.ui.framework.containers.ContainerButtonListener;
import com.constellio.app.ui.i18n.i18n;
import com.constellio.app.ui.pages.base.EnterViewListener;
import com.constellio.app.ui.pages.base.InitUIListener;
import com.constellio.app.ui.pages.base.PresenterService;
import com.constellio.data.dao.managers.StatefulService;
import com.constellio.data.dao.managers.StatefullServiceDecorator;
import com.constellio.data.dao.managers.config.ConfigManagerException.OptimisticLockingConfiguration;
import com.constellio.data.dao.services.factories.DataLayerFactory;
import com.constellio.data.dao.services.factories.LayerFactory;
import com.constellio.data.io.IOServicesFactory;
import com.constellio.data.io.services.facades.IOServices;
import com.constellio.data.utils.Delayed;
import com.constellio.data.utils.ImpossibleRuntimeException;
import com.constellio.data.utils.dev.Toggle;
import com.constellio.model.conf.FoldersLocator;
import com.constellio.model.services.configs.SystemConfigurationsManager;
import com.constellio.model.services.extensions.ConstellioModulesManager;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.migrations.ConstellioEIMConfigs;
import com.constellio.model.services.records.reindexing.ReindexationMode;
public class AppLayerFactory extends LayerFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(AppLayerFactory.class);
private FoldersLocator foldersLocator;
private ConstellioPluginManager pluginManager;
private ConstellioModulesManagerImpl modulesManager;
private ModelLayerFactory modelLayerFactory;
private DataLayerFactory dataLayerFactory;
private CmisCacheManager cmisRepositoriesManager;
private List<EnterViewListener> enterViewListeners;
private List<InitUIListener> initUIListeners;
private SystemGlobalConfigsManager systemGlobalConfigsManager;
private List<ContainerButtonListener> containerButtonListeners;
private SchemasDisplayManager metadataSchemasDisplayManager;
private final AppLayerExtensions appLayerExtensions;
private final CollectionsManager collectionsManager;
private final LabelTemplateManager labelTemplateManager;
private final AppLayerConfiguration appLayerConfiguration;
private final Map<String, StatefulService> moduleManagers = new HashMap<>();
final private NavigatorConfigurationService navigatorConfigService;
private final SystemCheckManager systemCheckManager;
public AppLayerFactory(AppLayerConfiguration appLayerConfiguration, ModelLayerFactory modelLayerFactory,
DataLayerFactory dataLayerFactory, StatefullServiceDecorator statefullServiceDecorator, String instanceName) {
super(modelLayerFactory, statefullServiceDecorator, instanceName);
this.appLayerExtensions = new AppLayerExtensions();
this.modelLayerFactory = modelLayerFactory;
this.dataLayerFactory = dataLayerFactory;
this.enterViewListeners = new ArrayList<>();
this.initUIListeners = new ArrayList<>();
this.containerButtonListeners = new ArrayList<>();
this.foldersLocator = new FoldersLocator();
this.appLayerConfiguration = appLayerConfiguration;
this.setDefaultLocale();
this.metadataSchemasDisplayManager = add(new SchemasDisplayManager(dataLayerFactory.getConfigManager(),
modelLayerFactory.getCollectionsListManager(), modelLayerFactory.getMetadataSchemasManager()));
IOServices ioServices = modelLayerFactory.getIOServicesFactory().newIOServices();
pluginManager = add(new JSPFConstellioPluginManager(appLayerConfiguration.getPluginsFolder(),
appLayerConfiguration.getPluginsManagementOnStartupFile(), ioServices,
new ConstellioPluginConfigurationManager(dataLayerFactory.getConfigManager())));
pluginManager.registerModule(new ConstellioRMModule());
pluginManager.registerModule(new ConstellioESModule());
pluginManager.registerModule(new TaskModule());
pluginManager.registerModule(new ConstellioRobotsModule());
pluginManager.registerModule(new ESRMRobotsModule());
Delayed<MigrationServices> migrationServicesDelayed = new Delayed<>();
this.modulesManager = add(new ConstellioModulesManagerImpl(this, pluginManager, migrationServicesDelayed));
this.systemGlobalConfigsManager = add(
new SystemGlobalConfigsManager(modelLayerFactory.getDataLayerFactory().getConfigManager()));
this.collectionsManager = add(
new CollectionsManager(modelLayerFactory, modulesManager, migrationServicesDelayed, systemGlobalConfigsManager));
migrationServicesDelayed.set(newMigrationServices());
try {
newMigrationServices().migrate(null, false);
} catch (OptimisticLockingConfiguration optimisticLockingConfiguration) {
throw new RuntimeException(optimisticLockingConfiguration);
}
labelTemplateManager = new LabelTemplateManager(dataLayerFactory.getConfigManager(), this);
this.navigatorConfigService = new NavigatorConfigurationService();
this.systemCheckManager = add(new SystemCheckManager(this));
}
private void setDefaultLocale() {
Locale locale;
String mainDataLanguage = modelLayerFactory.getConfiguration().getMainDataLanguage();
if ("en".equals(mainDataLanguage)) {
locale = Locale.ENGLISH;
} else if ("fr".equals(mainDataLanguage)) {
locale = Locale.FRENCH;
} else {
throw new ImpossibleRuntimeException("Invalid language " + mainDataLanguage);
}
i18n.setLocale(locale);
}
public void registerSystemWideManager(String module, String id, StatefulService manager) {
String key = module + "-" + id;
add(manager);
moduleManagers.put(key, manager);
}
public void registerManager(String collection, String module, String id, StatefulService manager) {
String key = collection + "-" + module + "-" + id;
add(manager);
moduleManagers.put(key, manager);
}
public <T> T getRegisteredManager(String collection, String module, String id) {
String key = collection + "-" + module + "-" + id;
return (T) moduleManagers.get(key);
}
public <T> T getSystemWideRegisteredManager(String module, String id) {
String key = module + "-" + id;
return (T) moduleManagers.get(key);
}
public AppLayerExtensions getExtensions() {
return appLayerExtensions;
}
public AppManagementService newApplicationService() {
IOServicesFactory ioServicesFactory = dataLayerFactory.getIOServicesFactory();
return new AppManagementService(this, foldersLocator);
}
public UpgradeAppRecoveryService newUpgradeAppRecoveryService() {
return new UpgradeAppRecoveryServiceImpl(this,
dataLayerFactory.getIOServicesFactory().newIOServices());
}
public SystemCheckManager getSystemCheckManager() {
return systemCheckManager;
}
@Override
public void initialize() {
UpgradeAppRecoveryServiceImpl upgradeAppRecoveryService = new UpgradeAppRecoveryServiceImpl(this,
dataLayerFactory.getIOServicesFactory().newIOServices());
upgradeAppRecoveryService.deletePreviousWarCausingFailure();
SystemConfigurationsManager configManager = modelLayerFactory
.getSystemConfigurationsManager();
configManager.initialize();
ConstellioEIMConfigs constellioConfigs = new ConstellioEIMConfigs(configManager);
boolean recoveryModeActive = constellioConfigs.isInUpdateProcess();
if (Toggle.FORCE_ROLLBACK.isEnabled() || recoveryModeActive) {
startupWithPossibleRecovery(upgradeAppRecoveryService);
} else {
normalStartup();
}
if (dataLayerFactory.getDataLayerConfiguration().isBackgroundThreadsEnabled()) {
dataLayerFactory.getBackgroundThreadsManager().onSystemStarted();
}
upgradeAppRecoveryService.close();
}
private void startupWithPossibleRecovery(UpgradeAppRecoveryServiceImpl recoveryService) {
if (dataLayerFactory.getSecondTransactionLogManager() != null) {
recoveryService.startRollbackMode();
try {
normalStartup();
recoveryService.stopRollbackMode();
} catch (Throwable exception) {
if (recoveryService.isInRollbackMode()) {
LOGGER.error("Error when trying to start application", exception);
recoveryService.rollback(exception);
//this.appLayerFactory.getModelLayerFactory().getDataLayerFactory().close(false);
try {
newApplicationService().restart();
} catch (AppManagementServiceException e) {
throw new RuntimeException(e);
}
} else {
LOGGER.info("No more in rollback mode...");
throw exception;
}
}
} else {
//rare case in tests
normalStartup();
}
}
private void normalStartup() {
appLayerExtensions.getSystemWideExtensions().pagesComponentsExtensions.add(new DefaultPagesComponentsExtension(this));
this.pluginManager.detectPlugins();
Set<String> invalidPlugins = new HashSet<>();
super.initialize();
String warVersion = newApplicationService().getWarVersion();
if (warVersion != null && !"5.0.0".equals(warVersion)) {
LOGGER.info("----------- STARTING APPLICATION IN VERSION " + warVersion + " -----------");
}
try {
collectionsManager.initializeModulesResources();
invalidPlugins.addAll(newMigrationServices().migrate(null, false));
} catch (OptimisticLockingConfiguration optimisticLockingConfiguration) {
throw new RuntimeException(optimisticLockingConfiguration);
}
LOGGER.info("initializeCollectionsAndGetInvalidModules");
invalidPlugins.addAll(collectionsManager.initializeCollectionsAndGetInvalidModules());
getModulesManager().enableComplementaryModules();
if (!invalidPlugins.isEmpty()) {
LOGGER.warn("System is restarting because of invalid modules \n\t" + StringUtils.join(invalidPlugins, "\n\t"));
try {
restart();
} catch (AppManagementServiceException e) {
throw new RuntimeException(e);
}
}
}
public void postInitialization() {
pluginManager.configure();
if (systemGlobalConfigsManager.isMarkedForReindexing()) {
try {
modelLayerFactory.newReindexingServices().reindexCollections(ReindexationMode.RECALCULATE_AND_REWRITE);
systemGlobalConfigsManager.setMarkedForReindexing(false);
systemGlobalConfigsManager.setReindexingRequired(false);
systemGlobalConfigsManager.setLastReindexingFailed(false);
} catch (Exception e) {
LOGGER.error("Reindexing failed", e);
systemGlobalConfigsManager.setMarkedForReindexing(false);
systemGlobalConfigsManager.setReindexingRequired(true);
systemGlobalConfigsManager.setLastReindexingFailed(true);
}
}
systemGlobalConfigsManager.setRestartRequired(false);
}
void restart()
throws AppManagementServiceException {
newApplicationService().restart();
}
@Override
public void close() {
super.close();
}
public ConstellioPluginManager getPluginManager() {
return pluginManager;
}
public ModelLayerFactory getModelLayerFactory() {
return modelLayerFactory;
}
public NavigatorConfigurationService getNavigatorConfigurationService() {
return navigatorConfigService;
}
public PresenterService newPresenterService() {
return new PresenterService(modelLayerFactory);
}
public CmisCacheManager getConstellioCmisRepositoriesManager() {
if (cmisRepositoriesManager == null) {
cmisRepositoriesManager = add(new CmisCacheManager(this));
cmisRepositoriesManager.initialize();
}
return cmisRepositoriesManager;
}
public List<EnterViewListener> getEnterViewListeners() {
return enterViewListeners;
}
public List<InitUIListener> getInitUIListeners() {
return initUIListeners;
}
public List<ContainerButtonListener> getContainerButtonListeners() {
return containerButtonListeners;
}
public SchemasDisplayManager getMetadataSchemasDisplayManager() {
return metadataSchemasDisplayManager;
}
public SystemGlobalConfigsManager getSystemGlobalConfigsManager() {
return this.systemGlobalConfigsManager;
}
public CollectionsManager getCollectionsManager() {
return collectionsManager;
}
public MigrationServices newMigrationServices() {
return new MigrationServices(new ConstellioEIM(), this, modulesManager, pluginManager);
}
public ConstellioModulesManager getModulesManager() {
return modulesManager;
}
public LabelTemplateManager getLabelTemplateManager() {
return labelTemplateManager;
}
public AppLayerConfiguration getAppLayerConfiguration() {
return appLayerConfiguration;
}
public AppSchemasServices newSchemasServices() {
return new AppSchemasServices(this);
}
}