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 <[email protected]>
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}.