Tony CHEMIT pushed to branch feature/issue-2846 at ultreiaio / ird-observe

Commits:

24 changed files:

Changes:

  • client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ContentReferentialUIHandler.java
    ... ... @@ -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
         }
    

  • client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ContentReferentialUIModelStates.java
    ... ... @@ -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
     }

  • client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/ReferentialSavePredicate.java
    ... ... @@ -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
         }
    

  • client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/actions/ReplaceReferentialUsages.java
    ... ... @@ -57,7 +57,7 @@ import static io.ultreia.java4all.i18n.I18n.n;
    57 57
      */
    
    58 58
     public class ReplaceReferentialUsages<D extends ReferentialDto, R extends ReferentialDtoReference, U extends ContentReferentialUI<D, R, U>> extends ContentReferentialUIActionSupport<D, R, U> implements ConfigureMenuAction<U> {
    
    59 59
     
    
    60
    -    private static final Logger log = LogManager.getLogger(DeleteReferential.class);
    
    60
    +    private static final Logger log = LogManager.getLogger(ReplaceReferentialUsages.class);
    
    61 61
     
    
    62 62
         private ToolkitIdLabel replaceReference;
    
    63 63
     
    

  • client/datasource/editor/api/src/main/java/fr/ird/observe/client/datasource/editor/api/content/referential/usage/UsageForDesactivateUIHandler.java
    ... ... @@ -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);
    

  • core/api/services/pom.xml
    ... ... @@ -84,6 +84,11 @@
    84 84
           <groupId>io.ultreia.java4all.http</groupId>
    
    85 85
           <artifactId>http-api</artifactId>
    
    86 86
         </dependency>
    
    87
    +    <dependency>
    
    88
    +      <groupId>junit</groupId>
    
    89
    +      <artifactId>junit</artifactId>
    
    90
    +      <scope>test</scope>
    
    91
    +    </dependency>
    
    87 92
         <dependency>
    
    88 93
           <groupId>io.ultreia.java4all.http</groupId>
    
    89 94
           <artifactId>http-spi-processor</artifactId>
    

  • core/api/services/src/main/resources/META-INF/services/Observe/ReferentialSecondLevelDeepBehaviourModel.json
    1
    +[
    
    2
    +  "fr.ird.observe.dto.referential.common.LengthLengthParameterDto",
    
    3
    +  "fr.ird.observe.dto.referential.common.LengthWeightParameterDto",
    
    4
    +  "fr.ird.observe.dto.referential.ps.common.WeightCategoryDto"
    
    5
    +]
    \ No newline at end of file

  • core/api/services/src/test/java/fr/ird/observe/services/service/referential/ObserveReferentialSecondLevelDeepBehaviourModelTest.java
    1
    +package fr.ird.observe.services.service.referential;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Core :: API :: Services
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import fr.ird.observe.dto.referential.ReferentialDto;
    
    26
    +import fr.ird.observe.dto.referential.common.LengthLengthParameterDto;
    
    27
    +import fr.ird.observe.dto.referential.common.LengthWeightParameterDto;
    
    28
    +import fr.ird.observe.dto.referential.common.SpeciesDto;
    
    29
    +import fr.ird.observe.dto.referential.ps.common.WeightCategoryDto;
    
    30
    +import org.junit.Test;
    
    31
    +
    
    32
    +import java.util.Iterator;
    
    33
    +import java.util.Set;
    
    34
    +
    
    35
    +import static org.junit.Assert.assertEquals;
    
    36
    +import static org.junit.Assert.assertFalse;
    
    37
    +import static org.junit.Assert.assertNotNull;
    
    38
    +import static org.junit.Assert.assertTrue;
    
    39
    +
    
    40
    +/**
    
    41
    + * Created at 30/09/2024.
    
    42
    + *
    
    43
    + * @author Tony Chemit - dev@tchemit.fr
    
    44
    + * @since 9.4.0
    
    45
    + */
    
    46
    +public class ObserveReferentialSecondLevelDeepBehaviourModelTest {
    
    47
    +
    
    48
    +    @Test
    
    49
    +    public void get() {
    
    50
    +        ObserveReferentialSecondLevelDeepBehaviourModel model = ObserveReferentialSecondLevelDeepBehaviourModel.get();
    
    51
    +        assertNotNull(model);
    
    52
    +        Set<Class<? extends ReferentialDto>> entries = model.entries();
    
    53
    +        assertEquals(3, entries.size());
    
    54
    +        Iterator<Class<? extends ReferentialDto>> iterator = entries.iterator();
    
    55
    +        assertEquals(LengthLengthParameterDto.class, iterator.next());
    
    56
    +        assertEquals(LengthWeightParameterDto.class, iterator.next());
    
    57
    +        assertEquals(WeightCategoryDto.class, iterator.next());
    
    58
    +    }
    
    59
    +
    
    60
    +    @Test
    
    61
    +    public void useSecondLevelDeepBehaviour() {
    
    62
    +        ObserveReferentialSecondLevelDeepBehaviourModel model = ObserveReferentialSecondLevelDeepBehaviourModel.get();
    
    63
    +        assertNotNull(model);
    
    64
    +        assertTrue(model.useSecondLevelDeepBehaviour(LengthLengthParameterDto.class));
    
    65
    +        assertTrue(model.useSecondLevelDeepBehaviour(LengthWeightParameterDto.class));
    
    66
    +        assertTrue(model.useSecondLevelDeepBehaviour(WeightCategoryDto.class));
    
    67
    +        assertFalse(model.useSecondLevelDeepBehaviour(SpeciesDto.class));
    
    68
    +    }
    
    69
    +}

  • core/persistence/java/src/main/java/fr/ird/observe/entities/referential/common/OceanSpi.java
    ... ... @@ -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
    +}

  • core/services/local/src/main/java/fr/ird/observe/services/local/service/referential/ReferentialServiceLocalSupport.java
    ... ... @@ -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
    

  • core/services/local/src/test/java/fr/ird/observe/services/local/service/referential/UnidirectionalResultIssue2208Test.java
    ... ... @@ -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
             }
    

  • core/services/test/src/main/java/fr/ird/observe/services/service/referential/ReferentialServiceFixtures.java
    ... ... @@ -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);
    

  • model/src/main/models/Observe/dto/class/referentialSecondLevelDeepBehaviour.properties
    1
    +###
    
    2
    +# #%L
    
    3
    +# ObServe :: Model
    
    4
    +# %%
    
    5
    +# Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    6
    +# %%
    
    7
    +# This program is free software: you can redistribute it and/or modify
    
    8
    +# it under the terms of the GNU General Public License as
    
    9
    +# published by the Free Software Foundation, either version 3 of the
    
    10
    +# License, or (at your option) any later version.
    
    11
    +#
    
    12
    +# This program is distributed in the hope that it will be useful,
    
    13
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    14
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    15
    +# GNU General Public License for more details.
    
    16
    +#
    
    17
    +# You should have received a copy of the GNU General Public
    
    18
    +# License along with this program.  If not, see
    
    19
    +# <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    20
    +# #L%
    
    21
    +###
    
    22
    +referential.common.LengthLengthParameter=true
    
    23
    +referential.common.LengthWeightParameter=true
    
    24
    +referential.ps.common.WeightCategory=true

  • toolkit/api-services/src/main/java/fr/ird/observe/services/service/referential/ExtraSaveRequest.java
    1
    +package fr.ird.observe.services.service.referential;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Toolkit :: API :: Services
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import fr.ird.observe.dto.referential.ReferentialDto;
    
    26
    +import io.ultreia.java4all.util.json.JsonAware;
    
    27
    +
    
    28
    +import java.util.Map;
    
    29
    +import java.util.Optional;
    
    30
    +import java.util.Set;
    
    31
    +
    
    32
    +/**
    
    33
    + * An object to define all extra actions that can be done while trying to save a referential.
    
    34
    + * <p>
    
    35
    + * Created at 30/09/2024.
    
    36
    + *
    
    37
    + * @author Tony Chemit - dev@tchemit.fr
    
    38
    + * @since 9.4.0
    
    39
    + */
    
    40
    +public class ExtraSaveRequest implements JsonAware {
    
    41
    +    /**
    
    42
    +     * Optional replace id to perform before save.
    
    43
    +     */
    
    44
    +    private final String replaceId;
    
    45
    +    /**
    
    46
    +     * Optional disable id to perform before save.
    
    47
    +     */
    
    48
    +    private final Map<Class<? extends ReferentialDto>, Set<String>> toDisableIds;
    
    49
    +
    
    50
    +    public ExtraSaveRequest(String replaceId, Map<Class<? extends ReferentialDto>, Set<String>> toDisableIds) {
    
    51
    +        this.replaceId = replaceId;
    
    52
    +        this.toDisableIds = toDisableIds;
    
    53
    +    }
    
    54
    +
    
    55
    +    public Optional<String> getReplaceId() {
    
    56
    +        return Optional.ofNullable(replaceId);
    
    57
    +    }
    
    58
    +
    
    59
    +    public Optional<Map<Class<? extends ReferentialDto>, Set<String>>> getToDisableIds() {
    
    60
    +        return Optional.ofNullable(toDisableIds);
    
    61
    +    }
    
    62
    +}

  • toolkit/api-services/src/main/java/fr/ird/observe/services/service/referential/ReferentialSecondLevelDeepBehaviourModel.java
    1
    +package fr.ird.observe.services.service.referential;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Toolkit :: API :: Services
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import com.google.gson.Gson;
    
    26
    +import com.google.gson.GsonBuilder;
    
    27
    +import com.google.gson.reflect.TypeToken;
    
    28
    +import fr.ird.observe.dto.referential.ReferentialDto;
    
    29
    +import io.ultreia.java4all.util.json.JsonAware;
    
    30
    +import io.ultreia.java4all.util.json.adapters.ClassAdapter;
    
    31
    +
    
    32
    +import java.io.BufferedReader;
    
    33
    +import java.io.IOException;
    
    34
    +import java.io.InputStreamReader;
    
    35
    +import java.io.Reader;
    
    36
    +import java.net.URL;
    
    37
    +import java.nio.charset.StandardCharsets;
    
    38
    +import java.util.Collections;
    
    39
    +import java.util.LinkedHashSet;
    
    40
    +import java.util.Objects;
    
    41
    +import java.util.Set;
    
    42
    +
    
    43
    +/**
    
    44
    + * Created at 30/09/2024.
    
    45
    + *
    
    46
    + * @author Tony Chemit - dev@tchemit.fr
    
    47
    + * @since 9.4.0
    
    48
    + */
    
    49
    +public class ReferentialSecondLevelDeepBehaviourModel implements JsonAware {
    
    50
    +
    
    51
    +    public static String toLocation(String modelName) {
    
    52
    +        return String.format("META-INF/services/%s/%s.json", Objects.requireNonNull(modelName), ReferentialSecondLevelDeepBehaviourModel.class.getSimpleName());
    
    53
    +    }
    
    54
    +
    
    55
    +    public static Gson newGson() {
    
    56
    +        return new GsonBuilder()
    
    57
    +                .disableHtmlEscaping()
    
    58
    +                .setPrettyPrinting()
    
    59
    +                .enableComplexMapKeySerialization()
    
    60
    +                .registerTypeAdapter(Class.class, new ClassAdapter())
    
    61
    +                .create();
    
    62
    +    }
    
    63
    +
    
    64
    +    private final Set<Class<? extends ReferentialDto>> entries;
    
    65
    +
    
    66
    +    public ReferentialSecondLevelDeepBehaviourModel(String modelName) {
    
    67
    +        String location = toLocation(Objects.requireNonNull(modelName));
    
    68
    +        URL resource = Objects.requireNonNull(ReferentialSecondLevelDeepBehaviourModel.class).getClassLoader().getResource(Objects.requireNonNull(location));
    
    69
    +        try (Reader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(resource).openStream(), StandardCharsets.UTF_8))) {
    
    70
    +            this.entries = Collections.unmodifiableSet(newGson().fromJson(reader, new TypeToken<LinkedHashSet<Class<? extends ReferentialDto>>>() {
    
    71
    +            }.getType()));
    
    72
    +        } catch (IOException e) {
    
    73
    +            throw new IllegalStateException(String.format("Could not load resource: %s (for type: %s)", resource, getClass().getName()), e);
    
    74
    +        }
    
    75
    +    }
    
    76
    +
    
    77
    +    public Set<Class<? extends ReferentialDto>> entries() {
    
    78
    +        return entries;
    
    79
    +    }
    
    80
    +
    
    81
    +    public boolean useSecondLevelDeepBehaviour(Class<? extends ReferentialDto> type) {
    
    82
    +        return entries().contains(type);
    
    83
    +    }
    
    84
    +}

  • toolkit/api-services/src/main/java/fr/ird/observe/services/service/referential/ReferentialService.java
    ... ... @@ -96,9 +96,9 @@ public interface ReferentialService extends ObserveService {
    96 96
         <D extends ReferentialDto> Form<D> preCreate(Class<D> type);
    
    97 97
     
    
    98 98
         @Write
    
    99
    -    @Post
    
    99
    +    @Post(useMultiPartForm = true)
    
    100 100
         @MethodCredential(Permission.WRITE_REFERENTIAL)
    
    101
    -    <D extends ReferentialDto> SaveResultDto save(D bean) throws ConcurrentModificationException;
    
    101
    +    <D extends ReferentialDto> SaveResultDto save(D bean, @Nullable ExtraSaveRequest extraSaveRequest) throws ConcurrentModificationException;
    
    102 102
     
    
    103 103
         @Write
    
    104 104
         @Delete
    

  • toolkit/persistence/src/main/java/fr/ird/observe/spi/context/ReferentialDtoEntityContext.java
    ... ... @@ -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,31 @@ 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
    +        extraSaveRequest.getReplaceId().ifPresent(replaceId -> {
    
    303
    +            Optional<SqlScript> sqlScript = replaceReferenceScript(context, dto.getId(), replaceId, false, true);
    
    304
    +            sqlScript.ifPresent(extraScripts::add);
    
    305
    +        });
    
    306
    +        Timestamp timestamp = context.timestampNow();
    
    307
    +        extraSaveRequest.getToDisableIds().ifPresent(toDisableIds -> {
    
    308
    +            // if toDisableIds is here, let's do the disable actions
    
    309
    +            List<String> sqlStatements = new ArrayList<>();
    
    310
    +            toDisableIds.forEach((k, v) -> {
    
    311
    +                ReferentialDtoEntityContext<? extends ReferentialDto, ?, ?, ?> spi2 = context.fromReferentialDto(k);
    
    312
    +                DisableReferentialScript disableScript = spi2.getDisableScript();
    
    313
    +                v.forEach(id -> sqlStatements.addAll(disableScript.generate(id, timestamp)));
    
    314
    +                sqlStatements.addAll(spi2.updateLastUpdateDateTable(context.getTopiaPersistenceContext(), timestamp));
    
    315
    +            });
    
    316
    +            if (!sqlStatements.isEmpty()) {
    
    317
    +                extraScripts.add(SqlScript.of(String.join("\n", sqlStatements)));
    
    318
    +            }
    
    319
    +        });
    
    290 320
             fromDto(context.getReferentialLocale(), entity, dto);
    
    291
    -        return saveEntity(context, entity, dto);
    
    321
    +        return saveEntity(context, entity, dto, extraScripts);
    
    292 322
         }
    
    293 323
     
    
    294 324
         private SqlScript generateDuplicateScript(ServiceContext context, String id, String newId) {
    
    ... ... @@ -357,10 +387,6 @@ public abstract class ReferentialDtoEntityContext<
    357 387
             return toReference(context.getReferentialLocale(), entity);
    
    358 388
         }
    
    359 389
     
    
    360
    -    public final SaveResultDto saveEntity(ServiceContext context, E entity) {
    
    361
    -        return newSaveHelper(context).update(this, entity).build(entity);
    
    362
    -    }
    
    363
    -
    
    364 390
         public final UsageCount count(ServiceContext context, ToolkitIdDtoBean request) {
    
    365 391
             ReferentialEntity entity = loadEntity(context, request.getId());
    
    366 392
             return newUsageHelper(context).count(entity);
    

  • toolkit/persistence/src/main/java/fr/ird/observe/spi/result/AddExtraSqlScripts.java
    1
    +package fr.ird.observe.spi.result;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Toolkit :: Persistence
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2023 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import io.ultreia.java4all.util.sql.SqlScript;
    
    26
    +
    
    27
    +import java.util.List;
    
    28
    +
    
    29
    +/**
    
    30
    + * Created at 30/09/2024.
    
    31
    + *
    
    32
    + * @author Tony Chemit - dev@tchemit.fr
    
    33
    + * @since 9.4.0
    
    34
    + */
    
    35
    +public interface AddExtraSqlScripts extends BuildStep {
    
    36
    +
    
    37
    +    default AddExtraSqlScripts addExtraSqlScripts(List<SqlScript> sqlScripts) {
    
    38
    +        sqlScripts.forEach(this::addExtraSqlScript);
    
    39
    +        return this;
    
    40
    +    }
    
    41
    +
    
    42
    +    AddExtraSqlScripts addExtraSqlScript(SqlScript sqlScript);
    
    43
    +}

  • toolkit/persistence/src/main/java/fr/ird/observe/spi/result/AddUpdateLastUpdateDateTableStep.java
    ... ... @@ -30,7 +30,7 @@ import fr.ird.observe.spi.context.DtoEntityContext;
    30 30
      * @author Tony Chemit - dev@tchemit.fr
    
    31 31
      * @since 6.0.4
    
    32 32
      */
    
    33
    -public interface AddUpdateLastUpdateDateTableStep extends BuildStep {
    
    33
    +public interface AddUpdateLastUpdateDateTableStep extends AddExtraSqlScripts {
    
    34 34
     
    
    35 35
         AddUpdateLastUpdateDateTableStep updateLastUpdateDateTable(DtoEntityContext<?, ?, ?, ?> spi);
    
    36 36
     }

  • toolkit/persistence/src/main/java/fr/ird/observe/spi/result/PersistenceResultBuilder.java
    ... ... @@ -26,6 +26,7 @@ import fr.ird.observe.entities.Entity;
    26 26
     import fr.ird.observe.entities.ToolkitTopiaPersistenceContextSupport;
    
    27 27
     import fr.ird.observe.services.service.SaveResultDto;
    
    28 28
     import fr.ird.observe.spi.context.DtoEntityContext;
    
    29
    +import io.ultreia.java4all.util.sql.SqlScript;
    
    29 30
     
    
    30 31
     import java.util.Date;
    
    31 32
     import java.util.LinkedList;
    
    ... ... @@ -41,12 +42,13 @@ import java.util.function.Supplier;
    41 42
      * @author Tony Chemit - dev@tchemit.fr
    
    42 43
      * @since 5.0.10
    
    43 44
      */
    
    44
    -public class PersistenceResultBuilder implements AddEntityToUpdateStep, AddUpdateLastUpdateDateFieldStep, AddUpdateLastUpdateDateTableStep, BuildStep {
    
    45
    +public class PersistenceResultBuilder implements AddEntityToUpdateStep, AddUpdateLastUpdateDateFieldStep, AddUpdateLastUpdateDateTableStep, AddExtraSqlScripts, BuildStep {
    
    45 46
         private final List<EntityContext<?>> updates;
    
    46 47
         private final List<EntityContext<?>> creates;
    
    47 48
         private final List<EntityContext<?>> createsReal;
    
    48 49
         private final List<EntityContext<?>> lastUpdateDateFields;
    
    49 50
         private final List<DtoEntityContext<?, ?, ?, ?>> lastUpdateDateTables;
    
    51
    +    private final List<SqlScript> extraScriptScripts;
    
    50 52
         private final ToolkitTopiaPersistenceContextSupport persistenceContext;
    
    51 53
         private final Supplier<Date> lastUpdateDateSupplier;
    
    52 54
     
    
    ... ... @@ -62,6 +64,7 @@ public class PersistenceResultBuilder implements AddEntityToUpdateStep, AddUpdat
    62 64
             this.createsReal = new LinkedList<>();
    
    63 65
             this.lastUpdateDateFields = new LinkedList<>();
    
    64 66
             this.lastUpdateDateTables = new LinkedList<>();
    
    67
    +        this.extraScriptScripts = new LinkedList<>();
    
    65 68
         }
    
    66 69
     
    
    67 70
         @Override
    
    ... ... @@ -111,6 +114,12 @@ public class PersistenceResultBuilder implements AddEntityToUpdateStep, AddUpdat
    111 114
             return this;
    
    112 115
         }
    
    113 116
     
    
    117
    +    @Override
    
    118
    +    public AddExtraSqlScripts addExtraSqlScript(SqlScript sqlScript) {
    
    119
    +        extraScriptScripts.add(Objects.requireNonNull(sqlScript));
    
    120
    +        return this;
    
    121
    +    }
    
    122
    +
    
    114 123
         @Override
    
    115 124
         public Date build() {
    
    116 125
             Date lastUpdateDate = lastUpdateDateSupplier.get();
    
    ... ... @@ -137,6 +146,7 @@ public class PersistenceResultBuilder implements AddEntityToUpdateStep, AddUpdat
    137 146
             for (DtoEntityContext<?, ?, ?, ?> spi : lastUpdateDateTables) {
    
    138 147
                 spi.updateLastUpdateDateTable(persistenceContext, lastUpdateDate);
    
    139 148
             }
    
    149
    +        extraScriptScripts.forEach(persistenceContext::executeSqlScript);
    
    140 150
             return lastUpdateDate;
    
    141 151
         }
    
    142 152
     
    

  • toolkit/templates/src/main/java/fr/ird/observe/toolkit/templates/GenerateServices.java
    ... ... @@ -24,6 +24,8 @@ package fr.ird.observe.toolkit.templates;
    24 24
     
    
    25 25
     import fr.ird.observe.toolkit.templates.services.GenerateDifferentialMetaModelClass;
    
    26 26
     import fr.ird.observe.toolkit.templates.services.GenerateDifferentialMetaModelFile;
    
    27
    +import fr.ird.observe.toolkit.templates.services.GenerateReferentialSecondLevelDeepBehaviourClass;
    
    28
    +import fr.ird.observe.toolkit.templates.services.GenerateReferentialSecondLevelDeepBehaviourFile;
    
    27 29
     import org.codehaus.plexus.component.annotations.Component;
    
    28 30
     import org.nuiton.eugene.Template;
    
    29 31
     
    
    ... ... @@ -38,7 +40,9 @@ public class GenerateServices extends DtoMetaTransformer {
    38 40
         public GenerateServices() {
    
    39 41
             setTemplateTypes(
    
    40 42
                     GenerateDifferentialMetaModelFile.class,
    
    41
    -                GenerateDifferentialMetaModelClass.class
    
    43
    +                GenerateDifferentialMetaModelClass.class,
    
    44
    +                GenerateReferentialSecondLevelDeepBehaviourFile.class,
    
    45
    +                GenerateReferentialSecondLevelDeepBehaviourClass.class
    
    42 46
             );
    
    43 47
         }
    
    44 48
     }

  • toolkit/templates/src/main/java/fr/ird/observe/toolkit/templates/ToolkitTagValues.java
    ... ... @@ -145,6 +145,19 @@ public class ToolkitTagValues extends DefaultTagValueMetadatasProvider {
    145 145
             return store.findAttributeBooleanTagValue(Store.skipCopyToEntity, clazz, attribute);
    
    146 146
         }
    
    147 147
     
    
    148
    +    /**
    
    149
    +     * Obtain the value of the {@link Store#referentialSecondLevelDeepBehaviour} tag value on the given classifier.
    
    150
    +     *
    
    151
    +     * @param store     tag-values store
    
    152
    +     * @param clazz     attribute classifier
    
    153
    +     * @return the none empty value of the found tag value or {@code null} if not found nor empty.
    
    154
    +     * @see Store#referentialSecondLevelDeepBehaviour
    
    155
    +     * @see <a href="https://gitlab.com/ultreiaio/ird-observe/-/issues/2846">issue 2846</a>
    
    156
    +     */
    
    157
    +    public boolean isReferentialSecondLevelDeepBehaviour(ObjectModelTagValuesStore store, ObjectModelClass clazz) {
    
    158
    +        return store.findClassifierBooleanTagValue(Store.referentialSecondLevelDeepBehaviour, clazz);
    
    159
    +    }
    
    160
    +
    
    148 161
         public String notSkip(String tagValue) {
    
    149 162
             return Objects.equals("skip", tagValue) ? null : tagValue;
    
    150 163
         }
    
    ... ... @@ -174,6 +187,11 @@ public class ToolkitTagValues extends DefaultTagValueMetadatasProvider {
    174 187
     
    
    175 188
             form("Pour qualifier les propriétés à générer", String.class, null, ObjectModelClassifier.class, ObjectModelPackage.class),
    
    176 189
     
    
    190
    +        /**
    
    191
    +         * @see <a href="https://gitlab.com/ultreiaio/ird-observe/-/issues/2846">issue 2846</a>
    
    192
    +         */
    
    193
    +        referentialSecondLevelDeepBehaviour("Pour qualifier le comportement à utiliser pour les référentiels lors d'une suppression, désactivation ou remplacement (false = comportement par défaut, true = pour effectuer une opération en profondeur sur les référentiels utilisés de second niveau", boolean.class, "false", ObjectModelClassifier.class),
    
    194
    +
    
    177 195
             packagePriority("Pour prioriser les paquetages", int.class, null, ObjectModelPackage.class);
    
    178 196
     
    
    179 197
             private final Set<Class<?>> targets;
    

  • toolkit/templates/src/main/java/fr/ird/observe/toolkit/templates/services/GenerateReferentialSecondLevelDeepBehaviourClass.java
    1
    +package fr.ird.observe.toolkit.templates.services;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Toolkit :: Templates
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import fr.ird.observe.services.service.referential.ReferentialSecondLevelDeepBehaviourModel;
    
    26
    +import fr.ird.observe.toolkit.templates.TemplateContract;
    
    27
    +import org.nuiton.eugene.java.ObjectModelTransformerToJava;
    
    28
    +import org.nuiton.eugene.models.object.ObjectModel;
    
    29
    +import org.nuiton.eugene.models.object.ObjectModelClass;
    
    30
    +import org.nuiton.eugene.models.object.ObjectModelJavaModifier;
    
    31
    +import org.nuiton.eugene.models.object.ObjectModelOperation;
    
    32
    +
    
    33
    +/**
    
    34
    + * Created at 30/09/2024.
    
    35
    + *
    
    36
    + * @author Tony Chemit - dev@tchemit.fr
    
    37
    + * @since 9.4.0
    
    38
    + */
    
    39
    +public class GenerateReferentialSecondLevelDeepBehaviourClass  extends ObjectModelTransformerToJava implements TemplateContract {
    
    40
    +
    
    41
    +    @Override
    
    42
    +    public void transformFromModel(ObjectModel model) {
    
    43
    +        String packageName = getDefaultPackageName().replace(".dto", ".services.service.referential");
    
    44
    +        String modelName = model.getName();
    
    45
    +        ObjectModelClass modelSupport = createClass(modelName + ReferentialSecondLevelDeepBehaviourModel.class.getSimpleName(), packageName);
    
    46
    +        setSuperClass(modelSupport, ReferentialSecondLevelDeepBehaviourModel.class);
    
    47
    +        addStaticFactory(modelSupport, modelSupport.getQualifiedName());
    
    48
    +        ObjectModelOperation constructor = addConstructor(modelSupport, ObjectModelJavaModifier.PUBLIC);
    
    49
    +        setOperationBody(constructor, ""/*{
    
    50
    +        super("<%=modelName%>");
    
    51
    +    }*/);
    
    52
    +    }
    
    53
    +
    
    54
    +}

  • toolkit/templates/src/main/java/fr/ird/observe/toolkit/templates/services/GenerateReferentialSecondLevelDeepBehaviourFile.java
    1
    +package fr.ird.observe.toolkit.templates.services;
    
    2
    +
    
    3
    +/*-
    
    4
    + * #%L
    
    5
    + * ObServe Toolkit :: Templates
    
    6
    + * %%
    
    7
    + * Copyright (C) 2008 - 2024 IRD, Ultreia.io
    
    8
    + * %%
    
    9
    + * This program is free software: you can redistribute it and/or modify
    
    10
    + * it under the terms of the GNU General Public License as
    
    11
    + * published by the Free Software Foundation, either version 3 of the
    
    12
    + * License, or (at your option) any later version.
    
    13
    + *
    
    14
    + * This program is distributed in the hope that it will be useful,
    
    15
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    16
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    17
    + * GNU General Public License for more details.
    
    18
    + *
    
    19
    + * You should have received a copy of the GNU General Public
    
    20
    + * License along with this program.  If not, see
    
    21
    + * <http://www.gnu.org/licenses/gpl-3.0.html>.
    
    22
    + * #L%
    
    23
    + */
    
    24
    +
    
    25
    +import fr.ird.observe.services.service.referential.ReferentialSecondLevelDeepBehaviourModel;
    
    26
    +import fr.ird.observe.toolkit.templates.ToolkitTagValues;
    
    27
    +import org.nuiton.eugene.models.object.ObjectModel;
    
    28
    +import org.nuiton.eugene.models.object.ObjectModelClass;
    
    29
    +import org.nuiton.eugene.models.object.ObjectModelGenerator;
    
    30
    +import org.nuiton.eugene.models.object.ObjectModelType;
    
    31
    +import org.nuiton.topia.templates.sql.TopiaMetadataModelGeneratorSupport;
    
    32
    +
    
    33
    +import java.io.File;
    
    34
    +import java.io.Writer;
    
    35
    +import java.util.Collections;
    
    36
    +import java.util.LinkedList;
    
    37
    +import java.util.List;
    
    38
    +
    
    39
    +/**
    
    40
    + * Created at 30/09/2024.
    
    41
    + *
    
    42
    + * @author Tony Chemit - dev@tchemit.fr
    
    43
    + * @since 9.4.0
    
    44
    + */
    
    45
    +public class GenerateReferentialSecondLevelDeepBehaviourFile extends ObjectModelGenerator {
    
    46
    +
    
    47
    +    @Override
    
    48
    +    public void applyTemplate(ObjectModel model, File destDir) {
    
    49
    +        this.model = model;
    
    50
    +
    
    51
    +        File realTarget = TopiaMetadataModelGeneratorSupport.getNotGeneratedResourceDirector(destDir);
    
    52
    +        String filename = getFilenameForModel(model);
    
    53
    +        generateFromElement(model, realTarget, filename, ObjectModelType.OBJECT_MODEL);
    
    54
    +    }
    
    55
    +
    
    56
    +    @Override
    
    57
    +    public String getFilenameForModel(ObjectModel model) {
    
    58
    +        return ReferentialSecondLevelDeepBehaviourModel.toLocation(super.getFilenameForModel(model));
    
    59
    +    }
    
    60
    +
    
    61
    +    @Override
    
    62
    +    protected void generateFromElement(Object element, File destDir, String filename, ObjectModelType type) {
    
    63
    +        if (ObjectModelType.OBJECT_MODEL != type) {
    
    64
    +            // only generate on model
    
    65
    +            return;
    
    66
    +        }
    
    67
    +        super.generateFromElement(element, destDir, filename, type);
    
    68
    +    }
    
    69
    +
    
    70
    +    @Override
    
    71
    +    public void generateFromModel(Writer output, ObjectModel input) {
    
    72
    +        List<String> referentialTypes = new LinkedList<>();
    
    73
    +
    
    74
    +        ToolkitTagValues tagValues = new ToolkitTagValues();
    
    75
    +        for (ObjectModelClass classifier : model.getClasses()) {
    
    76
    +            if (tagValues.isReferentialSecondLevelDeepBehaviour(model.getTagValuesStore(), classifier)) {
    
    77
    +                referentialTypes.add(classifier.getQualifiedName() + "Dto");
    
    78
    +            }
    
    79
    +        }
    
    80
    +        Collections.sort(referentialTypes);
    
    81
    +        ReferentialSecondLevelDeepBehaviourModel.newGson().toJson(referentialTypes, output);
    
    82
    +    }
    
    83
    +
    
    84
    +    @Override
    
    85
    +    protected File getDestinationFile(File destDir, String filename) {
    
    86
    +        return destDir.toPath().resolve(filename).toFile();
    
    87
    +    }
    
    88
    +}