package com.constellio.app.services.importExport.systemStateExport; import static com.constellio.data.dao.dto.records.RecordsFlushing.NOW; import static com.constellio.model.services.search.query.logical.LogicalSearchQuery.query; import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.from; import static java.util.Arrays.asList; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.constellio.app.conf.AppLayerConfiguration; import com.constellio.app.modules.rm.wrappers.ContainerRecord; import com.constellio.app.modules.rm.wrappers.Document; import com.constellio.app.modules.rm.wrappers.Folder; import com.constellio.app.modules.tasks.model.wrappers.Task; import com.constellio.app.services.factories.AppLayerFactory; import com.constellio.data.conf.DataLayerConfiguration; import com.constellio.data.dao.dto.records.RecordDTO; import com.constellio.data.dao.dto.records.TransactionDTO; import com.constellio.data.dao.services.bigVault.BigVaultRecordDao; import com.constellio.data.dao.services.bigVault.solr.BigVaultServerTransaction; import com.constellio.data.dao.services.factories.DataLayerFactory; import com.constellio.data.dao.services.transactionLog.SecondTransactionLogManager; import com.constellio.data.dao.services.transactionLog.writer1.TransactionWriterV1; 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.records.Record; import com.constellio.model.entities.records.wrappers.UserDocument; import com.constellio.model.entities.records.wrappers.UserFolder; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataSchemaType; import com.constellio.model.entities.schemas.MetadataSchemaTypes; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.records.FieldsPopulator; import com.constellio.model.services.records.RecordImpl; import com.constellio.model.services.records.RecordServices; import com.constellio.model.services.schemas.MetadataSchemasManager; import com.constellio.model.services.schemas.SchemaUtils; import com.constellio.model.services.search.SearchServices; public class PartialSystemStateExporter { private static final Logger LOGGER = LoggerFactory.getLogger(PartialSystemStateExporter.class); public static final String TEMP_FOLDER_RESOURCE_NAME = "SystemStateExporter-tempFolder"; RecordServices recordServices; DataLayerConfiguration dataLayerConfiguration; final AppLayerConfiguration appLayerConfiguration; ZipService zipService; IOServices ioServices; MetadataSchemasManager schemasManager; ModelLayerFactory modelLayerFactory; SecondTransactionLogManager secondTransactionLogManager; SearchServices searchServices; BigVaultRecordDao recordDao; public PartialSystemStateExporter(AppLayerFactory appLayerFactory) { this.appLayerConfiguration = appLayerFactory.getAppLayerConfiguration(); this.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(); this.searchServices = modelLayerFactory.newSearchServices(); recordDao = (BigVaultRecordDao) dataLayerFactory.newRecordDao(); } private void exportSystemToFolder(File folder, PartialSystemStateExportParams params) { secondTransactionLogManager.regroupAndMoveInVault(); File tempFolderContentFolder = new File(folder, "content"); final File tlogsFolder = new File(tempFolderContentFolder, "tlogs"); tlogsFolder.mkdirs(); generateSaveState(tlogsFolder, params); File tempFolderSettingsFolder = new File(folder, "settings"); File tempPluginsFolder = new File(folder, "plugins"); copySettingsTo(tempFolderSettingsFolder); copyPluginsJarFolderTo(tempPluginsFolder, params.isExportPluginJars()); } private void generateSaveState(File tlogsFolder, PartialSystemStateExportParams params) { List<String> filteredSchemaTypes = asList(Folder.SCHEMA_TYPE, Document.SCHEMA_TYPE, Task.SCHEMA_TYPE, ContainerRecord.SCHEMA_TYPE, UserDocument.SCHEMA_TYPE, UserFolder.SCHEMA_TYPE); List<FieldsPopulator> populators = new ArrayList<>(); SavestateFileWriter writer = null; try { writer = new SavestateFileWriter(new File(tlogsFolder, "records.tlog"), filteredSchemaTypes, populators); for (String collection : modelLayerFactory.getCollectionsListManager().getCollections()) { MetadataSchemaTypes types = schemasManager.getSchemaTypes(collection); for (String typeCode : types.getSchemaTypesSortedByDependency()) { MetadataSchemaType type = types.getSchemaType(typeCode); if (!filteredSchemaTypes.contains(typeCode)) { Iterator<List<Record>> it = searchServices.recordsBatchIterator(1000, query(from(type).returnAll())); while (it.hasNext()) { writer.write(it.next()); } } } } Set<String> ids = new HashSet<>(); if (params.getIds() != null) { List<Record> records = new ArrayList<>(); for (String id : params.getIds()) { String currentId = id; while (currentId != null) { Record record = recordServices.getDocumentById(currentId); String schemaType = new SchemaUtils().getSchemaTypeCode(record.getSchemaCode()); if (!ids.contains(currentId) && filteredSchemaTypes.contains(schemaType)) { records.add(record); ids.add(currentId); currentId = record.getParentId(); } else { currentId = null; } } } writer.write(records); } } finally { if (writer != null) { writer.close(); } } } private class SavestateFileWriter { TransactionWriterV1 transactionWriter = new TransactionWriterV1(false, new DataLayerSystemExtensions()); BufferedWriter writer; List<String> filteredSchemaTypes; List<FieldsPopulator> populators = new ArrayList<>(); public SavestateFileWriter(File file, List<String> filteredSchemaTypes, List<FieldsPopulator> populators) { this.writer = writer; this.filteredSchemaTypes = filteredSchemaTypes; this.populators = populators; try { writer = new BufferedWriter(new FileWriter(file)); } catch (IOException e) { throw new RuntimeException(e); } } public void write(List<Record> records) { List<RecordDTO> recordDTOs = new ArrayList<>(); for (Record record : records) { MetadataSchema schema = schemasManager.getSchemaTypes(record.getCollection()).getSchema(record.getSchemaCode()); recordDTOs.add(((RecordImpl) record).toDocumentDTO(schema, populators)); } BigVaultServerTransaction bigVaultServerTransaction = recordDao.prepare(new TransactionDTO(NOW()) .withFullRewrite(true).withNewRecords(recordDTOs)); try { writer.append(transactionWriter.toLogEntry(bigVaultServerTransaction)); } catch (IOException e) { throw new RuntimeException(e); } } public void close() { IOUtils.closeQuietly(writer); } } public void exportSystemToFile(File file, PartialSystemStateExportParams 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 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); } } } }