package com.constellio.app.ui.pages.search.batchProcessing;
import static com.constellio.app.ui.i18n.i18n.$;
import static com.constellio.model.services.records.RecordUtils.changeSchemaTypeAccordingToTypeLinkedSchema;
import static java.util.Arrays.asList;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
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.compress.utils.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import com.constellio.app.api.extensions.RecordFieldFactoryExtension;
import com.constellio.app.entities.schemasDisplay.enums.MetadataDisplayType;
import com.constellio.app.entities.schemasDisplay.enums.MetadataInputType;
import com.constellio.app.extensions.AppLayerCollectionExtensions;
import com.constellio.app.modules.rm.extensions.app.BatchProcessingRecordFactoryExtension;
import com.constellio.app.modules.rm.reports.builders.BatchProssessing.BatchProcessingResultModel;
import com.constellio.app.modules.rm.reports.builders.BatchProssessing.BatchProcessingResultReportWriter;
import com.constellio.app.modules.rm.wrappers.RMObject;
import com.constellio.app.services.factories.AppLayerFactory;
import com.constellio.app.ui.entities.MetadataSchemaVO;
import com.constellio.app.ui.entities.MetadataVO;
import com.constellio.app.ui.entities.RecordVO;
import com.constellio.app.ui.framework.builders.MetadataSchemaToVOBuilder;
import com.constellio.app.ui.framework.builders.MetadataToVOBuilder;
import com.constellio.app.ui.framework.builders.RecordToVOBuilder;
import com.constellio.app.ui.framework.components.RecordFieldFactory;
import com.constellio.app.ui.i18n.i18n;
import com.constellio.app.ui.pages.base.SessionContext;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessPossibleImpact;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessRecordFieldModification;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessRecordModifications;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessRequest;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessResults;
import com.constellio.app.ui.util.DateFormatUtils;
import com.constellio.data.dao.dto.records.FacetValue;
import com.constellio.data.frameworks.extensions.VaultBehaviorsList;
import com.constellio.data.io.services.facades.IOServices;
import com.constellio.data.utils.ImpossibleRuntimeException;
import com.constellio.data.utils.LangUtils;
import com.constellio.data.utils.Provider;
import com.constellio.model.entities.EnumWithSmallCode;
import com.constellio.model.entities.Language;
import com.constellio.model.entities.Taxonomy;
import com.constellio.model.entities.batchprocess.BatchProcessAction;
import com.constellio.model.entities.enums.BatchProcessingMode;
import com.constellio.model.entities.records.Content;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.Transaction;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.schemas.AllowedReferences;
import com.constellio.model.entities.schemas.Metadata;
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.entities.schemas.MetadataSchemasRuntimeException;
import com.constellio.model.entities.schemas.MetadataValueType;
import com.constellio.model.entities.schemas.ModificationImpact;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.entities.schemas.StructureFactory;
import com.constellio.model.entities.schemas.entries.DataEntryType;
import com.constellio.model.extensions.ModelLayerCollectionExtensions;
import com.constellio.model.services.batch.actions.ChangeValueOfMetadataBatchProcessAction;
import com.constellio.model.services.batch.manager.BatchProcessesManager;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.migrations.ConstellioEIMConfigs;
import com.constellio.model.services.records.RecordProvider;
import com.constellio.model.services.records.RecordServices;
import com.constellio.model.services.records.RecordServicesException;
import com.constellio.model.services.records.SchemasRecordsServices;
import com.constellio.model.services.schemas.ModificationImpactCalculator;
import com.constellio.model.services.schemas.SchemaUtils;
import com.constellio.model.services.search.SearchServices;
import com.constellio.model.services.search.query.logical.LogicalSearchQuery;
public class BatchProcessingPresenterService {
private static final String TMP_BATCH_FILE = "BatchProcessingPresenterService-formatBatchProcessingResults";
private static final Logger LOGGER = getLogger(BatchProcessingPresenterService.class);
private final SchemasRecordsServices schemas;
private final AppLayerFactory appLayerFactory;
private final ModelLayerFactory modelLayerFactory;
private final RecordServices recordServices;
private final SearchServices searchServices;
private final String collection;
private final Locale locale;
private final AppLayerCollectionExtensions extensions;
private final ModelLayerCollectionExtensions modelLayerExtensions;
public BatchProcessingPresenterService(String collection, AppLayerFactory appLayerFactory, Locale locale) {
this.appLayerFactory = appLayerFactory;
this.modelLayerFactory = appLayerFactory.getModelLayerFactory();
this.collection = collection;
this.locale = locale;
this.schemas = new SchemasRecordsServices(collection, modelLayerFactory);
this.recordServices = modelLayerFactory.newRecordServices();
this.searchServices = modelLayerFactory.newSearchServices();
this.extensions = appLayerFactory.getExtensions().forCollection(collection);
this.modelLayerExtensions = modelLayerFactory.getExtensions().forCollection(collection);
}
public String getOriginType(LogicalSearchQuery query) {
if (searchServices.getResultsCount(query) == 0) {
throw new ImpossibleRuntimeException("Batch processing should be done on at least one record");
}
Map<String, List<FacetValue>> typeId_s = searchServices.query(query.setNumberOfRows(0).addFieldFacet("typeId_s"))
.getFieldFacetValues();
Set<String> types = new HashSet<>();
for (FacetValue facetValue : typeId_s.get("typeId_s")) {
if (facetValue.getQuantity() != 0) {
types.add(facetValue.getValue());
}
}
return types.size() == 1 ? types.iterator().next() : null;
}
public String getOriginType(List<String> selectedRecordIds) {
if (selectedRecordIds == null || selectedRecordIds.isEmpty()) {
throw new ImpossibleRuntimeException("Batch processing should be done on at least one record");
}
Set<String> types = new HashSet<>();
for (String recordId : selectedRecordIds) {
Record record = recordServices.getDocumentById(recordId);
Metadata typeMetadata = schemas.getRecordTypeMetadataOf(record);
String type = record.get(typeMetadata);
if (type == null) {
return null;
} else {
types.add(type);
}
}
return types.size() == 1 ? types.iterator().next() : null;
}
private String getRecordSchemaCode(RecordServices recordServices, String recordId) {
return recordServices.getDocumentById(recordId).getSchemaCode();
}
private String getSchemataType(Set<String> recordsSchemata) {
String firstType = getSchemaType(recordsSchemata.iterator().next());
ensureAllSchemataOfSameType(recordsSchemata, firstType);
return firstType;
}
private String getSchemaType(String schemaCode) {
return StringUtils.substringBefore(schemaCode, "_");
}
private void ensureAllSchemataOfSameType(Set<String> recordsSchemata, String firstType) {
for (String schemaCode : recordsSchemata) {
String currentSchemaType = getSchemaType(schemaCode);
if (!currentSchemaType.equals(firstType)) {
throw new ImpossibleRuntimeException("Batch processing should be done on the same schema type :" +
StringUtils.join(recordsSchemata, ";"));
}
}
}
public List<String> getDestinationSchemata(String schemaType) {
List<String> schemataCodes = new ArrayList<>();
List<MetadataSchema> schemata = modelLayerFactory.getMetadataSchemasManager().getSchemaTypes(collection)
.getSchemaType(schemaType).getAllSchemas();
for (MetadataSchema currentSchema : schemata) {
schemataCodes.add(currentSchema.getCode());
}
return schemataCodes;
}
public RecordVO newRecordVO(String schemaCode, final SessionContext sessionContext, final List<String> selectedRecordIds) {
final MetadataSchema schema = modelLayerFactory.getMetadataSchemasManager().getSchemaTypes(collection)
.getSchema(schemaCode);
Record tmpRecord = modelLayerFactory.newRecordServices().newRecordWithSchema(schema);
final Map<String, String> customizedLabels = getCustomizedLabels(schemaCode, locale);
MetadataSchemaToVOBuilder schemaVOBuilder = new MetadataSchemaToVOBuilder() {
@Override
protected MetadataToVOBuilder newMetadataToVOBuilder() {
return new MetadataToVOBuilder() {
@Override
protected MetadataVO newMetadataVO(String metadataCode, String datastoreCode,
MetadataValueType type, String collection, MetadataSchemaVO schemaVO, boolean required,
boolean multivalue, boolean readOnly, Map<Locale, String> labels,
Class<? extends Enum<?>> enumClass, String[] taxonomyCodes, String schemaTypeCode,
MetadataInputType metadataInputType, MetadataDisplayType metadataDisplayType,
AllowedReferences allowedReferences, boolean enabled,
StructureFactory structureFactory, String metadataGroup, Object defaultValue,
String inputMask) {
// Replace labels with customized labels
String customizedLabel = customizedLabels.get(metadataCode);
if (customizedLabel != null) {
for (Locale locale : labels.keySet()) {
labels.put(locale, customizedLabel);
}
}
// Default value is always null
required = false;
defaultValue = null;
User user = schemas.getUser(sessionContext.getCurrentUser().getId());
return isMetadataModifiable(metadataCode, user, selectedRecordIds) ?
super.newMetadataVO(metadataCode, datastoreCode, type, collection, schemaVO, required, multivalue,
readOnly,
labels, enumClass, taxonomyCodes, schemaTypeCode, metadataInputType, metadataDisplayType,
allowedReferences,
enabled,
structureFactory, metadataGroup, defaultValue, inputMask) :
null;
}
};
}
};
MetadataSchemaVO schemaVO = schemaVOBuilder.build(schema, RecordVO.VIEW_MODE.FORM, sessionContext);
return new RecordToVOBuilder() {
@Override
protected Object getValue(Record record, Metadata metadata) {
return null;
}
}.build(tmpRecord, RecordVO.VIEW_MODE.FORM, schemaVO, sessionContext);
}
public BatchProcessResults execute(String selectedType, List<String> records, RecordVO viewObject, User user)
throws RecordServicesException {
BatchProcessAction batchProcessAction = toAction(selectedType, viewObject);
BatchProcessRequest request;
if (records != null && records.size() > 1000) {
request = toRequest(selectedType, records.subList(0, 1000), viewObject, user);
} else {
request = toRequest(selectedType, records, viewObject, user);
}
return execute(request, batchProcessAction, records, user.getUsername(), "userBatchProcess");
}
public BatchProcessResults execute(BatchProcessRequest request, BatchProcessAction action, List<String> records,
String username, String title)
throws RecordServicesException {
// System.out.println("**************** EXECUTE ****************");
// System.out.println("ACTION : ");
// System.out.println(action);
Transaction transaction = prepareTransaction(request, true);
recordServices.validateTransaction(transaction);
BatchProcessesManager batchProcessesManager = modelLayerFactory.newBatchProcessesManager();
batchProcessesManager.addPendingBatchProcess(records, action, username, title, collection);
return null;
}
public BatchProcessResults simulate(String selectedType, List<String> records, RecordVO viewObject, User user)
throws RecordServicesException {
BatchProcessRequest request;
if (records != null && records.size() > 100) {
request = toRequest(selectedType, records.subList(0, 100), viewObject, user);
} else {
request = toRequest(selectedType, records, viewObject, user);
}
return simulateWithIds(request);
}
public BatchProcessResults simulateWithIds(BatchProcessRequest request)
throws RecordServicesException.ValidationException {
System.out.println("**************** SIMULATE ****************");
System.out.println("REQUEST : ");
System.out.println(request);
Transaction transaction = prepareTransaction(request, true);
recordServices.validateTransaction(transaction);
BatchProcessResults results = toBatchProcessResults(transaction);
System.out.println("\nRESULTS : ");
System.out.println(results);
return results;
}
public RecordVO newRecordVO(String schemaCode, final SessionContext sessionContext, final LogicalSearchQuery query) {
final MetadataSchema schema = modelLayerFactory.getMetadataSchemasManager().getSchemaTypes(collection)
.getSchema(schemaCode);
Record tmpRecord = modelLayerFactory.newRecordServices().newRecordWithSchema(schema);
final Map<String, String> customizedLabels = getCustomizedLabels(schemaCode, locale);
MetadataSchemaToVOBuilder schemaVOBuilder = new MetadataSchemaToVOBuilder() {
@Override
protected MetadataToVOBuilder newMetadataToVOBuilder() {
return new MetadataToVOBuilder() {
@Override
protected MetadataVO newMetadataVO(String metadataCode, String datastoreCode,
MetadataValueType type, String collection, MetadataSchemaVO schemaVO, boolean required,
boolean multivalue, boolean readOnly, Map<Locale, String> labels,
Class<? extends Enum<?>> enumClass, String[] taxonomyCodes, String schemaTypeCode,
MetadataInputType metadataInputType, MetadataDisplayType metadataDisplayType,
AllowedReferences allowedReferences, boolean enabled,
StructureFactory structureFactory, String metadataGroup, Object defaultValue,
String inputMask) {
// Replace labels with customized labels
String customizedLabel = customizedLabels.get(metadataCode);
if (customizedLabel != null) {
for (Locale locale : labels.keySet()) {
labels.put(locale, customizedLabel);
}
}
// Default value is always null
required = false;
defaultValue = null;
// User user = schemas.getUser(sessionContext.getCurrentUser().getId());
Map<String, List<FacetValue>> fieldFacetValues = searchServices
.query(query.addFieldFacet("schema_s").setNumberOfRows(0)).getFieldFacetValues();
for (FacetValue facetValue : fieldFacetValues.get("schema_s")) {
long resultCountForFacetValue = facetValue.getQuantity();
String schemaCode = facetValue.getValue();
MetadataSchema schema = schemas.schema(schemaCode);
try {
Metadata metadata = schema.get(metadataCode);
if (resultCountForFacetValue > 0 && metadata.isUnmodifiable()) {
return null;
}
} catch (MetadataSchemasRuntimeException.NoSuchMetadata e) {
continue;
}
}
return super.newMetadataVO(metadataCode, datastoreCode, type, collection, schemaVO, required, multivalue,
readOnly,
labels, enumClass, taxonomyCodes, schemaTypeCode, metadataInputType, metadataDisplayType,
allowedReferences,
enabled,
structureFactory, metadataGroup, defaultValue, inputMask);
}
};
}
};
MetadataSchemaVO schemaVO = schemaVOBuilder.build(schema, RecordVO.VIEW_MODE.FORM, sessionContext);
return new RecordToVOBuilder() {
@Override
protected Object getValue(Record record, Metadata metadata) {
return null;
}
}.build(tmpRecord, RecordVO.VIEW_MODE.FORM, schemaVO, sessionContext);
}
public BatchProcessResults execute(String selectedType, LogicalSearchQuery query, RecordVO viewObject, User user)
throws RecordServicesException {
LogicalSearchQuery validationQuery = query;
validationQuery = validationQuery.setNumberOfRows(1000);
BatchProcessAction batchProcessAction = toAction(selectedType, viewObject);
BatchProcessRequest request = toRequest(selectedType, validationQuery, viewObject, user);
return execute(request, batchProcessAction, query, user.getUsername(), "userBatchProcess");
}
public BatchProcessResults execute(BatchProcessRequest request, BatchProcessAction action, LogicalSearchQuery query,
String username, String title)
throws RecordServicesException {
// System.out.println("**************** EXECUTE ****************");
// System.out.println("ACTION : ");
// System.out.println(action);
List<Transaction> transactionList = prepareTransactions(request, true);
for (Transaction transaction : transactionList) {
recordServices.validateTransaction(transaction);
}
BatchProcessesManager batchProcessesManager = modelLayerFactory.newBatchProcessesManager();
batchProcessesManager.addPendingBatchProcess(query, action, username, title);
return null;
}
public BatchProcessResults simulate(String selectedType, LogicalSearchQuery query, RecordVO viewObject, User user)
throws RecordServicesException {
BatchProcessRequest request = toRequest(selectedType, query, viewObject, user);
return simulateWithQuery(request);
}
public BatchProcessResults simulateWithQuery(BatchProcessRequest request)
throws RecordServicesException.ValidationException {
System.out.println("**************** SIMULATE ****************");
System.out.println("REQUEST : ");
System.out.println(request);
List<Transaction> transactionList = prepareTransactions(request, true);
for (Transaction transaction : transactionList) {
recordServices.validateTransaction(transaction);
}
BatchProcessResults results = null;
if (transactionList.size() == 1) {
results = toBatchProcessResults(transactionList.get(0));
} else {
results = toBatchProcessResults(transactionList);
}
System.out.println("\nRESULTS : ");
System.out.println(results);
return results;
}
public BatchProcessingMode getBatchProcessingMode() {
ConstellioEIMConfigs eimConfigs = new ConstellioEIMConfigs(modelLayerFactory.getSystemConfigurationsManager());
return eimConfigs.getBatchProcessingMode();
}
private BatchProcessResults toBatchProcessResults(List<Transaction> transactionList) {
List<BatchProcessRecordModifications> recordModificationses = new ArrayList<>();
for (Transaction transaction : transactionList) {
for (Record record : transaction.getModifiedRecords()) {
List<BatchProcessRecordFieldModification> recordFieldModifications = new ArrayList<>();
List<BatchProcessPossibleImpact> impacts = new ArrayList<>();
Record originalRecord = record.getCopyOfOriginalRecord();
for (Metadata metadata : record.getModifiedMetadatas(schemas.getTypes())) {
if (!Schemas.isGlobalMetadataExceptTitle(metadata.getLocalCode()) && extensions
.isMetadataDisplayedWhenModifiedInBatchProcessing(metadata)) {
String valueBefore = convertToString(metadata, originalRecord.get(metadata));
String valueAfter = convertToString(metadata, record.get(metadata));
recordFieldModifications.add(new BatchProcessRecordFieldModification(valueBefore, valueAfter, metadata));
}
}
List<Taxonomy> taxonomies = modelLayerFactory.getTaxonomiesManager().getEnabledTaxonomies(collection);
for (ModificationImpact impact : new ModificationImpactCalculator(schemas.getTypes(), taxonomies, searchServices,
recordServices)
.findTransactionImpact(transaction, true)) {
impacts.add(
new BatchProcessPossibleImpact(impact.getPotentialImpactsCount(), impact.getImpactedSchemaType()));
}
recordModificationses.add(new BatchProcessRecordModifications(originalRecord.getId(), originalRecord.getTitle(),
impacts, recordFieldModifications));
}
}
return new BatchProcessResults(recordModificationses);
}
private BatchProcessResults toBatchProcessResults(Transaction transaction) {
MetadataSchemaTypes types = schemas.getTypes();
List<BatchProcessRecordModifications> recordModificationses = new ArrayList<>();
for (Record record : transaction.getModifiedRecords()) {
Record originalRecord = record.getCopyOfOriginalRecord();
List<Metadata> modifiedMetadatas = new ArrayList<>();
modifiedMetadatas.addAll(record.getModifiedMetadatas(types));
recordServices.recalculate(originalRecord);
recordServices.recalculate(record);
// recordServices.loadLazyTransientMetadatas(originalRecord);
// recordServices.reloadEagerTransientMetadatas(originalRecord);
// recordServices.loadLazyTransientMetadatas(record);
// recordServices.reloadEagerTransientMetadatas(record);
for (Metadata metadata : types.getSchema(record.getSchemaCode()).getLazyTransientMetadatas()) {
if (!LangUtils.isEqual(record.get(metadata), originalRecord.get(metadata))) {
if (!Schemas.isGlobalMetadataExceptTitle(metadata.getLocalCode()) && extensions
.isMetadataDisplayedWhenModifiedInBatchProcessing(metadata)) {
modifiedMetadatas.add(metadata);
}
}
}
for (Metadata metadata : types.getSchema(record.getSchemaCode()).getEagerTransientMetadatas()) {
if (!LangUtils.isEqual(record.get(metadata), originalRecord.get(metadata))) {
if (!Schemas.isGlobalMetadataExceptTitle(metadata.getLocalCode()) && extensions
.isMetadataDisplayedWhenModifiedInBatchProcessing(metadata)) {
modifiedMetadatas.add(metadata);
}
}
}
List<BatchProcessRecordFieldModification> recordFieldModifications = new ArrayList<>();
List<BatchProcessPossibleImpact> impacts = new ArrayList<>();
for (Metadata metadata : modifiedMetadatas) {
if (!Schemas.isGlobalMetadataExceptTitle(metadata.getLocalCode()) && extensions
.isMetadataDisplayedWhenModifiedInBatchProcessing(metadata)) {
String valueBefore = convertToString(metadata, originalRecord.get(metadata));
String valueAfter = convertToString(metadata, record.get(metadata));
recordFieldModifications.add(new BatchProcessRecordFieldModification(valueBefore, valueAfter, metadata));
}
}
List<Taxonomy> taxonomies = modelLayerFactory.getTaxonomiesManager().getEnabledTaxonomies(collection);
for (ModificationImpact impact : new ModificationImpactCalculator(schemas.getTypes(), taxonomies, searchServices,
recordServices)
.findTransactionImpact(transaction, true)) {
impacts.add(new BatchProcessPossibleImpact(impact.getPotentialImpactsCount(), impact.getImpactedSchemaType()));
}
recordModificationses.add(new BatchProcessRecordModifications(originalRecord.getId(), originalRecord.getTitle(),
impacts, recordFieldModifications));
}
return new BatchProcessResults(recordModificationses);
}
private String convertToString(Metadata metadata, Object value) {
try {
if (value == null) {
return null;
} else if (metadata.isMultivalue()) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
List<Object> list = (List<Object>) value;
for (Object item : list) {
if (stringBuilder.length() > 1) {
stringBuilder.append(", ");
}
stringBuilder.append(convertScalarToString(metadata, item));
}
stringBuilder.append("]");
return stringBuilder.toString();
} else {
return convertScalarToString(metadata, value);
}
} catch (Exception e) {
LOGGER.warn("Cannot format unsupported value '" + value + "'", e);
return "?";
}
}
private String convertScalarToString(Metadata metadata, Object value) {
if (value == null) {
return null;
}
switch (metadata.getType()) {
case DATE:
return DateFormatUtils.format((LocalDate) value);
case DATE_TIME:
return DateFormatUtils.format((LocalDateTime) value);
case STRING:
case TEXT:
return value.toString();
case INTEGER:
case NUMBER:
return value.toString();
case BOOLEAN:
return $(value.toString(), locale);
case REFERENCE:
Record record = recordServices.getDocumentById(value.toString());
String code = record.get(Schemas.CODE);
if (code == null) {
return record.getId() + " (" + record.getTitle() + ")";
} else {
return code + " (" + record.getTitle() + ")";
}
case CONTENT:
return ((Content) value).getCurrentVersion().getFilename();
case STRUCTURE:
return value.toString();
case ENUM:
return $(metadata.getEnumClass().getSimpleName() + "." + ((EnumWithSmallCode) value).getCode(), locale);
}
throw new ImpossibleRuntimeException("Unsupported type : " + metadata.getType());
}
public List<Transaction> prepareTransactions(final BatchProcessRequest request, boolean recalculate) {
final MetadataSchemaTypes types = schemas.getTypes();
final List<Transaction> transactionList = new ArrayList<>();
Transaction transaction = new Transaction();
int counter = 0;
List<Record> recordList = searchServices.search(request.getQuery());
for (Record record : recordList) {
transaction.add(record);
if (++counter == 1000) {
counter = 0;
transactionList.add(transaction);
transaction = new Transaction();
}
MetadataSchema currentRecordSchema = types.getSchema(record.getSchemaCode());
for (Map.Entry<String, Object> entry : request.getModifiedMetadatas().entrySet()) {
String localMetadataCode = new SchemaUtils().getLocalCodeFromMetadataCode(entry.getKey());
String metadataCode = currentRecordSchema.getCode() + "_" + localMetadataCode;
if (currentRecordSchema.hasMetadataWithCode(metadataCode)) {
Metadata metadata = currentRecordSchema.get(metadataCode);
if (isNonEmptyValue(metadata, entry.getValue()) && types.isRecordTypeMetadata(metadata)) {
record.set(metadata, entry.getValue());
changeSchemaTypeAccordingToTypeLinkedSchema(record, types, new RecordProvider(recordServices), metadata);
}
}
}
currentRecordSchema = types.getSchema(record.getSchemaCode());
for (Map.Entry<String, Object> entry : request.getModifiedMetadatas().entrySet()) {
String localMetadataCode = new SchemaUtils().getLocalCodeFromMetadataCode(entry.getKey());
String metadataCode = currentRecordSchema.getCode() + "_" + localMetadataCode;
if (currentRecordSchema.hasMetadataWithCode(metadataCode)) {
Metadata metadata = currentRecordSchema.get(currentRecordSchema.getCode() + "_" + localMetadataCode);
if (isNonEmptyValue(metadata, entry.getValue())) {
record.set(metadata, entry.getValue());
}
}
}
}
if (counter < 1000) {
transactionList.add(transaction);
}
return transactionList;
}
public Transaction prepareTransaction(BatchProcessRequest request, boolean recalculate) {
Transaction transaction = new Transaction();
MetadataSchemaTypes types = schemas.getTypes();
for (String id : request.getIds()) {
Record record = recordServices.getDocumentById(id);
transaction.add(record);
MetadataSchema currentRecordSchema = types.getSchema(record.getSchemaCode());
for (Map.Entry<String, Object> entry : request.getModifiedMetadatas().entrySet()) {
String localMetadataCode = new SchemaUtils().getLocalCodeFromMetadataCode(entry.getKey());
String metadataCode = currentRecordSchema.getCode() + "_" + localMetadataCode;
if (currentRecordSchema.hasMetadataWithCode(metadataCode)) {
Metadata metadata = currentRecordSchema.get(metadataCode);
if (isNonEmptyValue(metadata, entry.getValue()) && types.isRecordTypeMetadata(metadata)) {
record.set(metadata, entry.getValue());
changeSchemaTypeAccordingToTypeLinkedSchema(record, types, new RecordProvider(recordServices), metadata);
}
}
}
currentRecordSchema = types.getSchema(record.getSchemaCode());
for (Map.Entry<String, Object> entry : request.getModifiedMetadatas().entrySet()) {
String localMetadataCode = new SchemaUtils().getLocalCodeFromMetadataCode(entry.getKey());
String metadataCode = currentRecordSchema.getCode() + "_" + localMetadataCode;
if (currentRecordSchema.hasMetadataWithCode(metadataCode)) {
Metadata metadata = currentRecordSchema.get(currentRecordSchema.getCode() + "_" + localMetadataCode);
if (isNonEmptyValue(metadata, entry.getValue())) {
record.set(metadata, entry.getValue());
}
}
}
}
if (recalculate) {
for (Record record : transaction.getModifiedRecords()) {
recordServices.recalculate(record);
}
}
return transaction;
}
private boolean isNonEmptyValue(Metadata metadata, Object o) {
if (metadata.isMultivalue()) {
return o != null && o instanceof List && !((List) o).isEmpty();
} else {
return o != null && !"".equals(o);
}
}
public String getSchema(String schemaType, String typeId) {
if (StringUtils.isBlank(typeId)) {
return schemaType + "_default";
}
Record record = recordServices.getDocumentById(typeId);
return schemas.getLinkedSchemaOf(record);
}
public boolean isMetadataModifiable(String metadataCode, User user, List<String> selectedRecordIds) {
boolean metadataModifiable = true;
for (String selectedRecordId : selectedRecordIds) {
Metadata metadata = schemas.getTypes().getMetadata(metadataCode);
metadataModifiable &= extensions.isMetadataModifiableInBatchProcessing(metadata, user, selectedRecordId);
}
return metadataModifiable;
}
public String getTypeSchemaType(String schemaType) {
return schemas.getRecordTypeMetadataOf(schemas.getTypes().getSchemaType(schemaType)).getReferencedSchemaType();
}
public Map<String, String> getCustomizedLabels(String schemaCode, Locale locale) {
Provider<String, String> provider = new Provider<String, String>() {
@Override
public String get(String key) {
return $(key);
}
};
MetadataSchema schema = schemas.getTypes().getSchema(schemaCode);
return extensions.getCustomLabels(schema, locale, provider);
}
public RecordFieldFactory newRecordFieldFactory(String schemaType, String selectedType, LogicalSearchQuery query) {
BatchProcessingRecordFactoryExtension.BatchProcessingFieldFactoryExtensionParams params =
new BatchProcessingRecordFactoryExtension.BatchProcessingFieldFactoryExtensionParams(
BatchProcessingRecordFactoryExtension.BATCH_PROCESSING_FIELD_FACTORY_KEY, null, schemaType, query);
params.setSelectedTypeId(selectedType);
RecordFieldFactory recordFieldFactory = null;
VaultBehaviorsList<RecordFieldFactoryExtension> recordFieldFactoryExtensions = appLayerFactory.getExtensions()
.forCollection(collection).recordFieldFactoryExtensions;
for (RecordFieldFactoryExtension extension : recordFieldFactoryExtensions) {
recordFieldFactory = extension.newRecordFieldFactory(params);
if (recordFieldFactory != null) {
break;
}
}
return recordFieldFactory;
}
public RecordFieldFactory newRecordFieldFactory(String schemaType, String selectedType, List<String> selectedRecordIds) {
BatchProcessingRecordFactoryExtension.BatchProcessingFieldFactoryExtensionParams params =
new BatchProcessingRecordFactoryExtension.BatchProcessingFieldFactoryExtensionParams(
BatchProcessingRecordFactoryExtension.BATCH_PROCESSING_FIELD_FACTORY_KEY, null, schemaType,
selectedRecordIds);
//params.setSelectedTypeId(selectedType).setSelectedRecords(selectedRecordIds);
RecordFieldFactory recordFieldFactory = null;
VaultBehaviorsList<RecordFieldFactoryExtension> recordFieldFactoryExtensions = appLayerFactory.getExtensions()
.forCollection(collection).recordFieldFactoryExtensions;
for (RecordFieldFactoryExtension extension : recordFieldFactoryExtensions) {
recordFieldFactory = extension.newRecordFieldFactory(params);
if (recordFieldFactory != null) {
break;
}
}
return recordFieldFactory;
}
public boolean hasWriteAccessOnAllRecords(User user, List<String> selectedRecordIds) {
boolean writeAccess = true;
for (String selectedRecordId : selectedRecordIds) {
Record record = recordServices.getDocumentById(selectedRecordId);
writeAccess &= user.hasWriteAccess().on(record) && modelLayerExtensions.isRecordModifiableBy(record, user);
}
return writeAccess;
}
public AppLayerCollectionExtensions getBatchProcessingExtension() {
return appLayerFactory.getExtensions().forCollection(collection);
}
private static List<String> excludedMetadatas = asList(Schemas.IDENTIFIER.getLocalCode(), Schemas.CREATED_ON.getLocalCode(),
Schemas.MODIFIED_ON.getLocalCode(), RMObject.FORM_CREATED_ON, RMObject.FORM_MODIFIED_ON);
public BatchProcessRequest toRequest(String selectedType, LogicalSearchQuery query, RecordVO formVO, User user) {
String typeCode = new SchemaUtils().getSchemaTypeCode(formVO.getSchema().getCode());
MetadataSchemaType type = schemas.getTypes().getSchemaType(typeCode);
MetadataSchema schema = schemas.getTypes().getSchema(formVO.getSchema().getCode());
Map<String, Object> fieldsModifications = new HashMap<>();
for (MetadataVO metadataVO : formVO.getMetadatas()) {
Metadata metadata = schema.get(metadataVO.getLocalCode());
Object value = formVO.get(metadataVO);
LOGGER.info(metadata.getCode() + ":" + value);
if (metadata.getDataEntry().getType() == DataEntryType.MANUAL
&& value != null
&& (!metadata.isSystemReserved() || Schemas.TITLE_CODE.equals(metadata.getLocalCode()))
&& (!metadata.isMultivalue() || !((List) value).isEmpty())
&& !excludedMetadatas.contains(metadata.getLocalCode())) {
LOGGER.info("");
fieldsModifications.put(metadataVO.getCode(), value);
}
}
if (org.apache.commons.lang3.StringUtils.isNotBlank(selectedType)) {
Metadata typeMetadata = schemas.getRecordTypeMetadataOf(type);
LOGGER.info(typeMetadata.getCode() + ":" + selectedType);
fieldsModifications.put(typeMetadata.getCode(), selectedType);
}
query.setPreferAnalyzedFields(true);
return new BatchProcessRequest(null, query, user, type, fieldsModifications);
}
public BatchProcessRequest toRequest(String selectedType, List<String> selectedRecord, RecordVO formVO, User user) {
String typeCode = new SchemaUtils().getSchemaTypeCode(formVO.getSchema().getCode());
MetadataSchemaType type = schemas.getTypes().getSchemaType(typeCode);
MetadataSchema schema = schemas.getTypes().getSchema(formVO.getSchema().getCode());
Map<String, Object> fieldsModifications = new HashMap<>();
for (MetadataVO metadataVO : formVO.getMetadatas()) {
Metadata metadata = schema.get(metadataVO.getLocalCode());
Object value = formVO.get(metadataVO);
LOGGER.info(metadata.getCode() + ":" + value);
if (metadata.getDataEntry().getType() == DataEntryType.MANUAL
&& value != null
&& (!metadata.isSystemReserved() || Schemas.TITLE_CODE.equals(metadata.getLocalCode()))
&& (!metadata.isMultivalue() || !((List) value).isEmpty())
&& !excludedMetadatas.contains(metadata.getLocalCode())) {
LOGGER.info("");
fieldsModifications.put(metadataVO.getCode(), value);
}
}
if (org.apache.commons.lang3.StringUtils.isNotBlank(selectedType)) {
Metadata typeMetadata = schemas.getRecordTypeMetadataOf(type);
LOGGER.info(typeMetadata.getCode() + ":" + selectedType);
fieldsModifications.put(typeMetadata.getCode(), selectedType);
}
return new BatchProcessRequest(selectedRecord, null, user, type, fieldsModifications);
}
public BatchProcessAction toAction(String selectedType, RecordVO formVO) {
String typeCode = new SchemaUtils().getSchemaTypeCode(formVO.getSchema().getCode());
MetadataSchemaType type = schemas.getTypes().getSchemaType(typeCode);
MetadataSchema schema = schemas.getTypes().getSchema(formVO.getSchema().getCode());
Map<String, Object> fieldsModifications = new HashMap<>();
for (MetadataVO metadataVO : formVO.getMetadatas()) {
Metadata metadata = schema.get(metadataVO.getLocalCode());
Object value = formVO.get(metadataVO);
LOGGER.info(metadata.getCode() + ":" + value);
if (metadata.getDataEntry().getType() == DataEntryType.MANUAL
&& value != null
&& (!metadata.isSystemReserved() || Schemas.TITLE_CODE.equals(metadata.getLocalCode()))
&& (!metadata.isMultivalue() || !((List) value).isEmpty())
&& !excludedMetadatas.contains(metadata.getLocalCode())) {
LOGGER.info("");
fieldsModifications.put(metadataVO.getCode(), value);
}
}
if (org.apache.commons.lang3.StringUtils.isNotBlank(selectedType)) {
Metadata typeMetadata = schemas.getRecordTypeMetadataOf(type);
LOGGER.info(typeMetadata.getCode() + ":" + selectedType);
fieldsModifications.put(typeMetadata.getCode(), selectedType);
}
return new ChangeValueOfMetadataBatchProcessAction(fieldsModifications);
}
public InputStream formatBatchProcessingResults(BatchProcessResults results) {
Language locale = i18n.getLanguage();
File resultsFile = null;
Closeable outputStream = null;
IOServices ioServices = modelLayerFactory.getDataLayerFactory().getIOServicesFactory().newIOServices();
try {
resultsFile = ioServices.newTemporaryFile(TMP_BATCH_FILE);
outputStream = new FileOutputStream(resultsFile);
new BatchProcessingResultReportWriter(new BatchProcessingResultModel(results, locale), i18n.getLocale())
.write((OutputStream) outputStream);
IOUtils.closeQuietly(outputStream);
return new FileInputStream(resultsFile);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
ioServices.deleteQuietly(resultsFile);
IOUtils.closeQuietly(outputStream);
}
}
}