Tony CHEMIT pushed to branch feature/issue-2846 at ultreiaio / ird-observe
Commits:
-
ef91c221
by Tony Chemit at 2024-09-30T17:22:19+02:00
-
5df804a7
by Tony Chemit at 2024-09-30T17:22:19+02:00
-
9f28eb6d
by Tony Chemit at 2024-09-30T17:22:19+02:00
-
d36001f2
by Tony Chemit at 2024-09-30T17:22:19+02:00
-
6584c596
by Tony Chemit at 2024-09-30T17:22:19+02:00
9 changed files:
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ContentReferentialUIHandler.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ContentReferentialUIModelStates.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ReferentialSavePredicate.java
- client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/usage/UsageForDesactivateUIHandler.java
- core/persistence/java/src/main/java/fr/ird/observe/entities/referential/common/OceanSpi.java
- core/services/local/src/main/java/fr/ird/observe/services/local/service/referential/ReferentialServiceLocalSupport.java
- core/services/local/src/test/java/fr/ird/observe/services/local/service/referential/UnidirectionalResultIssue2208Test.java
- core/services/test/src/main/java/fr/ird/observe/services/service/referential/ReferentialServiceFixtures.java
- toolkit/persistence/src/main/java/fr/ird/observe/spi/context/ReferentialDtoEntityContext.java
Changes:
| ... | ... | @@ -44,11 +44,11 @@ import fr.ird.observe.client.datasource.editor.api.content.referential.actions.S |
| 44 | 44 | import fr.ird.observe.client.datasource.editor.api.content.referential.actions.ShowUsagesReferential;
|
| 45 | 45 | import fr.ird.observe.client.util.UIHelper;
|
| 46 | 46 | import fr.ird.observe.datasource.security.ConcurrentModificationException;
|
| 47 | -import fr.ird.observe.dto.ToolkitIdLabel;
|
|
| 48 | 47 | import fr.ird.observe.dto.reference.ReferentialDtoReference;
|
| 49 | 48 | import fr.ird.observe.dto.referential.ReferentialDto;
|
| 50 | 49 | import fr.ird.observe.dto.referential.ReferentialDtoReferenceWithNoCodeAware;
|
| 51 | 50 | import fr.ird.observe.services.service.SaveResultDto;
|
| 51 | +import fr.ird.observe.services.service.referential.ExtraSaveRequest;
|
|
| 52 | 52 | import io.ultreia.java4all.i18n.I18n;
|
| 53 | 53 | import io.ultreia.java4all.jaxx.widgets.list.ListHeader;
|
| 54 | 54 | import org.apache.logging.log4j.LogManager;
|
| ... | ... | @@ -284,14 +284,8 @@ public class ContentReferentialUIHandler<D extends ReferentialDto, R extends Ref |
| 284 | 284 | }
|
| 285 | 285 | |
| 286 | 286 | protected SaveResultDto doSave(D bean) throws ConcurrentModificationException {
|
| 287 | - ToolkitIdLabel replaceReference = getModel().getStates().getReplaceReference();
|
|
| 288 | - if (replaceReference != null) {
|
|
| 289 | - String id = bean.getId();
|
|
| 290 | - String replaceId = replaceReference.getId();
|
|
| 291 | - log.info(String.format("Do replace reference before save (%s → %s)", id, replaceId));
|
|
| 292 | - getReferentialService().replaceReference(getModel().getSource().getScope().getMainType(), id, replaceId);
|
|
| 293 | - }
|
|
| 294 | - SaveResultDto result = getReferentialService().save(bean);
|
|
| 287 | + ExtraSaveRequest request = getModel().getStates().toExtraSaveRequest();
|
|
| 288 | + SaveResultDto result = getReferentialService().save(bean, request);
|
|
| 295 | 289 | bean.copy(getModel().getStates().getForm().getObject());
|
| 296 | 290 | return result;
|
| 297 | 291 | }
|
| ... | ... | @@ -30,6 +30,7 @@ import fr.ird.observe.client.datasource.editor.api.content.ContentUIModel; |
| 30 | 30 | import fr.ird.observe.client.datasource.editor.api.content.ContentUIModelStates;
|
| 31 | 31 | import fr.ird.observe.client.datasource.editor.api.content.actions.save.SavePredicate;
|
| 32 | 32 | import fr.ird.observe.client.util.init.DefaultUIInitializerResult;
|
| 33 | +import fr.ird.observe.dto.ToolkitIdBean;
|
|
| 33 | 34 | import fr.ird.observe.dto.ToolkitIdDtoBean;
|
| 34 | 35 | import fr.ird.observe.dto.ToolkitIdLabel;
|
| 35 | 36 | import fr.ird.observe.dto.form.Form;
|
| ... | ... | @@ -38,11 +39,20 @@ import fr.ird.observe.dto.referential.ReferentialDto; |
| 38 | 39 | import fr.ird.observe.dto.referential.ReferentialLocale;
|
| 39 | 40 | import fr.ird.observe.navigation.id.Project;
|
| 40 | 41 | import fr.ird.observe.services.ObserveServicesProvider;
|
| 42 | +import fr.ird.observe.services.service.referential.ExtraSaveRequest;
|
|
| 43 | +import org.apache.logging.log4j.LogManager;
|
|
| 44 | +import org.apache.logging.log4j.Logger;
|
|
| 41 | 45 | |
| 42 | 46 | import javax.swing.ListModel;
|
| 47 | +import java.util.Collection;
|
|
| 48 | +import java.util.LinkedHashMap;
|
|
| 43 | 49 | import java.util.LinkedList;
|
| 44 | 50 | import java.util.List;
|
| 51 | +import java.util.Map;
|
|
| 45 | 52 | import java.util.Objects;
|
| 53 | +import java.util.Optional;
|
|
| 54 | +import java.util.Set;
|
|
| 55 | +import java.util.stream.Collectors;
|
|
| 46 | 56 | |
| 47 | 57 | /**
|
| 48 | 58 | * Created on 30/10/2020.
|
| ... | ... | @@ -52,6 +62,7 @@ import java.util.Objects; |
| 52 | 62 | */
|
| 53 | 63 | public abstract class ContentReferentialUIModelStates<D extends ReferentialDto, R extends ReferentialDtoReference> extends ContentUIModelStates {
|
| 54 | 64 | public static final String PROPERTY_SELECTED_BEAN_REFERENCE = "selectedBeanReference";
|
| 65 | + private static final Logger log = LogManager.getLogger(ContentReferentialUIModelStates.class);
|
|
| 55 | 66 | /**
|
| 56 | 67 | * Reference cache.
|
| 57 | 68 | */
|
| ... | ... | @@ -67,6 +78,12 @@ public abstract class ContentReferentialUIModelStates<D extends ReferentialDto, |
| 67 | 78 | private Form<D> form;
|
| 68 | 79 | private ToolkitIdLabel replaceReference;
|
| 69 | 80 | private ContentReferentialUI<D, R, ?> ui;
|
| 81 | + /**
|
|
| 82 | + * To keep the second level usages when necessary).
|
|
| 83 | + *
|
|
| 84 | + * @since 9.4.0
|
|
| 85 | + */
|
|
| 86 | + private Map<Class<? extends ReferentialDto>, Collection<ToolkitIdLabel>> secondLevelUsages;
|
|
| 70 | 87 | |
| 71 | 88 | public ContentReferentialUIModelStates(ContentReferentialUIModel<D, R> model, D bean) {
|
| 72 | 89 | source = Objects.requireNonNull(model).getSource();
|
| ... | ... | @@ -194,7 +211,45 @@ public abstract class ContentReferentialUIModelStates<D extends ReferentialDto, |
| 194 | 211 | return mainType;
|
| 195 | 212 | }
|
| 196 | 213 | |
| 214 | + public ExtraSaveRequest toExtraSaveRequest() {
|
|
| 215 | + ToolkitIdLabel replaceReference = getReplaceReference();
|
|
| 216 | + if (replaceReference != null) {
|
|
| 217 | + String id = bean.getId();
|
|
| 218 | + String replaceId = replaceReference.getId();
|
|
| 219 | + log.info("Do replace reference before save ({} → {})", id, replaceId);
|
|
| 220 | + }
|
|
| 221 | + Map<Class<? extends ReferentialDto>, Set<String>> toDisableIds = getToDisableIds();
|
|
| 222 | + if (toDisableIds != null) {
|
|
| 223 | + toDisableIds.forEach((k, v) -> log.info("Do disable references before save of type {} → {} id(s)", k, v.size()));
|
|
| 224 | + }
|
|
| 225 | + String replaceId = Optional.ofNullable(replaceReference).map(ToolkitIdBean::getId).orElse(null);
|
|
| 226 | + if (replaceId == null && toDisableIds == null) {
|
|
| 227 | + return null;
|
|
| 228 | + }
|
|
| 229 | + return new ExtraSaveRequest(replaceId, toDisableIds);
|
|
| 230 | + }
|
|
| 231 | + |
|
| 232 | + private Map<Class<? extends ReferentialDto>, Set<String>> getToDisableIds() {
|
|
| 233 | + Map<Class<? extends ReferentialDto>, Collection<ToolkitIdLabel>> secondLevelUsages = getSecondLevelUsages();
|
|
| 234 | + Map<Class<? extends ReferentialDto>, Set<String>> toDisableIds;
|
|
| 235 | + if (secondLevelUsages == null) {
|
|
| 236 | + toDisableIds = null;
|
|
| 237 | + } else {
|
|
| 238 | + toDisableIds = new LinkedHashMap<>(secondLevelUsages.size());
|
|
| 239 | + secondLevelUsages.forEach((k, v) -> toDisableIds.put(k, v.stream().map(ToolkitIdBean::getId).collect(Collectors.toSet())));
|
|
| 240 | + }
|
|
| 241 | + return toDisableIds;
|
|
| 242 | + }
|
|
| 243 | + |
|
| 197 | 244 | public Class<R> mainReferenceType() {
|
| 198 | 245 | return mainReferenceType;
|
| 199 | 246 | }
|
| 247 | + |
|
| 248 | + public Map<Class<? extends ReferentialDto>, Collection<ToolkitIdLabel>> getSecondLevelUsages() {
|
|
| 249 | + return secondLevelUsages;
|
|
| 250 | + }
|
|
| 251 | + |
|
| 252 | + public void setSecondLevelUsages(Map<Class<? extends ReferentialDto>, Collection<ToolkitIdLabel>> secondLevelUsages) {
|
|
| 253 | + this.secondLevelUsages = secondLevelUsages;
|
|
| 254 | + }
|
|
| 200 | 255 | } |
| ... | ... | @@ -24,16 +24,28 @@ package fr.ird.observe.client.datasource.editor.api.content.referential; |
| 24 | 24 | |
| 25 | 25 | import fr.ird.observe.client.datasource.editor.api.content.actions.save.SavePredicateSupport;
|
| 26 | 26 | import fr.ird.observe.client.datasource.editor.api.content.referential.usage.UsageForDesactivateUIHandler;
|
| 27 | +import fr.ird.observe.dto.BusinessDto;
|
|
| 27 | 28 | import fr.ird.observe.dto.ToolkitIdDtoBean;
|
| 28 | 29 | import fr.ird.observe.dto.ToolkitIdLabel;
|
| 29 | 30 | import fr.ird.observe.dto.reference.ReferentialDtoReference;
|
| 30 | 31 | import fr.ird.observe.dto.referential.ReferenceStatus;
|
| 31 | 32 | import fr.ird.observe.dto.referential.ReferentialDto;
|
| 32 | 33 | import fr.ird.observe.services.service.UsageCount;
|
| 34 | +import fr.ird.observe.services.service.UsageCountWithLabel;
|
|
| 33 | 35 | import fr.ird.observe.services.service.UsageService;
|
| 36 | +import fr.ird.observe.services.service.referential.ObserveReferentialSecondLevelDeepBehaviourModel;
|
|
| 37 | +import fr.ird.observe.spi.module.ObserveBusinessProject;
|
|
| 38 | +import io.ultreia.java4all.i18n.I18n;
|
|
| 34 | 39 | import org.apache.commons.lang3.tuple.Pair;
|
| 40 | +import org.apache.logging.log4j.LogManager;
|
|
| 41 | +import org.apache.logging.log4j.Logger;
|
|
| 35 | 42 | |
| 43 | +import java.util.Collection;
|
|
| 44 | +import java.util.LinkedHashMap;
|
|
| 36 | 45 | import java.util.List;
|
| 46 | +import java.util.Map;
|
|
| 47 | +import java.util.Objects;
|
|
| 48 | +import java.util.Set;
|
|
| 37 | 49 | import java.util.stream.Collectors;
|
| 38 | 50 | |
| 39 | 51 | /**
|
| ... | ... | @@ -43,7 +55,7 @@ import java.util.stream.Collectors; |
| 43 | 55 | * @since 9.0.0
|
| 44 | 56 | */
|
| 45 | 57 | public class ReferentialSavePredicate<D extends ReferentialDto, R extends ReferentialDtoReference, S extends ContentReferentialUIModelStates<D, R>> extends SavePredicateSupport<S,D> {
|
| 46 | - |
|
| 58 | + private static final Logger log = LogManager.getLogger(ReferentialSavePredicate.class);
|
|
| 47 | 59 | public ReferentialSavePredicate(S states) {
|
| 48 | 60 | super(states);
|
| 49 | 61 | }
|
| ... | ... | @@ -66,26 +78,51 @@ public class ReferentialSavePredicate<D extends ReferentialDto, R extends Refere |
| 66 | 78 | ToolkitIdDtoBean request = states.toUsageRequest(bean.getId());
|
| 67 | 79 | UsageCount usages = usageService.countReferential(request);
|
| 68 | 80 | |
| 69 | - if (!usages.isEmpty()) {
|
|
| 70 | - // some usages were found
|
|
| 81 | + if (usages.isEmpty()) {
|
|
| 82 | + return true;
|
|
| 83 | + }
|
|
| 71 | 84 | |
| 72 | - // get replacements
|
|
| 73 | - List<R> referentialReferences = states.getReferentialReferences();
|
|
| 74 | - List<R> referenceList = referentialReferences
|
|
| 75 | - .stream()
|
|
| 76 | - .filter(ReferentialDtoReference::isEnabled)
|
|
| 77 | - .filter(r -> !bean.getId().equals(r.getId()))
|
|
| 78 | - .collect(Collectors.toList());
|
|
| 85 | + // some usages were found
|
|
| 86 | + UsageCountWithLabel realUsages = new UsageCountWithLabel(I18n.getDefaultLocale(), ObserveBusinessProject.get(), usages);
|
|
| 87 | + UsageForDesactivateUIHandler.DisableReferentialUsagesGetter getter = new UsageForDesactivateUIHandler.DisableReferentialUsagesGetter(realUsages, usageService, request);
|
|
| 79 | 88 | |
| 80 | - ToolkitIdLabel dtoLabel = bean.toLabel();
|
|
| 81 | - states.getDecoratorService().installToolkitIdLabelDecorator(bean.getClass(), dtoLabel);
|
|
| 82 | - Pair<Boolean, ToolkitIdLabel> result = UsageForDesactivateUIHandler.showUsages(usageService, dtoLabel, request, usages, referenceList.stream().map(ReferentialDtoReference::toLabel).collect(Collectors.toList()));
|
|
| 83 | - boolean willSave = result.getLeft();
|
|
| 84 | - if (!willSave) {
|
|
| 85 | - return false;
|
|
| 89 | + ObserveReferentialSecondLevelDeepBehaviourModel referentialSecondLevelDeepBehaviourModel = ObserveReferentialSecondLevelDeepBehaviourModel.get();
|
|
| 90 | + Map<Class<? extends ReferentialDto>, Collection<ToolkitIdLabel>> secondLevelUsages = new LinkedHashMap<>();
|
|
| 91 | + Set<Class<? extends BusinessDto>> typesFound = usages.keySet();
|
|
| 92 | + for (Class<? extends BusinessDto> type : typesFound) {
|
|
| 93 | + if (!ReferentialDto.class.isAssignableFrom(type) ) {
|
|
| 94 | + continue;
|
|
| 86 | 95 | }
|
| 87 | - states.setReplaceReference(result.getRight());
|
|
| 96 | + @SuppressWarnings("unchecked") Class<? extends ReferentialDto> referentialType = (Class<? extends ReferentialDto>) type;
|
|
| 97 | + if (referentialSecondLevelDeepBehaviourModel.useSecondLevelDeepBehaviour(referentialType)) {
|
|
| 98 | + Collection<ToolkitIdLabel> toolkitIdLabels = getter.getUsages(type).get();
|
|
| 99 | + log.info("Found second level type: {} - {} occurrence(s).", referentialType, toolkitIdLabels.size());
|
|
| 100 | + secondLevelUsages.put(referentialType,toolkitIdLabels);
|
|
| 101 | + }
|
|
| 102 | + }
|
|
| 103 | + if (!secondLevelUsages.isEmpty()) {
|
|
| 104 | + states.setSecondLevelUsages(secondLevelUsages);
|
|
| 105 | + }
|
|
| 106 | + |
|
| 107 | + // get replacements
|
|
| 108 | + List<R> referentialReferences = states.getReferentialReferences();
|
|
| 109 | + List<ToolkitIdLabel> referenceList = referentialReferences
|
|
| 110 | + .stream()
|
|
| 111 | + .filter(ReferentialDtoReference::isEnabled)
|
|
| 112 | + .filter(r -> !Objects.equals(bean.getId(), r.getId()))
|
|
| 113 | + .map(ReferentialDtoReference::toLabel)
|
|
| 114 | + .collect(Collectors.toList());
|
|
| 115 | + |
|
| 116 | + ToolkitIdLabel dtoLabel = bean.toLabel();
|
|
| 117 | + states.getDecoratorService().installToolkitIdLabelDecorator(bean.getClass(), dtoLabel);
|
|
| 118 | + Pair<Boolean, ToolkitIdLabel> result = UsageForDesactivateUIHandler.showUsages(dtoLabel,
|
|
| 119 | + getter,
|
|
| 120 | + referenceList);
|
|
| 121 | + boolean willSave = result.getLeft();
|
|
| 122 | + if (!willSave) {
|
|
| 123 | + return false;
|
|
| 88 | 124 | }
|
| 125 | + states.setReplaceReference(result.getRight());
|
|
| 89 | 126 | }
|
| 90 | 127 | return true;
|
| 91 | 128 | }
|
| ... | ... | @@ -29,12 +29,10 @@ import fr.ird.observe.client.util.init.UIInitHelper; |
| 29 | 29 | import fr.ird.observe.dto.BusinessDto;
|
| 30 | 30 | import fr.ird.observe.dto.ToolkitIdDtoBean;
|
| 31 | 31 | import fr.ird.observe.dto.ToolkitIdLabel;
|
| 32 | -import fr.ird.observe.services.service.UsageCount;
|
|
| 33 | 32 | import fr.ird.observe.services.service.UsageCountWithLabel;
|
| 34 | 33 | import fr.ird.observe.services.service.UsageService;
|
| 35 | 34 | import fr.ird.observe.spi.module.ObserveBusinessProject;
|
| 36 | 35 | import io.ultreia.java4all.application.template.spi.GenerateTemplate;
|
| 37 | -import io.ultreia.java4all.i18n.I18n;
|
|
| 38 | 36 | import io.ultreia.java4all.jaxx.widgets.combobox.FilterableComboBox;
|
| 39 | 37 | import io.ultreia.java4all.jaxx.widgets.combobox.FilterableComboBoxModel;
|
| 40 | 38 | import io.ultreia.java4all.util.SingletonSupplier;
|
| ... | ... | @@ -85,15 +83,10 @@ public class UsageForDesactivateUIHandler extends UsageUIHandlerSupport<UsageFor |
| 85 | 83 | }
|
| 86 | 84 | }
|
| 87 | 85 | |
| 88 | - public static Pair<Boolean, ToolkitIdLabel> showUsages(UsageService usageService,
|
|
| 89 | - ToolkitIdLabel dto,
|
|
| 90 | - ToolkitIdDtoBean request,
|
|
| 91 | - UsageCount usages,
|
|
| 86 | + public static Pair<Boolean, ToolkitIdLabel> showUsages(ToolkitIdLabel dto,
|
|
| 87 | + DisableReferentialUsagesGetter getter,
|
|
| 92 | 88 | List<ToolkitIdLabel> referenceList) {
|
| 93 | 89 | ObserveBusinessProject businessProject = ObserveBusinessProject.get();
|
| 94 | - UsageCountWithLabel realUsages = new UsageCountWithLabel(I18n.getDefaultLocale(), businessProject, usages);
|
|
| 95 | - DisableReferentialUsagesGetter getter = new DisableReferentialUsagesGetter(realUsages, usageService, request);
|
|
| 96 | - |
|
| 97 | 90 | Class<? extends BusinessDto> dtoType = dto.getType();
|
| 98 | 91 | String type = businessProject.getLongTitle(dtoType);
|
| 99 | 92 | String message = t("observe.ui.message.show.usage.referential.disabled", type, dto);
|
| ... | ... | @@ -28,6 +28,7 @@ import fr.ird.observe.dto.referential.common.SpeciesReference; |
| 28 | 28 | import fr.ird.observe.services.service.SaveResultDto;
|
| 29 | 29 | import fr.ird.observe.spi.result.AddEntityToUpdateStep;
|
| 30 | 30 | import fr.ird.observe.spi.service.ServiceContext;
|
| 31 | +import io.ultreia.java4all.util.sql.SqlScript;
|
|
| 31 | 32 | |
| 32 | 33 | import java.util.LinkedHashSet;
|
| 33 | 34 | import java.util.List;
|
| ... | ... | @@ -54,7 +55,7 @@ public class OceanSpi extends GeneratedOceanSpi { |
| 54 | 55 | }
|
| 55 | 56 | |
| 56 | 57 | @Override
|
| 57 | - public SaveResultDto saveEntity(ServiceContext context, Ocean entity, OceanDto dto) {
|
|
| 58 | + public SaveResultDto saveEntity(ServiceContext context, Ocean entity, OceanDto dto, List<SqlScript> extraScripts) {
|
|
| 58 | 59 | Set<Species> speciesToUpdate = new LinkedHashSet<>();
|
| 59 | 60 | Set<String> newSpeciesWithThisOceanIds = dto.getSpecies().stream().map(SpeciesReference::getId).collect(Collectors.toSet());
|
| 60 | 61 | if (dto.isPersisted()) {
|
| ... | ... | @@ -87,6 +88,6 @@ public class OceanSpi extends GeneratedOceanSpi { |
| 87 | 88 | for (Species species : speciesToUpdate) {
|
| 88 | 89 | update.update(Species.SPI, species);
|
| 89 | 90 | }
|
| 90 | - return update.build(entity);
|
|
| 91 | + return update.addExtraSqlScripts(extraScripts).build(entity);
|
|
| 91 | 92 | }
|
| 92 | -} //OceanSpi |
|
| 93 | +} |
| ... | ... | @@ -31,6 +31,7 @@ import fr.ird.observe.dto.reference.ReferentialDtoReferenceSet; |
| 31 | 31 | import fr.ird.observe.dto.referential.ReferentialDto;
|
| 32 | 32 | import fr.ird.observe.services.local.service.ObserveServiceLocal;
|
| 33 | 33 | import fr.ird.observe.services.service.SaveResultDto;
|
| 34 | +import fr.ird.observe.services.service.referential.ExtraSaveRequest;
|
|
| 34 | 35 | import fr.ird.observe.services.service.referential.ReferentialIds;
|
| 35 | 36 | import fr.ird.observe.services.service.referential.ReferentialService;
|
| 36 | 37 | import fr.ird.observe.spi.context.ReferentialDtoEntityContext;
|
| ... | ... | @@ -85,10 +86,10 @@ class ReferentialServiceLocalSupport extends ObserveServiceLocal implements Refe |
| 85 | 86 | }
|
| 86 | 87 | |
| 87 | 88 | @Override
|
| 88 | - public <D extends ReferentialDto> SaveResultDto save(D bean) throws ConcurrentModificationException {
|
|
| 89 | + public <D extends ReferentialDto> SaveResultDto save(D bean, ExtraSaveRequest extraSaveRequest) throws ConcurrentModificationException {
|
|
| 89 | 90 | @SuppressWarnings("unchecked") Class<D> type = (Class<D>) bean.getClass();
|
| 90 | 91 | ReferentialDtoEntityContext<D, ?, ?, ?> spi = fromReferentialDto(type);
|
| 91 | - return spi.save(this, bean);
|
|
| 92 | + return spi.save(this, bean, extraSaveRequest);
|
|
| 92 | 93 | }
|
| 93 | 94 | |
| 94 | 95 | @Override
|
| ... | ... | @@ -31,6 +31,7 @@ import fr.ird.observe.dto.referential.common.SpeciesDto; |
| 31 | 31 | import fr.ird.observe.services.local.LocalTestClassResource;
|
| 32 | 32 | import fr.ird.observe.services.local.LocalTestMethodResourceWrite;
|
| 33 | 33 | import fr.ird.observe.services.local.service.ServiceLocalTestSupportWrite;
|
| 34 | +import fr.ird.observe.services.service.referential.ExtraSaveRequest;
|
|
| 34 | 35 | import fr.ird.observe.services.service.referential.ReferentialService;
|
| 35 | 36 | import fr.ird.observe.services.service.referential.ReferentialServiceFixtures;
|
| 36 | 37 | import fr.ird.observe.services.service.referential.SynchronizeEngine;
|
| ... | ... | @@ -121,7 +122,7 @@ public class UnidirectionalResultIssue2208Test extends ServiceLocalTestSupportWr |
| 121 | 122 | centralSpecies.getOcean().add(ocean);
|
| 122 | 123 | TOPIA_TEST_CLASS_RESOURCE_CENTRAL.setGenerateNow(true);
|
| 123 | 124 | try {
|
| 124 | - centralReferentialService.save(centralSpecies);
|
|
| 125 | + centralReferentialService.save(centralSpecies, null);
|
|
| 125 | 126 | } finally {
|
| 126 | 127 | TOPIA_TEST_CLASS_RESOURCE_CENTRAL.setGenerateNow(false);
|
| 127 | 128 | }
|
| ... | ... | @@ -189,7 +189,7 @@ public class ReferentialServiceFixtures extends GeneratedReferentialServiceFixtu |
| 189 | 189 | fr.ird.observe.dto.referential.ps.common.ProgramDto actual = service.loadDto(fr.ird.observe.dto.referential.ps.common.ProgramDto.class, getProperty("loadDto.id"));
|
| 190 | 190 | Assert.assertNotNull(actual);
|
| 191 | 191 | try {
|
| 192 | - SaveResultDto actualResult = service.save(actual);
|
|
| 192 | + SaveResultDto actualResult = service.save(actual, null);
|
|
| 193 | 193 | Assert.assertNotNull(actualResult);
|
| 194 | 194 | } catch (ConcurrentModificationException e) {
|
| 195 | 195 | throw new RuntimeException(e);
|
| ... | ... | @@ -40,6 +40,7 @@ import fr.ird.observe.entities.referential.I18nReferentialEntity; |
| 40 | 40 | import fr.ird.observe.entities.referential.ReferentialEntity;
|
| 41 | 41 | import fr.ird.observe.services.service.SaveResultDto;
|
| 42 | 42 | import fr.ird.observe.services.service.UsageCount;
|
| 43 | +import fr.ird.observe.services.service.referential.ExtraSaveRequest;
|
|
| 43 | 44 | import fr.ird.observe.spi.referential.ReferentialExtraScripts;
|
| 44 | 45 | import fr.ird.observe.spi.service.ServiceContext;
|
| 45 | 46 | import fr.ird.observe.spi.usage.UsageHelper;
|
| ... | ... | @@ -52,10 +53,11 @@ import org.nuiton.topia.persistence.TopiaEntity; |
| 52 | 53 | import org.nuiton.topia.persistence.TopiaException;
|
| 53 | 54 | import org.nuiton.topia.service.sql.script.DeleteReferentialScript;
|
| 54 | 55 | import org.nuiton.topia.service.sql.script.DisableReferentialScript;
|
| 55 | -import org.nuiton.topia.service.sql.script.ReplaceReferentialInReferentialScript;
|
|
| 56 | 56 | import org.nuiton.topia.service.sql.script.ReplaceReferentialInDataScript;
|
| 57 | +import org.nuiton.topia.service.sql.script.ReplaceReferentialInReferentialScript;
|
|
| 57 | 58 | import org.nuiton.topia.service.sql.script.TopiaEntitySqlScript;
|
| 58 | 59 | |
| 60 | +import java.sql.Timestamp;
|
|
| 59 | 61 | import java.util.ArrayList;
|
| 60 | 62 | import java.util.Collection;
|
| 61 | 63 | import java.util.Comparator;
|
| ... | ... | @@ -83,23 +85,22 @@ public abstract class ReferentialDtoEntityContext< |
| 83 | 85 | |
| 84 | 86 | private final SingletonSupplier<ReferentialExtraScripts<E>> extraScripts;
|
| 85 | 87 | |
| 86 | - protected abstract TopiaEntitySqlScript loadSqlScript();
|
|
| 87 | - |
|
| 88 | - |
|
| 89 | - protected abstract ReferentialExtraScripts<E> loadExtraScripts();
|
|
| 90 | - |
|
| 91 | 88 | public ReferentialDtoEntityContext() {
|
| 92 | 89 | this.extraScripts = SingletonSupplier.of(this::loadExtraScripts);
|
| 93 | 90 | }
|
| 94 | 91 | |
| 92 | + protected abstract TopiaEntitySqlScript loadSqlScript();
|
|
| 93 | + |
|
| 94 | + protected abstract ReferentialExtraScripts<E> loadExtraScripts();
|
|
| 95 | + |
|
| 95 | 96 | @Override
|
| 96 | 97 | public Form<D> loadForm(ServiceContext context, String id) {
|
| 97 | 98 | E entity = loadEntity(context, id);
|
| 98 | 99 | return referentialEntityToForm(context.getReferentialLocale(), entity);
|
| 99 | 100 | }
|
| 100 | 101 | |
| 101 | - public SaveResultDto saveEntity(ServiceContext context, E entity, D dto) {
|
|
| 102 | - return saveEntity(context, entity);
|
|
| 102 | + public SaveResultDto saveEntity(ServiceContext context, E entity, D dto, List<SqlScript> extraScripts) {
|
|
| 103 | + return newSaveHelper(context).update(this, entity).addExtraSqlScripts(extraScripts).build(entity);
|
|
| 103 | 104 | }
|
| 104 | 105 | |
| 105 | 106 | public Optional<ReplaceReferentialInDataScript> getReplaceInDataScript() {
|
| ... | ... | @@ -261,6 +262,15 @@ public abstract class ReferentialDtoEntityContext< |
| 261 | 262 | sqlScript.ifPresent(s -> context.getTopiaPersistenceContext().executeSqlScript(s));
|
| 262 | 263 | }
|
| 263 | 264 | |
| 265 | + public final Optional<SqlScript> replaceReferenceScript(ServiceContext context, String idToReplace, String replaceId, boolean replaceInReferential, boolean replaceInData) {
|
|
| 266 | + if (!replaceInReferential && !replaceInData) {
|
|
| 267 | + throw new IllegalStateException("Need at least one of the parameters *replaceInReferential* or *replaceInData* to be on.");
|
|
| 268 | + }
|
|
| 269 | + checkEntityExists(context, idToReplace);
|
|
| 270 | + checkEntityExists(context, replaceId);
|
|
| 271 | + return generateReplaceScript(idToReplace, replaceId, context.now(), replaceInReferential, replaceInData);
|
|
| 272 | + }
|
|
| 273 | + |
|
| 264 | 274 | public final void changeId(ServiceContext context, String id, String newId) {
|
| 265 | 275 | checkEntityExists(context, id);
|
| 266 | 276 | log.info(String.format("will change id from %s to %s", id, newId));
|
| ... | ... | @@ -284,11 +294,33 @@ public abstract class ReferentialDtoEntityContext< |
| 284 | 294 | // delete(context, id);
|
| 285 | 295 | }
|
| 286 | 296 | |
| 287 | - public final SaveResultDto save(ServiceContext context, D dto) throws ConcurrentModificationException {
|
|
| 297 | + public final SaveResultDto save(ServiceContext context, D dto, ExtraSaveRequest extraSaveRequest) throws ConcurrentModificationException {
|
|
| 288 | 298 | E entity = loadOrCreateEntityFromReferentialDto(context, dto);
|
| 289 | 299 | checkLastUpdateDate(context, entity, dto);
|
| 300 | + // if replace id is here, let's do the replacement in data (never replace in referential)
|
|
| 301 | + List<SqlScript> extraScripts = new ArrayList<>();
|
|
| 302 | + if (extraSaveRequest != null) {
|
|
| 303 | + extraSaveRequest.getReplaceId().ifPresent(replaceId -> {
|
|
| 304 | + Optional<SqlScript> sqlScript = replaceReferenceScript(context, dto.getId(), replaceId, false, true);
|
|
| 305 | + sqlScript.ifPresent(extraScripts::add);
|
|
| 306 | + });
|
|
| 307 | + Timestamp timestamp = context.timestampNow();
|
|
| 308 | + extraSaveRequest.getToDisableIds().ifPresent(toDisableIds -> {
|
|
| 309 | + // if toDisableIds is here, let's do the disable actions
|
|
| 310 | + List<String> sqlStatements = new ArrayList<>();
|
|
| 311 | + toDisableIds.forEach((k, v) -> {
|
|
| 312 | + ReferentialDtoEntityContext<? extends ReferentialDto, ?, ?, ?> spi2 = context.fromReferentialDto(k);
|
|
| 313 | + DisableReferentialScript disableScript = spi2.getDisableScript();
|
|
| 314 | + v.forEach(id -> sqlStatements.addAll(disableScript.generate(id, timestamp)));
|
|
| 315 | + sqlStatements.addAll(spi2.updateLastUpdateDateTable(context.getTopiaPersistenceContext(), timestamp));
|
|
| 316 | + });
|
|
| 317 | + if (!sqlStatements.isEmpty()) {
|
|
| 318 | + extraScripts.add(SqlScript.of(String.join("\n", sqlStatements)));
|
|
| 319 | + }
|
|
| 320 | + });
|
|
| 321 | + }
|
|
| 290 | 322 | fromDto(context.getReferentialLocale(), entity, dto);
|
| 291 | - return saveEntity(context, entity, dto);
|
|
| 323 | + return saveEntity(context, entity, dto, extraScripts);
|
|
| 292 | 324 | }
|
| 293 | 325 | |
| 294 | 326 | private SqlScript generateDuplicateScript(ServiceContext context, String id, String newId) {
|
| ... | ... | @@ -357,10 +389,6 @@ public abstract class ReferentialDtoEntityContext< |
| 357 | 389 | return toReference(context.getReferentialLocale(), entity);
|
| 358 | 390 | }
|
| 359 | 391 | |
| 360 | - public final SaveResultDto saveEntity(ServiceContext context, E entity) {
|
|
| 361 | - return newSaveHelper(context).update(this, entity).build(entity);
|
|
| 362 | - }
|
|
| 363 | - |
|
| 364 | 392 | public final UsageCount count(ServiceContext context, ToolkitIdDtoBean request) {
|
| 365 | 393 | ReferentialEntity entity = loadEntity(context, request.getId());
|
| 366 | 394 | return newUsageHelper(context).count(entity);
|