KmeliaXmlFormUpdateContext.java
/*
* Copyright (C) 2000 - 2024 Silverpeas
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* As a special exception to the terms and conditions of version 3.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* Open Source Software ("FLOSS") applications as described in Silverpeas's
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* "https://www.silverpeas.org/legal/floss_exception.html"
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.silverpeas.components.kmelia.service;
import org.apache.commons.fileupload.FileItem;
import org.silverpeas.components.kmelia.model.KmaxRuntimeException;
import org.silverpeas.components.kmelia.model.KmeliaRuntimeException;
import org.silverpeas.core.contribution.content.form.DataRecord;
import org.silverpeas.core.contribution.content.form.Field;
import org.silverpeas.core.contribution.content.form.Form;
import org.silverpeas.core.contribution.content.form.FormException;
import org.silverpeas.core.contribution.content.form.RecordSet;
import org.silverpeas.core.contribution.content.form.Util;
import org.silverpeas.core.contribution.content.form.field.FileField;
import org.silverpeas.core.contribution.publication.model.PublicationDetail;
import org.silverpeas.core.contribution.template.publication.PublicationTemplate;
import org.silverpeas.core.contribution.template.publication.PublicationTemplateException;
import org.silverpeas.core.contribution.template.publication.PublicationTemplateManager;
import org.silverpeas.core.util.MemoizedSupplier;
import org.silverpeas.kernel.util.Pair;
import org.silverpeas.kernel.util.StringUtil;
import org.silverpeas.core.util.file.FileUploadUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* Handles the context of an Xml Form update.
* <p>
* It permits to manage some useful caches.
* </p>
* @author silveryocha
*/
public class KmeliaXmlFormUpdateContext {
private final Map<String, PublicationTemplate> templateCache = new HashMap<>();
private final Map<String, Pair<PublicationTemplate, DataRecord>> dataRecordCache =
new HashMap<>();
private final List<FileItem> items;
private final MemoizedSupplier<String> xmlShortName;
private final boolean forceUpdatePublication;
private boolean batchProcessing = false;
public KmeliaXmlFormUpdateContext(final List<FileItem> items,
final boolean forceUpdatePublication) {
this.items = items;
this.forceUpdatePublication = forceUpdatePublication;
this.xmlShortName = new MemoizedSupplier<>(
() -> FileUploadUtil.getParameter(items, "KmeliaPubFormName"));
}
public KmeliaXmlFormUpdateContext batchProcessing() {
this.batchProcessing = true;
return this;
}
public List<FileItem> getItems() {
return items;
}
public boolean isForceUpdatePublication() {
return forceUpdatePublication;
}
public boolean isBatchProcessing() {
return batchProcessing;
}
/**
* Gets from the context the shot name of the Xml Form.
* @return a name as string.
*/
public String getXmlFormShortNameFromItems() {
return xmlShortName.get();
}
/**
* Gets the list of couples of {@link FileItem} and {@link FileField} about the given
* publication and language.
* @param pub a publication.
* @param language a language.
* @return a list of couple of {@link FileItem} and {@link FileField}.
*/
public List<Pair<FileItem, FileField>> getPublicationFileFields(final PublicationDetail pub,
final String language) {
final Pair<PublicationTemplate, DataRecord> pubData = getOrInitializePublicationDataRecordOf(pub, language);
try {
return pubData.getFirst()
.getUpdateForm()
.getFieldTemplates()
.stream()
.flatMap(ft -> IntStream.range(0, ft.getMaximumNumberOfOccurrences()).mapToObj(i -> {
final String fieldName = ft.getFieldName();
final Field field = pubData.getSecond().getField(fieldName, i);
if (FileField.TYPE.equals(field.getTypeName())) {
final String inputName = Util.getFieldOccurrenceName(field.getName(), field.getOccurrence());
final FileItem item = FileUploadUtil.getFile(items, inputName);
if (item != null && !item.isFormField() && StringUtil.isDefined(item.getName())) {
return Pair.of(item, (FileField) field);
} else {
return Pair.of((FileItem) null, (FileField) field);
}
}
return null;
})
.filter(Objects::nonNull))
.collect(Collectors.toList());
} catch (PublicationTemplateException e) {
throw new KmeliaRuntimeException(e);
}
}
/**
* Gets a {@link Pair} of {@link Form} and existing {@link DataRecord} of the given
* publication if any or initializes a new {@link DataRecord} otherwise.
* <p>
* Searched elements are cached in order to improve the treatment processing.
* </p>
* @param pub the aimed publication.
* @param language the current managed language.
* @return a {@link Pair} of {@link Form} and {@link DataRecord}.
* @throws KmeliaRuntimeException in case of publication template service error or in case of
* form management error.
*/
public Pair<PublicationTemplate, DataRecord> getOrInitializePublicationDataRecordOf(
final PublicationDetail pub, final String language) {
return dataRecordCache.computeIfAbsent(pub.getId() + ":" + language, i -> {
final String externalId = pub.getInstanceId() + ":" + getXmlFormShortNameFromItems();
final PublicationTemplate template = getPublicationTemplate(externalId);
try {
final RecordSet set = template.getRecordSet();
final String pubLanguage = pub.getLanguageToDisplay(language);
DataRecord data = set.getRecord(pub.getId(), pubLanguage);
if (data == null || (pubLanguage != null && !pubLanguage.equals(data.getLanguage()))) {
// This publication haven't got any content at all or for requested language
data = set.getEmptyRecord();
data.setId(pub.getId());
data.setLanguage(pubLanguage);
}
return Pair.of(template, data);
} catch (FormException | PublicationTemplateException e) {
throw new KmeliaRuntimeException(e);
}
});
}
/**
* Gets a {@link PublicationTemplate} instance from its external identifier.
* <p>
* The instance is cached against its external identifier.
* </p>
* @param externalId an external identifier as string.
* @return a {@link PublicationTemplate} instance.
*/
private PublicationTemplate getPublicationTemplate(final String externalId) {
return templateCache.computeIfAbsent(externalId, i -> {
try {
return getPublicationTemplateManager().getPublicationTemplate(i);
} catch (PublicationTemplateException e) {
throw new KmaxRuntimeException(e);
}
});
}
/**
* Gets an instance of PublicationTemplateManager.
* @return an instance of PublicationTemplateManager.
*/
private PublicationTemplateManager getPublicationTemplateManager() {
return PublicationTemplateManager.getInstance();
}
}