This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit d024c7dd360bcd2114dba5d2a1d879705dc11ca7 Author: Martin Desruisseaux <[email protected]> AuthorDate: Wed May 13 01:55:14 2026 +0200 In the tree representation of GeoHEIF nodes, indicate when a box is unsupported. --- .../org/apache/sis/util/resources/Vocabulary.java | 10 +++ .../sis/util/resources/Vocabulary.properties | 2 + .../sis/util/resources/Vocabulary_fr.properties | 2 + .../apache/sis/storage/geoheif/GeoHeifStore.java | 3 +- .../org/apache/sis/storage/isobmff/Extension.java | 16 +---- .../org/apache/sis/storage/isobmff/FullBox.java | 28 +++----- .../org/apache/sis/storage/isobmff/TreeNode.java | 80 ++++++++++++++++++---- .../apache/sis/storage/isobmff/base/ItemInfo.java | 11 ++- .../sis/storage/isobmff/base/ItemProperties.java | 30 +++++--- .../isobmff/base/ItemPropertyAssociation.java | 34 +++++---- .../sis/storage/isobmff/base/TrackHeader.java | 14 +--- 11 files changed, 139 insertions(+), 91 deletions(-) diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java index db82cf3935..fb6c66cbed 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java @@ -958,6 +958,11 @@ public class Vocabulary extends IndexedResourceBundle { */ public static final short Offset = 149; + /** + * Omitted + */ + public static final short Omitted = 288; + /** * Operating system */ @@ -1403,6 +1408,11 @@ public class Vocabulary extends IndexedResourceBundle { */ public static final short UnspecifiedDatumChange = 73; + /** + * Unsupported properties + */ + public static final short UnsupportedProperties = 289; + /** * Untitled */ diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties index 28348fe187..63f1c17305 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties @@ -193,6 +193,7 @@ NumberOfNaN = Number of \u2018NaN\u2019 Obligation = Obligation Offset = Offset Of_3 = {0} ({1} of {2}) +Omitted = Omitted OperatingSystem = Operating system Operations = Operations Optional = Optional @@ -282,6 +283,7 @@ Unnamed = Unnamed Unnamed_1 = Unnamed #{0} Unspecified = Unspecified UnspecifiedDatumChange = Unspecified datum change +UnsupportedProperties = Unsupported properties Untitled = Untitled UpperBound = Upper bound UserHome = User home directory diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties index d72a1e502d..acf2328f98 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties @@ -200,6 +200,7 @@ NumberOfNaN = Nombre de \u2018NaN\u2019 Obligation = Obligation Offset = D\u00e9calage Of_3 = {0} ({1} de {2}) +Omitted = Omis OperatingSystem = Syst\u00e8me d\u2019exploitation Operations = Op\u00e9rations Optional = Optionnel @@ -289,6 +290,7 @@ Unnamed = Sans nom Unnamed_1 = Sans nom \u2116{0} Unspecified = Non-sp\u00e9cifi\u00e9 UnspecifiedDatumChange = Changement de r\u00e9f\u00e9rentiel non sp\u00e9cifi\u00e9 +UnsupportedProperties = Propri\u00e9t\u00e9s non-support\u00e9es Untitled = Sans titre UpperBound = Limite haute UserHome = R\u00e9pertoire de l\u2019utilisateur diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java index 940cb4a94a..d5935cdcbb 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/geoheif/GeoHeifStore.java @@ -290,7 +290,7 @@ public class GeoHeifStore extends DataStore implements Aggregate { */ @Override public synchronized Optional<TreeTable> getNativeMetadata() throws DataStoreException { - return Optional.of(root().toTree(getDisplayName(), true)); + return Optional.of(root().toTree(getLocale(), getDisplayName(), true)); } /** @@ -325,6 +325,7 @@ public class GeoHeifStore extends DataStore implements Aggregate { * Logs a warning emitted (usually indirectly) by {@link #components()}. */ final void warning(final LogRecord record) { + record.setLoggerName("org.apache.sis.storage.geoheif"); record.setSourceClassName(GeoHeifStore.class.getCanonicalName()); record.setSourceMethodName("components"); listeners.warning(record); diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java index 811b7952b6..0bfa608149 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java @@ -18,7 +18,6 @@ package org.apache.sis.storage.isobmff; import java.util.UUID; import org.apache.sis.util.collection.TreeTable; -import org.apache.sis.util.collection.TableColumn; /** @@ -71,19 +70,10 @@ public abstract class Extension extends Box { * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { - super.appendTreeNodes(context, target, after); - if (!after) { - final UUID value = extendedType(); - if (value != null) { - final TreeTable.Node child = target.newChild(); - child.setValue(TableColumn.NAME, "extendedType"); - child.setValue(TableColumn.VALUE, value); - child.setValue(TableColumn.VALUE_AS_TEXT, value.toString()); - } - } + protected void prependTreeNodes(final Tree context, final TreeTable.Node target) { + super.prependTreeNodes(context, target); + Tree.addNode(target, "extendedType", extendedType()); } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/FullBox.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/FullBox.java index c39d78e9f0..b53d2f7cb2 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/FullBox.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/FullBox.java @@ -17,7 +17,6 @@ package org.apache.sis.storage.isobmff; import java.io.IOException; -import org.apache.sis.util.collection.TableColumn; import org.apache.sis.util.collection.TreeTable; @@ -86,26 +85,17 @@ public abstract class FullBox extends Box { * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { - super.appendTreeNodes(context, target, after); - if (!after) { - final int version = version(); - final int options = flags & ((1 << VERSION_BIT_SHIFT) - 1); - if (version != 0) { - TreeTable.Node child = target.newChild(); - child.setValue(TableColumn.NAME, "version"); - child.setValue(TableColumn.VALUE, version); - child.setValue(TableColumn.VALUE_AS_TEXT, String.valueOf(version)); - } - if (options != 0) { - TreeTable.Node child = target.newChild(); - child.setValue(TableColumn.NAME, "flags"); - child.setValue(TableColumn.VALUE, options); - child.setValue(TableColumn.VALUE_AS_TEXT, Integer.toBinaryString(options)); - } + protected void prependTreeNodes(final Tree context, final TreeTable.Node target) { + super.prependTreeNodes(context, target); + final int version = version(); + final int options = flags & ((1 << VERSION_BIT_SHIFT) - 1); + if (version != 0) { + Tree.addNode(target, "version", version, String.valueOf(version)); + } + if (options != 0) { + Tree.addNode(target, "flags", options, Integer.toBinaryString(options)); } } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java index 69dfc48703..ac16b1c35d 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java @@ -18,6 +18,7 @@ package org.apache.sis.storage.isobmff; import java.util.Map; import java.util.HashMap; +import java.util.Locale; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -29,6 +30,7 @@ import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import org.apache.sis.util.Utilities; import org.apache.sis.util.CharSequences; +import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.internal.shared.Strings; import org.apache.sis.util.collection.TreeTable; import org.apache.sis.util.collection.TableColumn; @@ -155,20 +157,21 @@ public abstract class TreeNode { } /** - * Returns a string representation of element for debugging purposes. + * Returns a string representation of this tree node for debugging purposes. * This method shows all non-static public fields, including inherited fields, in no particular order. * * @return a string representation of this element for debugging purposes. */ @Override public final String toString() { - return toTree(getClass().getSimpleName(), false).toString(); + return toTree(null, getClass().getSimpleName(), false).toString(); } /** * Returns <abbr>HEIF</abbr> boxes and their fields as a tree. * Used for showing native metadata or for debugging purposes. * + * @param locale the locale to use, or {@code null} for the default. * @param rootName name of the root node. * @param withSummary workaround, see {@link Tree#withSummary}. * @return fields contained in this node, together with child boxes. @@ -176,8 +179,8 @@ public abstract class TreeNode { * @todo It is sometime possible, through the tree cell values, to modify the content of internal arrays. * This is unsafe, we should makes this implementation safer before this module is released. */ - public final TreeTable toTree(final String rootName, final boolean withSummary) { - final var tree = new Tree(withSummary); + public final TreeTable toTree(final Locale locale, final String rootName, final boolean withSummary) { + final var tree = new Tree(locale, withSummary); final TreeTable.Node root = tree.getRoot(); root.setValue(TableColumn.NAME, rootName); tree.appendProperties(this, root); @@ -201,6 +204,11 @@ public abstract class TreeNode { */ @SuppressWarnings("serial") protected static final class Tree extends DefaultTreeTable { + /** + * The locale to use, or {@code null} for the default. + */ + protected final Locale locale; + /** * Properties saved during the creation of the tree. */ @@ -227,8 +235,9 @@ public abstract class TreeNode { /** * Creates an initially empty tree table. */ - Tree(final boolean withSummary) { + Tree(final Locale locale, final boolean withSummary) { super(TableColumn.NAME, TableColumn.VALUE, TableColumn.VALUE_AS_TEXT); + this.locale = locale; properties = new HashMap<>(); names = new HashMap<>(); this.withSummary = withSummary; @@ -279,7 +288,7 @@ public abstract class TreeNode { */ private String appendProperties(final TreeNode source, final TreeTable.Node target) { String summary = null; - source.appendTreeNodes(this, target, false); + source.prependTreeNodes(this, target); for (final Field field : source.getClass().getFields()) { if (Modifier.isStatic(field.getModifiers())) { continue; @@ -358,20 +367,67 @@ public abstract class TreeNode { child.setValue(TableColumn.VALUE_AS_TEXT, Utilities.deepToString(value)); } } - source.appendTreeNodes(this, target, true); + source.appendTreeNodes(this, target); return summary; } + + /** + * Convenience method for adding a child node. + * + * @param target where to add the node. + * @param name the programmatic (camel-case) name of the node. + * @param value value of the node, or {@code null} if none. + */ + public static void addNode(final TreeTable.Node target, final String name, final Object value) { + if (value != null) { + addNode(target, name, value, value.toString()); + } + } + + /** + * Convenience method for adding a child node. + * + * @param target where to add the node. + * @param name the programmatic (camel-case) name of the node. + * @param value value of the node. Should not be null. + * @param valueAsText string representation of the value. + */ + public static void addNode(final TreeTable.Node target, String name, Object value, String valueAsText) { + TreeTable.Node child = target.newChild(); + child.setValue(TableColumn.NAME, CharSequences.camelCaseToWords(name, true).toString()); + child.setValue(TableColumn.VALUE, value); + child.setValue(TableColumn.VALUE_AS_TEXT, valueAsText); + } + } + + /** + * Inserts custom properties before the properties inferred from the public fields. + * This method is invoked automatically by {@link #toTree toTree(…)} for generating + * the first nodes, before the nodes inferred by reflection. + * + * @param context the tree being formatted. Can be used for fetching contextual information. + * @param target the node where to add properties. + */ + protected void prependTreeNodes(Tree context, TreeTable.Node target) { } /** - * Appends properties other than the ones defined by public fields. - * This method is invoked automatically by {@link #toTree toTree(…)} - * for generating the first or last nodes, before or after the nodes inferred by reflection. + * Appends custom properties after the properties inferred from the public fields. + * This method is invoked automatically by {@link #toTree toTree(…)} for generating + * the last nodes, after the nodes inferred by reflection. + * + * <p>The default implementation adds an artificial node saying that some nodes are missing + * if the class is annotated with {@link Incomplete}.</p> * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ - protected void appendTreeNodes(Tree context, TreeTable.Node target, boolean after) { + protected void appendTreeNodes(Tree context, TreeTable.Node target) { + if (getClass().isAnnotationPresent(Incomplete.class)) { + final Vocabulary vocabulary = Vocabulary.forLocale(context.locale); + final TreeTable.Node child = target.newChild(); + child.setValue(TableColumn.NAME, vocabulary.getString(Vocabulary.Keys.UnsupportedProperties)); + child.setValue(TableColumn.VALUE, vocabulary.getString(Vocabulary.Keys.Omitted)); + } } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfo.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfo.java index ac7531c79f..c6743d82e7 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfo.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemInfo.java @@ -99,15 +99,12 @@ public final class ItemInfo extends FullBox { * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { - super.appendTreeNodes(context, target, after); - if (!after) { - for (ItemInfoEntry entry : entries) { - context.names.put(entry.itemID, entry); // In case of conflict, keep the most recent item. - } + protected void prependTreeNodes(final Tree context, final TreeTable.Node target) { + super.prependTreeNodes(context, target); + for (ItemInfoEntry entry : entries) { + context.names.put(entry.itemID, entry); // In case of conflict, keep the most recent item. } } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemProperties.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemProperties.java index f2367e81c1..c0fc1aea60 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemProperties.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemProperties.java @@ -86,10 +86,11 @@ public final class ItemProperties extends ContainerBox { /** * Creates an initially empty list of boxes. + * Parameter {@code itemID} is defined for using this constructor as a lambda function. * * @param itemID identifier of the item for which properties are collected. */ - private ForID(final Integer itemID) { + private ForID(@SuppressWarnings("unused") final Integer itemID) { essentials = new BitSet(); } @@ -188,20 +189,29 @@ public final class ItemProperties extends ContainerBox { * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { + protected void prependTreeNodes(final Tree context, final TreeTable.Node target) { Box[] properties = null; - if (!after) { - for (final Box box : children) { - if (box.type() == ItemPropertyContainer.BOXTYPE) { - properties = ((ItemPropertyContainer) box).children; - break; - } + for (final Box box : children) { + if (box.type() == ItemPropertyContainer.BOXTYPE) { + properties = ((ItemPropertyContainer) box).children; + break; } } context.setContext(Box[].class, properties); - super.appendTreeNodes(context, target, after); + super.prependTreeNodes(context, target); + } + + /** + * Clears the context after formatting. + * + * @param context the tree being formatted. + * @param target the node where to add properties. + */ + @Override + protected void appendTreeNodes(final Tree context, final TreeTable.Node target) { + super.appendTreeNodes(context, target); + context.setContext(Box[].class, null); } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemPropertyAssociation.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemPropertyAssociation.java index 6031916b1c..61aebca46c 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemPropertyAssociation.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/ItemPropertyAssociation.java @@ -131,27 +131,25 @@ public final class ItemPropertyAssociation extends FullBox { * @see ItemProperties#collect(Map) */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { - super.appendTreeNodes(context, target, after); - if (after) { - final Box[] properties = context.getContext(Box[].class); - final TreeTable.Node indexes = target.newChild(); - indexes.setValue(TableColumn.NAME, "property index"); - for (int i : propertyIndex) { - int index = i & Short.MAX_VALUE; - String name = String.valueOf(index); - if (i < 0) name += " (essential)"; - TreeTable.Node child = indexes.newChild(); - child.setValue(TableColumn.NAME, name); - child.setValue(TableColumn.VALUE, i); - if (properties != null && --index >= 0 && index < properties.length) { - final Box property = properties[index]; - if (property != null) { - child.setValue(TableColumn.VALUE_AS_TEXT, property.typeName()); - } + protected void appendTreeNodes(final Tree context, final TreeTable.Node target) { + final Box[] properties = context.getContext(Box[].class); + final TreeTable.Node indexes = target.newChild(); + indexes.setValue(TableColumn.NAME, "property index"); + for (int i : propertyIndex) { + int index = i & Short.MAX_VALUE; + String name = String.valueOf(index); + if (i < 0) name += " (essential)"; + TreeTable.Node child = indexes.newChild(); + child.setValue(TableColumn.NAME, name); + child.setValue(TableColumn.VALUE, i); + if (properties != null && --index >= 0 && index < properties.length) { + final Box property = properties[index]; + if (property != null) { + child.setValue(TableColumn.VALUE_AS_TEXT, property.typeName()); } } } + super.appendTreeNodes(context, target); } } diff --git a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/TrackHeader.java b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/TrackHeader.java index 7613a78025..8232d2d177 100644 --- a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/TrackHeader.java +++ b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/base/TrackHeader.java @@ -22,7 +22,6 @@ import org.apache.sis.io.stream.ChannelDataInput; import org.apache.sis.storage.DataStoreContentException; import org.apache.sis.storage.isobmff.Reader; import org.apache.sis.storage.isobmff.Incomplete; -import org.apache.sis.util.collection.TableColumn; import org.apache.sis.util.collection.TreeTable; @@ -109,17 +108,10 @@ public final class TrackHeader extends HeaderBox { * * @param context the tree being formatted. Can be used for fetching contextual information. * @param target the node where to add properties. - * @param after {@code false} for the first nodes, or {@code true} for the last nodes. */ @Override - protected void appendTreeNodes(final Tree context, final TreeTable.Node target, final boolean after) { - super.appendTreeNodes(context, target, after); - if (!after) { - final boolean enabled = isEnabled(); - TreeTable.Node child = target.newChild(); - child.setValue(TableColumn.NAME, "enabled"); - child.setValue(TableColumn.VALUE, enabled); - child.setValue(TableColumn.VALUE_AS_TEXT, String.valueOf(enabled)); - } + protected void prependTreeNodes(final Tree context, final TreeTable.Node target) { + super.prependTreeNodes(context, target); + Tree.addNode(target, "enabled", isEnabled()); } }
