package com.constellio.app.ui.pages.setup;
import static com.constellio.app.ui.i18n.i18n.$;
import static java.util.Arrays.asList;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import com.constellio.app.entities.modules.InstallableModule;
import com.constellio.app.modules.rm.ui.builders.UserToVOBuilder;
import com.constellio.app.services.appManagement.AppManagementServiceException;
import com.constellio.app.services.collections.CollectionsManagerRuntimeException.CollectionsManagerRuntimeException_InvalidCode;
import com.constellio.app.services.factories.ConstellioFactories;
import com.constellio.app.ui.entities.RecordVO.VIEW_MODE;
import com.constellio.app.ui.entities.UserVO;
import com.constellio.app.ui.i18n.i18n;
import com.constellio.app.ui.pages.base.BasePresenter;
import com.constellio.app.ui.pages.base.SessionContext;
import com.constellio.app.ui.pages.setup.ConstellioSetupPresenterException.ConstellioSetupPresenterException_CannotLoadSaveState;
import com.constellio.app.ui.pages.setup.ConstellioSetupPresenterException.ConstellioSetupPresenterException_CodeMustBeAlphanumeric;
import com.constellio.app.ui.pages.setup.ConstellioSetupPresenterException.ConstellioSetupPresenterException_MustSelectAtLeastOneModule;
import com.constellio.app.ui.pages.setup.ConstellioSetupPresenterException.ConstellioSetupPresenterException_TasksCannotBeTheOnlySelectedModule;
import com.constellio.data.conf.DataLayerConfiguration;
import com.constellio.data.dao.services.DataLayerLogger;
import com.constellio.data.dao.services.bigVault.solr.BigVaultServer;
import com.constellio.data.dao.services.transactionLog.TransactionLogReadWriteServices;
import com.constellio.data.dao.services.transactionLog.replay.TransactionLogReplayServices;
import com.constellio.data.extensions.DataLayerSystemExtensions;
import com.constellio.data.io.services.facades.IOServices;
import com.constellio.data.io.services.zip.ZipService;
import com.constellio.data.io.services.zip.ZipServiceException;
import com.constellio.model.entities.modules.Module;
import com.constellio.model.entities.modules.PluginUtil;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.wrappers.Collection;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.security.global.UserCredential;
import com.constellio.model.entities.security.global.UserCredentialStatus;
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.RecordServicesException;
import com.constellio.model.services.users.UserServices;
public class ConstellioSetupPresenter extends BasePresenter<ConstellioSetupView> {
private static final String TEMP_UNZIP_FOLDER = "ConstellioSetupPresenter-TempUnzipFolder";
private static final Logger LOGGER = LogManager.getLogger(ConstellioSetupPresenter.class);
private String setupLocaleCode;
private boolean loadSaveState;
private ConstellioSetupView view;
private UserToVOBuilder userToVOBuilder = new UserToVOBuilder();
public ConstellioSetupPresenter(ConstellioSetupView view) {
super(view);
this.view = view;
ConstellioFactories factories = view.getConstellioFactories();
ConstellioModulesManager modulesManager = factories.getAppLayerFactory().getModulesManager();
List<Module> installedModules = new ArrayList<>();
for (Module module : modulesManager.getBuiltinModules()) {
if (!module.isComplementary()) {
installedModules.add(module);
}
}
List<String> localeCodes = i18n.getSupportedLanguages();
List<String> moduleIds = new ArrayList<>();
for (Module installedModule : installedModules) {
String moduleId = installedModule.getId();
moduleIds.add(moduleId);
}
view.setLocaleCodes(localeCodes);
view.setModuleIds(moduleIds);
}
@Override
protected boolean hasPageAccess(String params, User user) {
return true;
}
public String getLogoTarget() {
SystemConfigurationsManager manager = modelLayerFactory.getSystemConfigurationsManager();
String linkTarget = manager.getValue(ConstellioEIMConfigs.LOGO_LINK);
if (StringUtils.isBlank(linkTarget)) {
linkTarget = "http://www.constellio.com";
}
return linkTarget;
}
boolean isLoadSaveState() {
return loadSaveState;
}
String getSetupLocaleCode() {
return setupLocaleCode;
}
void languageButtonClicked(String localeCode) {
loadSaveState = false;
setupLocaleCode = localeCode;
Locale setupLocale = new Locale(setupLocaleCode);
i18n.setLocale(setupLocale);
view.setLocale(setupLocale);
view.reloadForm();
}
void loadSaveStateButtonClicked() {
loadSaveState = true;
view.reloadForm();
}
public void saveRequested(List<String> languages, List<String> modules, String collectionTitle, String collectionCode,
String adminPassword, boolean demoData)
throws ConstellioSetupPresenterException {
if (!isValidCode(collectionCode)) {
throw new ConstellioSetupPresenterException_CodeMustBeAlphanumeric();
} else if (modules.isEmpty()) {
throw new ConstellioSetupPresenterException_MustSelectAtLeastOneModule();
} else if (modules.size() == 1 && modules.contains("tasks")) {
throw new ConstellioSetupPresenterException_TasksCannotBeTheOnlySelectedModule();
}
view.showMessage($("ConstellioSetupView.setupInProgress"));
ConstellioFactories factories = view.getConstellioFactories();
setSystemLanguage(setupLocaleCode);
Record collectionRecord = factories.getAppLayerFactory().getCollectionsManager().createCollectionInCurrentVersion(
collectionCode, languages);
Collection collection = new Collection(collectionRecord,
modelLayerFactory.getMetadataSchemasManager().getSchemaTypes(collectionCode));
if (StringUtils.isBlank(collectionTitle)) {
collectionTitle = collectionCode;
}
collection.setName(collectionTitle).setTitle(collectionTitle);
try {
recordServices().update(collection);
} catch (RecordServicesException e) {
throw new RuntimeException(e);
}
ConstellioModulesManager modulesManager = factories.getAppLayerFactory().getModulesManager();
List<String> roles = new ArrayList<>();
for (String moduleCode : modules) {
Module module = modulesManager.getInstalledModule(moduleCode);
modulesManager.installValidModuleAndGetInvalidOnes(module,
factories.getModelLayerFactory().getCollectionsListManager());
modulesManager.enableValidModuleAndGetInvalidOnes(collectionCode, module);
roles.addAll(PluginUtil.getRolesForCreator(module));
if (demoData) {
try {
((InstallableModule) module).addDemoData(collectionCode, appLayerFactory);
} catch (Throwable e) {
LOGGER.error("Error when adding demo data of module " + module.getId() + " in collection " + collection, e);
}
}
}
ModelLayerFactory modelLayerFactory = factories.getModelLayerFactory();
UserServices userServices = modelLayerFactory.newUserServices();
UserCredential adminCredential = userServices.createUserCredential("admin", "System", "Admin", "admin@administration.com",
new ArrayList<String>(), asList(collectionCode), UserCredentialStatus.ACTIVE).withSystemAdminPermission();
userServices.addUpdateUserCredential(adminCredential);
userServices.addUserToCollection(adminCredential, collectionCode);
User user = userServices.getUserRecordInCollection("admin", collectionCode);
if (StringUtils.isBlank(adminPassword)) {
adminPassword = "password";
}
modelLayerFactory.getPasswordFileAuthenticationService().changePassword("admin", adminPassword);
try {
modelLayerFactory.newRecordServices().update(user.setUserRoles(roles).setCollectionAllAccess(true));
} catch (RecordServicesException e) {
throw new RuntimeException(e);
}
SessionContext sessionContext = view.getSessionContext();
UserVO userVO = userToVOBuilder.build(user.getWrappedRecord(), VIEW_MODE.DISPLAY, sessionContext);
sessionContext.setCurrentCollection(collectionCode);
sessionContext.setCurrentLocale(new Locale(setupLocaleCode));
sessionContext.setCurrentUser(userVO);
view.updateUI();
}
private boolean isValidCode(String collectionCode) {
try {
appLayerFactory.getCollectionsManager().validateCode(collectionCode);
return true;
} catch (CollectionsManagerRuntimeException_InvalidCode e) {
return false;
}
}
public void setSystemLanguage(String languageCode) {
modelLayerFactory.getConfiguration().setMainDataLanguage(languageCode);
}
public void loadSaveStateRequested(File saveStateFile)
throws ConstellioSetupPresenterException {
try {
File tempFolder = createTempFolder();
try {
ZipService zipService = modelLayerFactory.getIOServicesFactory().newZipService();
DataLayerConfiguration dataLayerConfiguration = modelLayerFactory.getDataLayerFactory()
.getDataLayerConfiguration();
IOServices ioServices = modelLayerFactory.getIOServicesFactory().newIOServices();
File settingsFolder = dataLayerConfiguration.getSettingsFileSystemBaseFolder();
File contentsFolder = dataLayerConfiguration.getContentDaoFileSystemFolder();
BigVaultServer bigVaultServer = modelLayerFactory.getDataLayerFactory().getContentsVaultServer();
DataLayerSystemExtensions dataLayerSystemExtensions = modelLayerFactory
.getDataLayerFactory().getExtensions().getSystemWideExtensions();
ConstellioFactories.clear();
try {
extractSaveState(zipService, saveStateFile, tempFolder);
copyExtractedFiles(tempFolder, ioServices, settingsFolder, contentsFolder);
List<File> tLogFiles = getTLogs(tempFolder);
TransactionLogReadWriteServices readWriteServices = new TransactionLogReadWriteServices(ioServices,
dataLayerConfiguration, dataLayerSystemExtensions);
new TransactionLogReplayServices(readWriteServices, bigVaultServer, new DataLayerLogger())
.replayTransactionLogs(tLogFiles);
} catch (Throwable t) {
revertState(ioServices, settingsFolder, contentsFolder);
ConstellioFactories.start();
throw new ConstellioSetupPresenterException_CannotLoadSaveState();
}
view.updateUI();
} finally {
modelLayerFactory.getIOServicesFactory().newIOServices().deleteQuietly(tempFolder);
}
} catch (Throwable t) {
LOGGER.info("Error when trying to load system from a saved state", t);
throw new ConstellioSetupPresenterException_CannotLoadSaveState();
}
}
private List<File> getTLogs(File tempFolder) {
File tlogsFolder = new File(new File(tempFolder, "content"), "tlogs");
return new ArrayList<>(FileUtils.listFiles(tlogsFolder, new String[] { "tlog" }, false));
}
private void revertState(IOServices ioServices, File settingsFolder, File contentsFolder) {
ioServices.deleteDirectoryWithoutExpectableIOException(settingsFolder);
ioServices.deleteDirectoryWithoutExpectableIOException(contentsFolder);
new File(settingsFolder.getPath()).mkdirs();
new File(contentsFolder.getPath()).mkdirs();
}
private File createTempFolder() {
return modelLayerFactory.getIOServicesFactory().newIOServices().newTemporaryFolder(TEMP_UNZIP_FOLDER);
}
private void copyExtractedFiles(File tempFolder, IOServices ioServices, File settingsFolder, File contentsFolder) {
ioServices.deleteDirectoryWithoutExpectableIOException(settingsFolder);
ioServices.deleteDirectoryWithoutExpectableIOException(contentsFolder);
File settingsFolderInSaveState = new File(tempFolder, "settings");
File contentsFolderInSaveState = new File(tempFolder, "content");
ioServices.moveFolder(settingsFolderInSaveState, settingsFolder);
ioServices.moveFolder(contentsFolderInSaveState, contentsFolder);
}
private void extractSaveState(ZipService zipService, File saveStateFile, File tempFolder)
throws ZipServiceException {
zipService.unzip(saveStateFile, tempFolder);
}
private void loadTransactionLog()
throws AppManagementServiceException {
appLayerFactory.newApplicationService().restart();
}
}