package com.constellio.data.dao.services.transactionLog.reader1;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrInputDocument;
import com.constellio.data.conf.DataLayerConfiguration;
import com.constellio.data.dao.dto.records.RecordsFlushing;
import com.constellio.data.dao.services.bigVault.solr.BigVaultServerTransaction;
import com.constellio.data.dao.services.bigVault.solr.SolrUtils;
import com.constellio.data.dao.services.sequence.SolrSequencesManager;
import com.constellio.data.dao.services.solr.ConstellioSolrInputDocument;
import com.constellio.data.dao.services.transactionLog.SecondTransactionLogReplayFilter;
import com.constellio.data.dao.services.transactionLog.SecondTransactionLogRuntimeException.SecondTransactionLogRuntimeException_CannotParseLogCommand;
import com.constellio.data.utils.ImpossibleRuntimeException;
import com.constellio.data.utils.KeyListMap;
import com.constellio.data.utils.LazyIterator;
public class ReaderTransactionsIteratorV1 extends LazyIterator<BigVaultServerTransaction> {
String fileName;
Iterator<List<String>> transactionLinesIterator;
DataLayerConfiguration configuration;
public ReaderTransactionsIteratorV1(String fileName, Iterator<List<String>> transactionLinesIterator,
DataLayerConfiguration configuration) {
this.fileName = fileName;
this.transactionLinesIterator = transactionLinesIterator;
this.configuration = configuration;
}
@Override
protected BigVaultServerTransaction getNextOrNull() {
if (!transactionLinesIterator.hasNext()) {
return null;
}
BigVaultServerTransaction transaction = new BigVaultServerTransaction(RecordsFlushing.NOW());
List<String> currentAddUpdateLines = new ArrayList<>();
for (String line : transactionLinesIterator.next()) {
if (isFirstLineOfOperation(line) && !currentAddUpdateLines.isEmpty()) {
addOperationToTransaction(fileName, transaction, currentAddUpdateLines);
currentAddUpdateLines.clear();
}
currentAddUpdateLines.add(line);
}
if (!currentAddUpdateLines.isEmpty()) {
addOperationToTransaction(fileName, transaction, currentAddUpdateLines);
}
return transaction;
}
private void addOperationToTransaction(String fileName, BigVaultServerTransaction transaction,
List<String> currentAddUpdateLines) {
String firstLine = currentAddUpdateLines.get(0);
if (firstLine.startsWith("addUpdate ")) {
handleAddUpdateLine(fileName, transaction, currentAddUpdateLines, firstLine);
} else if (firstLine.startsWith("delete ")) {
handleDeleteOperation(transaction, firstLine);
} else if (firstLine.startsWith("deletequery ")) {
handleDeleteQueryOperation(transaction, firstLine);
} else if (firstLine.startsWith("sequence next ")) {
handleSequenceNextLine(transaction, firstLine);
} else if (firstLine.startsWith("sequence set ")) {
handleSequenceSetLine(transaction, firstLine);
}
}
protected void handleSequenceSetLine(BigVaultServerTransaction transaction, String firstLine) {
String infos = firstLine.substring("sequence set ".length());
String sequenceId = StringUtils.substringBeforeLast(infos, "=");
long value = Long.valueOf(StringUtils.substringAfterLast(infos, "="));
transaction.getNewDocuments().add(SolrSequencesManager.setSequenceInLogReplay(sequenceId, value));
}
protected void handleSequenceNextLine(BigVaultServerTransaction transaction, String firstLine) {
String sequenceId = firstLine.substring("sequence next ".length());
transaction.getNewDocuments().add(SolrSequencesManager.incrementSequenceInLogReplay(sequenceId));
}
protected void handleDeleteQueryOperation(BigVaultServerTransaction transaction, String firstLine) {
int index = firstLine.indexOf(" ");
String query = firstLine.substring(index);
transaction.getDeletedQueries().add(query);
}
protected void handleDeleteOperation(BigVaultServerTransaction transaction, String firstLine) {
int index = firstLine.indexOf(" ");
List<String> ids = Arrays.asList(firstLine.substring(index).split(" "));
transaction.getDeletedRecords().addAll(ids);
}
protected void handleAddUpdateLine(String fileName, BigVaultServerTransaction transaction, List<String> currentAddUpdateLines,
String firstLine) {
String[] firstLineParts = firstLine.split(" ");
if (firstLineParts.length != 3) {
throw new ImpossibleRuntimeException("Unsupported first line '" + firstLine + "'");
}
String id = firstLineParts[1];
String version = firstLineParts[2];
SolrInputDocument document = buildAddUpdateDocument(fileName, currentAddUpdateLines, id);
addUpdate(transaction, document, version);
}
private SolrInputDocument buildAddUpdateDocument(String fileName, List<String> currentAddUpdateLines, String id) {
KeyListMap<String, Object> fieldValues = new KeyListMap<>();
try {
for (int i = 1; i < currentAddUpdateLines.size(); i++) {
String line = currentAddUpdateLines.get(i);
int indexOfEqualSign = line.indexOf("=");
String field = line.substring(0, indexOfEqualSign);
String value = line.substring(indexOfEqualSign + 1);
Object convertedValue = convertValueForLogReplay(field, value);
fieldValues.add(field, convertedValue);
}
} catch (RuntimeException e) {
throw new SecondTransactionLogRuntimeException_CannotParseLogCommand(currentAddUpdateLines, fileName, e);
}
return buildAddUpdateDocument(id, fieldValues);
}
public void addUpdate(BigVaultServerTransaction transaction, SolrInputDocument document, String version) {
SecondTransactionLogReplayFilter filter = configuration.getSecondTransactionLogReplayFilter();
String id = (String) document.getFieldValue("id");
if (version.equals("-1")) {
String schema = (String) document.getFieldValue("schema_s");
if (filter.isReplayingAdd(id, schema, document)) {
transaction.getNewDocuments().add(document);
}
} else {
if (filter.isReplayingUpdate(id, document)) {
transaction.getUpdatedDocuments().add(document);
}
}
}
private SolrInputDocument buildAddUpdateDocument(String id, KeyListMap<String, Object> fieldValues) {
SolrInputDocument inputDocument = new ConstellioSolrInputDocument();
inputDocument.setField("id", id);
for (Map.Entry<String, List<Object>> entry : fieldValues.getMapEntries()) {
String fieldName = entry.getKey();
String atomicOperation = null;
int indexOfSpace = fieldName.indexOf(" ");
if (indexOfSpace != -1) {
atomicOperation = fieldName.substring(0, indexOfSpace);
fieldName = fieldName.substring(indexOfSpace + 1);
}
List<Object> values = entry.getValue();
Object value = entry.getValue();
if (!SolrUtils.isMultivalue(fieldName)) {
value = entry.getValue().get(0);
}
if (atomicOperation != null) {
Map<String, Object> setValue = new HashMap<>();
setValue.put(atomicOperation, value);
inputDocument.setField(fieldName, setValue);
} else {
inputDocument.setField(fieldName, value);
}
}
return inputDocument;
}
private Object convertValueForLogReplay(String field, String value) {
return value.replace("__LINEBREAK__", "\n");
}
private boolean isFirstLineOfOperation(String line) {
return line.startsWith("addUpdate ") || line.startsWith("delete ") || line.startsWith("deletequery ");
}
}