package com.constellio.app.services.importExport.systemStateExport; import static java.util.Arrays.asList; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.constellio.app.conf.AppLayerConfiguration; import com.constellio.app.services.factories.AppLayerFactory; import com.constellio.app.services.importExport.systemStateExport.SystemStateExporterRuntimeException.SystemStateExporterRuntimeException_InvalidRecordId; import com.constellio.app.services.importExport.systemStateExport.SystemStateExporterRuntimeException.SystemStateExporterRuntimeException_RecordHasNoContent; import com.constellio.data.conf.DataLayerConfiguration; import com.constellio.data.dao.services.factories.DataLayerFactory; import com.constellio.data.dao.services.transactionLog.SecondTransactionLogManager; 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.records.Content; import com.constellio.model.entities.records.Record; import com.constellio.model.entities.schemas.Metadata; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataValueType; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.records.RecordServices; import com.constellio.model.services.records.RecordServicesRuntimeException.NoSuchRecordWithId; import com.constellio.model.services.schemas.MetadataSchemasManager; public class SystemStateExporter { private static final Logger LOGGER = LoggerFactory.getLogger(SystemStateExporter.class); public static final String TEMP_FOLDER_RESOURCE_NAME = "SystemStateExporter-tempFolder"; RecordServices recordServices; DataLayerConfiguration dataLayerConfiguration; final AppLayerConfiguration appLayerConfiguration; ZipService zipService; IOServices ioServices; MetadataSchemasManager schemasManager; SecondTransactionLogManager secondTransactionLogManager; public SystemStateExporter(AppLayerFactory appLayerFactory) { this.appLayerConfiguration = appLayerFactory.getAppLayerConfiguration(); ModelLayerFactory modelLayerFactory = appLayerFactory.getModelLayerFactory(); DataLayerFactory dataLayerFactory = modelLayerFactory.getDataLayerFactory(); this.dataLayerConfiguration = dataLayerFactory.getDataLayerConfiguration(); this.zipService = dataLayerFactory.getIOServicesFactory().newZipService(); this.ioServices = dataLayerFactory.getIOServicesFactory().newIOServices(); this.secondTransactionLogManager = dataLayerFactory.getSecondTransactionLogManager(); this.schemasManager = modelLayerFactory.getMetadataSchemasManager(); this.recordServices = modelLayerFactory.newRecordServices(); } public void exportSystemToFolder(File folder, SystemStateExportParams params) { secondTransactionLogManager.regroupAndMoveInVault(); File tempFolderContentFolder = new File(folder, "content"); File tempFolderSettingsFolder = new File(folder, "settings"); File tempPluginsFolder = new File(folder, "plugins"); copySettingsTo(tempFolderSettingsFolder); if (params.isExportAllContent()) { copyContentsTo(tempFolderContentFolder); } else { Set<String> exportedHashes = findExportedHashes(params); copyContentsTo(tempFolderContentFolder, exportedHashes); } copyPluginsJarFolderTo(tempPluginsFolder, params.isExportPluginJars()); } public void exportSystemToFile(File file, SystemStateExportParams params) { secondTransactionLogManager.regroupAndMoveInVault(); File tempFolder = ioServices.newTemporaryFolder(TEMP_FOLDER_RESOURCE_NAME); try { exportSystemToFolder(tempFolder, params); File tempFolderContentFolder = new File(tempFolder, "content"); File tempFolderSettingsFolder = new File(tempFolder, "settings"); List<File> list; if (params.isExportPluginJars()) { File tempPluginsFolder = new File(tempFolder, "plugins"); if (tempPluginsFolder.exists()) { list = asList(tempFolderContentFolder, tempFolderSettingsFolder, tempPluginsFolder); } else { list = asList(tempFolderContentFolder, tempFolderSettingsFolder); } } else { list = asList(tempFolderContentFolder, tempFolderSettingsFolder); } try { zipService.zip(file, list); } catch (ZipServiceException e) { throw new RuntimeException(e); } } finally { ioServices.deleteQuietly(tempFolder); } } private Set<String> findExportedHashes(SystemStateExportParams params) { Set<String> exportedHashes = new HashSet<>(); for (String recordId : params.getOnlyExportContentOfRecords()) { try { Record record = recordServices.getDocumentById(recordId); Set<String> recordHashes = getRecordHashes(record); exportedHashes.addAll(recordHashes); if (recordHashes.isEmpty()) { throw new SystemStateExporterRuntimeException_RecordHasNoContent(recordId); } } catch (NoSuchRecordWithId e) { throw new SystemStateExporterRuntimeException_InvalidRecordId(recordId); } } return exportedHashes; } private Set<String> getRecordHashes(Record record) { Set<String> exportedHashes = new HashSet<>(); MetadataSchema schema = schemasManager.getSchemaTypes(record.getCollection()).getSchema(record.getSchemaCode()); for (Metadata contentMetadata : schema.getMetadatas().onlyWithType(MetadataValueType.CONTENT)) { if (contentMetadata.isMultivalue()) { List<Content> contents = record.getList(contentMetadata); for (Content content : contents) { exportedHashes.addAll(content.getHashOfAllVersions()); } } else { Content content = record.get(contentMetadata); if (content != null) { exportedHashes.addAll(content.getHashOfAllVersions()); } } } return exportedHashes; } private void copyContentsTo(File tempFolderContentsFolder, final Set<String> exportedHashes) { final File contentsFolder = dataLayerConfiguration.getContentDaoFileSystemFolder(); final File tlogsFolder = new File(contentsFolder, "tlogs"); final File tlogsBckFolder = new File(contentsFolder, "tlogs_bck"); try { FileUtils.copyDirectory(contentsFolder, tempFolderContentsFolder, new FileFilter() { @Override public boolean accept(File pathname) { if (pathname.equals(contentsFolder) || pathname.getAbsolutePath().contains(tlogsFolder.getAbsolutePath())) { return !pathname.getAbsolutePath().contains(tlogsBckFolder.getAbsolutePath()); } String name; if (pathname.getName().contains("_") && pathname.getName().split("_").length > 0) { name = pathname.getName().split("_")[0]; } else { name = pathname.getName(); } for (String hash : exportedHashes) { if (hash.contains(name)) { return true; } } return false; } }); } catch (IOException e) { throw new RuntimeException(e); } } private void copyContentsTo(File tempFolderContentsFolder) { File contentsFolder = dataLayerConfiguration.getContentDaoFileSystemFolder(); try { FileUtils.copyDirectory(contentsFolder, tempFolderContentsFolder); } catch (IOException e) { throw new RuntimeException(e); } File tlogBackup = new File(tempFolderContentsFolder, "tlogs_bck"); if (tlogBackup.exists()) { try { FileUtils.deleteDirectory(tlogBackup); } catch (IOException e) { throw new RuntimeException(e); } } } private void copySettingsTo(File tempFolderSettingsFolder) { File settingsFolder = dataLayerConfiguration.getSettingsFileSystemBaseFolder(); try { FileUtils.copyDirectory(settingsFolder, tempFolderSettingsFolder); } catch (IOException e) { throw new RuntimeException(e); } } private void copyPluginsJarFolderTo(File tempPluginsFolder, boolean exportJars) { File pluginsFolder = appLayerConfiguration.getPluginsFolder(); if (exportJars && pluginsFolder.exists()) { try { FileUtils.copyDirectory(pluginsFolder, tempPluginsFolder); } catch (IOException e) { throw new RuntimeException(e); } } } }