~slub.team/goobi-production/1.8.0-mergebase

« back to all changes in this revision

Viewing changes to Kitodo/src/main/java/org/kitodo/production/forms/createprocess/ProcessFieldedMetadata.java

  • Committer: GitHub
  • Author(s): Kathrin Huber
  • Date: 2022-03-22 10:19:52 UTC
  • mfrom: (3715.3.19)
  • Revision ID: git-v1:1d5ba8396099c9eabefa7002664c694f0e525634
Merge pull request #4340 from matthias-ronge/issue-4229_2.2

Implement business logic for dependent value restrictions

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
import java.util.ArrayList;
17
17
import java.util.Collection;
18
18
import java.util.Collections;
 
19
import java.util.HashMap;
 
20
import java.util.HashSet;
19
21
import java.util.Iterator;
20
22
import java.util.List;
 
23
import java.util.Map;
 
24
import java.util.Map.Entry;
21
25
import java.util.Objects;
22
26
import java.util.Optional;
23
27
import java.util.function.BiConsumer;
 
28
import java.util.function.Function;
 
29
import java.util.stream.Collectors;
24
30
 
25
31
import org.apache.commons.collections4.list.UnmodifiableList;
26
32
import org.apache.commons.lang3.tuple.Pair;
 
33
import org.apache.logging.log4j.Level;
27
34
import org.apache.logging.log4j.LogManager;
28
35
import org.apache.logging.log4j.Logger;
29
36
import org.kitodo.api.Metadata;
170
177
     */
171
178
    private void createMetadataTable() {
172
179
        // the existing metadata is passed to the rule set, which sorts it
173
 
        List<MetadataViewWithValuesInterface> tableData = null;
 
180
        Collection<Metadata> entered = addLabels(new HashSet<>(metadata));
174
181
        if (Objects.nonNull(treeNode) && !treeNode.getChildren().isEmpty()) {
175
182
            try {
176
 
                tableData = metadataView.getSortedVisibleMetadata(
177
 
                        DataEditorService.getExistingMetadataRows(treeNode.getChildren()),
178
 
                        additionallySelectedFields);
 
183
                entered.addAll(DataEditorService.getExistingMetadataRows(treeNode.getChildren()));
179
184
            } catch (InvalidMetadataValueException e) {
180
185
                logger.error(e.getLocalizedMessage());
181
186
            }
182
 
        } else {
183
 
            tableData = metadataView
184
 
                    .getSortedVisibleMetadata(addLabels(metadata), additionallySelectedFields);
185
187
        }
 
188
        List<MetadataViewWithValuesInterface> tableData = metadataView.getSortedVisibleMetadata(entered, additionallySelectedFields);
186
189
        treeNode.getChildren().clear();
187
190
        hiddenMetadata = Collections.emptyList();
188
191
        for (MetadataViewWithValuesInterface rowData : tableData) {
193
196
                if (metadataView.isComplex()) {
194
197
                    createMetadataGroupPanel((ComplexMetadataViewInterface) metadataView, values);
195
198
                } else {
196
 
                    createMetadataEntryEdit((SimpleMetadataViewInterface) metadataView, values);
 
199
                    if (!createMetadataEntryEdit((SimpleMetadataViewInterface) metadataView, values)) {
 
200
                        /*
 
201
                         * If a conditional metadata was set automatically,
 
202
                         * start over. This is necessary to update dependent
 
203
                         * fields above or below.
 
204
                         */
 
205
                        logger.debug("Metadata was changed. Restarting.");
 
206
                        createMetadataTable();
 
207
                        break;
 
208
                    }
197
209
                }
198
210
            } else {
199
211
                hiddenMetadata = values;
292
304
     *            ruleset
293
305
     * @param values
294
306
     *            the value(s) to be displayed
 
307
     * @return whether the input field could be generated. If an automatic
 
308
     *         preset has been added to the metadata, false is returned. In that
 
309
     *         case, the rule set must be invoked again to update the options
 
310
     *         for dependent fields.
295
311
     */
296
 
    public void createMetadataEntryEdit(SimpleMetadataViewInterface simpleMetadataView,
 
312
    public boolean createMetadataEntryEdit(SimpleMetadataViewInterface simpleMetadataView,
297
313
                                                 Collection<Metadata> values) {
298
314
 
299
315
        ProcessDetail data;
304
320
                case MULTIPLE_SELECTION:
305
321
                case MULTI_LINE_SINGLE_SELECTION:
306
322
                case ONE_LINE_SINGLE_SELECTION:
307
 
                    data = new ProcessSelectMetadata(this, simpleMetadataView, simpleValues(values));
 
323
                    List<Map<MetadataEntry, Boolean>> leadingFields = getListForLeadingMetadataFields();
 
324
                    Map<String, String> options = simpleMetadataView.getSelectItems(leadingFields);
 
325
                    boolean dependent = leadingFields.parallelStream().flatMap(map -> map.entrySet().parallelStream())
 
326
                            .anyMatch(entry -> Boolean.TRUE.equals(entry.getValue()));
 
327
                    if (dependent && !options.isEmpty() && addAutoPresetForConditionalMetadata(simpleMetadataView, options, values)) {
 
328
                        return false;
 
329
                    }
 
330
                    data = new ProcessSelectMetadata(this, simpleMetadataView, simpleValues(values), dependent);
308
331
                    break;
309
332
                case BOOLEAN:
310
333
                    data = new ProcessBooleanMetadata(this, simpleMetadataView, oneValue(values, MetadataEntry.class));
322
345
            }
323
346
            new DefaultTreeNode(data, treeNode).setExpanded(true);
324
347
        } catch (IllegalStateException e) {
 
348
            logger.catching(Level.WARN, e);
325
349
            ProcessFieldedMetadata metadata = new ProcessFieldedMetadata(this, oneValue(values, MetadataGroup.class));
326
350
            metadata.treeNode = new DefaultTreeNode(metadata, treeNode);
327
351
            metadata.createUndefinedMetadataTable();
328
352
            metadata.treeNode.setExpanded(true);
329
353
        }
 
354
        return true;
 
355
    }
 
356
 
 
357
    /**
 
358
     * A value must be set for conditional metadata, as there is no no-selection
 
359
     * option. In this case, the first possible value is already displayed as
 
360
     * selected, even if it is not yet reflected in the metadata before saving.
 
361
     * In this case, no options are offered in selection fields that depend on
 
362
     * this field, because their options are based on the metadata. Therefore,
 
363
     * in this case, the metadata must be set explicitly. Then, a termination
 
364
     * must take place and the rule set must be invoked again in order to
 
365
     * correctly populate the dependent fields with options.
 
366
     * 
 
367
     * @param view
 
368
     *            view that gives the access the select items
 
369
     * @param metadataForInput
 
370
     *            list of metadata, to which a preset will be added if necessary
 
371
     * @return true, if the current tree building process must be restarted,
 
372
     *         because the metadata was changed
 
373
     */
 
374
    private boolean addAutoPresetForConditionalMetadata(SimpleMetadataViewInterface view, Map<String, String> options,
 
375
            Collection<Metadata> metadataForInput) {
 
376
 
 
377
        if (metadataForInput.isEmpty()) {
 
378
            MetadataEntry autoPreset = new MetadataEntry();
 
379
            autoPreset.setKey(view.getId());
 
380
            if (Objects.isNull(container)) {
 
381
                autoPreset.setDomain(DOMAIN_TO_MDSEC.get(view.getDomain().orElse(Domain.DESCRIPTION)));
 
382
            }
 
383
            autoPreset.setValue(options.entrySet().iterator().next().getKey());
 
384
            metadata.add(autoPreset);
 
385
 
 
386
            logger.debug("Added metadata {} to {}", autoPreset, metadataKey);
 
387
            return true;
 
388
        }
 
389
        return false;
330
390
    }
331
391
 
332
392
    /**
433
493
        return false;
434
494
    }
435
495
 
 
496
    /**
 
497
     * Returns the division.
 
498
     * @return the division
 
499
     */
 
500
    public Division<?> getDivision() {
 
501
        return division;
 
502
    }
 
503
 
436
504
    @Override
437
505
    public String getMetadataID() {
438
506
        return metadataKey;
443
511
        return "dataTable";
444
512
    }
445
513
 
 
514
    List<Map<MetadataEntry, Boolean>> getListForLeadingMetadataFields() {
 
515
        List<Map<MetadataEntry, Boolean>> result = Objects.isNull(container) ? new ArrayList<>()
 
516
                : container.getListForLeadingMetadataFields();
 
517
        Map<String, MetadataEntry> metadataEntryMap = new HashMap<>();
 
518
        treeNode.getChildren().stream().map(TreeNode::getData).filter(ProcessSimpleMetadata.class::isInstance)
 
519
                .map(ProcessSimpleMetadata.class::cast).map(ProcessDetail::getMetadataID).forEachOrdered(key -> {
 
520
                    MetadataEntry metadataEntry = new MetadataEntry();
 
521
                    metadataEntry.setKey(key);
 
522
                    metadataEntryMap.put(key, metadataEntry);
 
523
                });
 
524
        metadata.stream().filter(MetadataEntry.class::isInstance).map(MetadataEntry.class::cast)
 
525
                .forEachOrdered(key -> metadataEntryMap.put(key.getKey(), key));
 
526
        result.add(metadataEntryMap.entrySet().stream()
 
527
            .collect(Collectors.toMap(Entry::getValue, all -> Boolean.FALSE)));
 
528
        return result;
 
529
    }
 
530
 
446
531
    /**
447
532
     * Returns the metadata of a metadata group, when used recursively.
448
533
     *
525
610
        return true;
526
611
    }
527
612
 
 
613
    void markLeadingMetadataFields(List<Map<MetadataEntry, Boolean>> leadingMetadataFields) {
 
614
        int lastIndex = leadingMetadataFields.size() - 1;
 
615
        if (lastIndex > 0) {
 
616
            container.markLeadingMetadataFields(leadingMetadataFields.subList(0, lastIndex));
 
617
        }
 
618
        final List<String> leadingMetadataKeys = leadingMetadataFields.get(lastIndex).entrySet().parallelStream()
 
619
                .filter(entry -> Boolean.TRUE.equals(entry.getValue())).map(entry -> entry.getKey().getKey())
 
620
                .collect(Collectors.toList());
 
621
        treeNode.getChildren().parallelStream().map(TreeNode::getData).map(ProcessDetail.class::cast)
 
622
                .filter(processDetail -> leadingMetadataKeys.contains(processDetail.getMetadataID()))
 
623
                .forEach(ProcessDetail::setLeading);
 
624
    }
 
625
 
528
626
    /**
529
627
     * Reads the contents of the processMetadata and stores the values in the
530
628
     * appropriate place. If the line is used to edit a field of the METS