This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new ff9dc10dcb Complete `MetadataBuilder.useParentElements()`.
ff9dc10dcb is described below

commit ff9dc10dcb5e79287940f48211b91df954223dfe
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Dec 8 18:20:58 2023 +0100

    Complete `MetadataBuilder.useParentElements()`.
---
 .../apache/sis/storage/base/MetadataBuilder.java   | 94 ++++++++++++++++------
 .../main/org/apache/sis/pending/jdk/JDK21.java     | 62 ++++++++++++++
 .../apache/sis/util/internal/CollectionsExt.java   | 16 ----
 3 files changed, 131 insertions(+), 41 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
index 9236535864..e43960eec0 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
@@ -92,6 +92,7 @@ import org.apache.sis.storage.internal.Resources;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.pending.jdk.JDK21;
 import org.apache.sis.measure.Units;
 import static 
org.apache.sis.util.internal.StandardDateFormat.MILLISECONDS_PER_DAY;
 
@@ -172,6 +173,18 @@ public class MetadataBuilder {
     public MetadataBuilder() {
     }
 
+    /**
+     * Creates a new metadata builder for completing an existing metadata.
+     * The given metadata shall may be modifiable. When a metadata element 
accepts many instances,
+     * the instance which will be modified is the last one.
+     *
+     * @param  edit  the metadata to modify, or {@code null} if none.
+     */
+    public MetadataBuilder(final Metadata edit) {
+        metadata = DefaultMetadata.castOrCopy(edit);
+        useParentElements();
+    }
+
     /**
      * The metadata created by this builder, or {@code null} if not yet 
created.
      */
@@ -3323,25 +3336,34 @@ parse:      for (int i = 0; i < length;) {
     public boolean mergeMetadata(final Object source, final Locale locale) {
         flush();
         final ModifiableMetadata target;
+        /*
+         * In the following `instanceof` checks, objects closer to root should 
be tested first.
+         * For example, we should finish the checks of all `Metadata` elements 
before to check
+         * if the object is a sub-element of a `Metadata` element. This 
ordering is because an
+         * implementation may implement many interfaces: the main element 
together with some of
+         * its sub-elements. We want to use the object with most information. 
Furthermore, the
+         * main object may not use a type (e.g. `Citation`) for the same 
sub-element than what
+         * the code below assumes.
+         */
              if (source instanceof Metadata)                    target = 
metadata();
         else if (source instanceof DataIdentification)          target = 
identification();
+        else if (source instanceof GridSpatialRepresentation)   target = 
gridRepresentation();
+        else if (source instanceof CoverageDescription)         target = 
coverageDescription();
+        else if (source instanceof FeatureCatalogueDescription) target = 
featureDescription();
+        else if (source instanceof AcquisitionInformation)      target = 
acquisition();
+        else if (source instanceof Lineage)                     target = 
lineage();
+        else if (source instanceof Distribution)                target = 
distribution();
         else if (source instanceof Citation)                    target = 
citation();
+        else if (source instanceof Extent)                      target = 
extent();
+        else if (source instanceof LegalConstraints)            target = 
constraints();
         else if (source instanceof Series)                      target = 
series();
         else if (source instanceof Responsibility)              target = 
responsibility();
         else if (source instanceof Party)                       target = 
party();
-        else if (source instanceof LegalConstraints)            target = 
constraints();
-        else if (source instanceof Extent)                      target = 
extent();
-        else if (source instanceof AcquisitionInformation)      target = 
acquisition();
-        else if (source instanceof Platform)                    target = 
platform();
-        else if (source instanceof FeatureCatalogueDescription) target = 
featureDescription();
-        else if (source instanceof CoverageDescription)         target = 
coverageDescription();
         else if (source instanceof AttributeGroup)              target = 
attributeGroup();
         else if (source instanceof SampleDimension)             target = 
sampleDimension();
-        else if (source instanceof GridSpatialRepresentation)   target = 
gridRepresentation();
         else if (source instanceof GCPCollection)               target = 
groundControlPoints();
-        else if (source instanceof Distribution)                target = 
distribution();
         else if (source instanceof Format)                      target = 
format();
-        else if (source instanceof Lineage)                     target = 
lineage();
+        else if (source instanceof Platform)                    target = 
platform();
         else if (source instanceof ProcessStep)                 target = 
processStep();
         else if (source instanceof Processing)                  target = 
processing();
         else return false;
@@ -3356,28 +3378,43 @@ parse:      for (int i = 0; i < length;) {
      * This is used for continuing the edition of an existing metadata.
      */
     private void useParentElements() {
-        if (identification == null) identification = last 
(DefaultDataIdentification.class,     metadata,       
Metadata::getIdentificationInfo);
-        if (citation       == null) citation       = 
fetch(DefaultCitation.class,               identification, 
Identification::getCitation);
-        if (responsibility == null) responsibility = last 
(DefaultResponsibility.class,         citation,       
Citation::getCitedResponsibleParties);
-        if (party          == null) party          = last 
(AbstractParty.class,                 responsibility, 
Responsibility::getParties);
-        if (constraints    == null) constraints    = last 
(DefaultLegalConstraints.class,       identification, 
Identification::getResourceConstraints);
-        if (extent         == null) extent         = last 
(DefaultExtent.class,                 identification, 
Identification::getExtents);
-        if (acquisition    == null) acquisition    = last 
(DefaultAcquisitionInformation.class, metadata,       
Metadata::getAcquisitionInformation);
-        if (platform       == null) platform       = last 
(DefaultPlatform.class,               acquisition,    
AcquisitionInformation::getPlatforms);
+        if (identification      == null) identification      = last 
(DefaultDataIdentification.class,          metadata,            
DefaultMetadata::getIdentificationInfo);
+        if (gridRepresentation  == null) gridRepresentation  = last 
(DefaultGridSpatialRepresentation.class,   metadata,            
DefaultMetadata::getSpatialRepresentationInfo);
+        if (coverageDescription == null) coverageDescription = last 
(DefaultCoverageDescription.class,         metadata,            
DefaultMetadata::getContentInfo);
+        if (featureDescription  == null) featureDescription  = last 
(DefaultFeatureCatalogueDescription.class, metadata,            
DefaultMetadata::getContentInfo);
+        if (acquisition         == null) acquisition         = last 
(DefaultAcquisitionInformation.class,      metadata,            
DefaultMetadata::getAcquisitionInformation);
+        if (lineage             == null) lineage             = last 
(DefaultLineage.class,                     metadata,            
DefaultMetadata::getResourceLineages);
+        if (distribution        == null) distribution        = last 
(DefaultDistribution.class,                metadata,            
DefaultMetadata::getDistributionInfo);
+        if (citation            == null) citation            = 
fetch(DefaultCitation.class,                    identification,      
AbstractIdentification::getCitation);
+        if (extent              == null) extent              = last 
(DefaultExtent.class,                      identification,      
AbstractIdentification::getExtents);
+        if (constraints         == null) constraints         = last 
(DefaultLegalConstraints.class,            identification,      
AbstractIdentification::getResourceConstraints);
+        if (responsibility      == null) responsibility      = last 
(DefaultResponsibility.class,              citation,            
DefaultCitation::getCitedResponsibleParties);
+        if (party               == null) party               = last 
(AbstractParty.class,                      responsibility,      
DefaultResponsibility::getParties);
+        if (attributeGroup      == null) attributeGroup      = last 
(DefaultAttributeGroup.class,              coverageDescription, 
DefaultCoverageDescription::getAttributeGroups);
+        if (sampleDimension     == null) sampleDimension     = last 
(DefaultSampleDimension.class,             attributeGroup,      
DefaultAttributeGroup::getAttributes);
+        if (format              == null) format              = last 
(DefaultFormat.class,                      distribution,        
DefaultDistribution::getDistributionFormats);
+        if (platform            == null) platform            = last 
(DefaultPlatform.class,                    acquisition,         
DefaultAcquisitionInformation::getPlatforms);
+        if (processStep         == null) processStep         = last 
(DefaultProcessStep.class,                 lineage,             
DefaultLineage::getProcessSteps);
+        if (processing          == null) processing          = 
fetch(DefaultProcessing.class,                  processStep,         
DefaultProcessStep::getProcessingInformation);
     }
 
     /**
      * Returns the element of the given source metadata if it is of the 
desired class.
      * This method is equivalent to {@link #last(Class, Object, Function)} but 
for a singleton.
      *
-     * @param  target  the desired class.
+     * @param  <S>     the type of the source metadata.
+     * @param  <E>     the type of metadata element provided by the source.
+     * @param  <T>     the type of the desired metadata element.
+     * @param  target  the type of the desired metadata element.
      * @param  source  the source metadata, or {@code null} if none.
      * @param  getter  the getter to use for fetching elements from the source 
metadata.
      * @return the metadata element from the source, or {@code null} if none.
      */
-    private static <S,T> T fetch(final Class<T> target, final S source, final 
Function<S,?> getter) {
+    private static <S extends ISOMetadata, E, T extends E> T fetch(final 
Class<T> target, final S source,
+            final Function<S,E> getter)
+    {
         if (source != null) {
-            final Object last = getter.apply(source);
+            final E last = getter.apply(source);
             if (target.isInstance(last)) {
                 return target.cast(last);
             }
@@ -3389,16 +3426,23 @@ parse:      for (int i = 0; i < length;) {
      * Returns the element of the given source metadata if it is of the 
desired class.
      * This method is equivalent to {@link #fetch(Class, Object, Function)} 
but for a collection.
      *
-     * @param  target  the desired class.
+     * @param  <S>     the type of the source metadata.
+     * @param  <E>     the type of metadata element provided by the source.
+     * @param  <T>     the type of the desired metadata element.
+     * @param  target  the type of the desired metadata element.
      * @param  source  the source metadata, or {@code null} if none.
      * @param  getter  the getter to use for fetching elements from the source 
metadata.
      * @return the metadata element from the source, or {@code null} if none.
      */
-    private static <S,T> T last(final Class<T> target, final S source, final 
Function<S,Collection<?>> getter) {
+    private static <S extends ISOMetadata, E, T extends E> T last(final 
Class<T> target, final S source,
+            final Function<S,Collection<E>> getter)
+    {
         if (source != null) {
-            final Object last = CollectionsExt.last(getter.apply(source));
-            if (target.isInstance(last)) {
-                return target.cast(last);
+            // If not a sequenced collection, the iteration may be in any 
order.
+            for (final E last : JDK21.reversed(getter.apply(source))) {
+                if (target.isInstance(last)) {
+                    return target.cast(last);
+                }
             }
         }
         return null;
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/jdk/JDK21.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/jdk/JDK21.java
new file mode 100644
index 0000000000..33580297b4
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/jdk/JDK21.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.pending.jdk;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+
+/**
+ * Place holder for some functionalities defined in a JDK more recent than 
Java 11.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public final class JDK21 {
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private JDK21() {
+    }
+
+    /**
+     * Placeholder for {@code SequencedCollection.reversed()}.
+     *
+     * @param  <E>        type of elements in the collection.
+     * @param  sequenced  the sequenced collection for which to get elements 
in reverse order.
+     * @return elements of the given collection in reverse order.
+     */
+    public static <E> Iterable<E> reversed(final Collection<E> sequenced) {
+        final List<E> list;
+        if (sequenced instanceof List<?>) {
+            list = (List<E>) sequenced;
+        } else {
+            list = new ArrayList<>(sequenced);
+        }
+        return new Iterable<>() {
+            @Override public Iterator<E> iterator() {
+                final ListIterator<E> it = list.listIterator(list.size());
+                return new Iterator<E>() {
+                    @Override public boolean hasNext() {return 
it.hasPrevious();}
+                    @Override public E       next()    {return it.previous();}
+                };
+            }
+        };
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/CollectionsExt.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/CollectionsExt.java
index e43ae7e5d2..d24b297d2e 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/CollectionsExt.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/CollectionsExt.java
@@ -139,22 +139,6 @@ public final class CollectionsExt extends Static {
         return null;
     }
 
-    /**
-     * Returns the last element of the given iterable if it is a list, or an 
arbitrary element otherwise.
-     *
-     * @todo Check for sequenced collection in JDK21.
-     *
-     * @param  <T>         the type of elements contained in the iterable.
-     * @param  collection  the iterable from which to get the last element, or 
{@code null}.
-     * @return the last element, or {@code null} if the given iterable is null 
or empty.
-     */
-    public static <T> T last(final Collection<T> collection) {
-        if (collection instanceof List<?> && !collection.isEmpty()) {
-            return ((List<T>) collection).get(collection.size() - 1);
-        }
-        return null;
-    }
-
     /**
      * If the given iterable contains exactly one non-null element, returns 
that element.
      * Otherwise returns {@code null}.

Reply via email to