You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2017/09/09 00:12:08 UTC

svn commit: r1807850 - in /sis/branches/JDK8/core/sis-feature/src: main/java/org/apache/sis/feature/ main/java/org/apache/sis/internal/feature/ test/java/org/apache/sis/feature/

Author: desruisseaux
Date: Sat Sep  9 00:12:08 2017
New Revision: 1807850

URL: http://svn.apache.org/viewvc?rev=1807850&view=rev
Log:
Fix attribute characteristic formatting (was missing the actual values).

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -43,6 +43,7 @@ import org.apache.sis.util.logging.Loggi
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.math.MathFunctions;
@@ -98,6 +99,11 @@ public class FeatureFormat extends Tabul
     private static final long serialVersionUID = -5792086817264884947L;
 
     /**
+     * The separator to use in comma-separated lists.
+     */
+    private static final String SEPARATOR = ", ";
+
+    /**
      * An instance created when first needed and potentially shared.
      */
     private static final AtomicReference<FeatureFormat> INSTANCE = new AtomicReference<>();
@@ -350,7 +356,7 @@ public class FeatureFormat extends Tabul
             String separator = " ⇾ ";                                       // UML symbol for inheritance.
             for (final FeatureType parent : featureType.getSuperTypes()) {
                 toAppendTo.append(separator).append(toString(parent.getName()));
-                separator = ", ";
+                separator = SEPARATOR;
             }
         }
         toAppendTo.append(getLineSeparator());
@@ -463,19 +469,37 @@ public class FeatureFormat extends Tabul
                 if (!isFirstColumn) nextColumn(table);
                 isFirstColumn = false;
                 switch (column) {
+                    /*
+                     * Human-readable name of the property. May contains any characters (spaces, ideographs, etc).
+                     * In many cases, this information is not provided and the whole column is skipped.
+                     */
                     case DESIGNATION: {
                         final InternationalString d = propertyType.getDesignation();
                         if (d != null) table.append(d.toString(displayLocale));
                         break;
                     }
+                    /*
+                     * Machine-readable name of the property (identifier). This information is mandatory.
+                     * This name is usually shorter than the designation and should contain only valid
+                     * Unicode identifier characters (e.g. no spaces).
+                     */
                     case NAME: {
                         table.append(toString(propertyType.getName()));
                         break;
                     }
+                    /*
+                     * The base class or interface for all values in properties of the same type.
+                     * This is typically String, Number, Integer, Geometry or URL.
+                     */
                     case TYPE: {
                         table.append(valueType);
                         break;
                     }
+                    /*
+                     * Minimum and maximum number of occurrences allowed for this property.
+                     * If we are formatting a Feature instead than a FeatureType, then the
+                     * actual number of values is also formatted. Example: 42 ∈ [0 … ∞]
+                     */
                     case CARDINALITY: {
                         table.setCellAlignment(TableAppender.ALIGN_RIGHT);
                         if (cardinality >= 0) {
@@ -501,6 +525,12 @@ public class FeatureFormat extends Tabul
                         }
                         break;
                     }
+                    /*
+                     * If formatting a FeatureType, the default value. If formatting a Feature, the actual value.
+                     * A java.text.Format instance dedicated to the value class is used if possible. In addition
+                     * to types for which a java.text.Format may be available, we also have to check for other
+                     * special cases. If there is more than one value, they are formatted as a coma-separated list.
+                     */
                     case VALUE: {
                         table.setCellAlignment(TableAppender.ALIGN_LEFT);
                         final Format format = getFormat(valueClass);                            // Null if valueClass is null.
@@ -555,28 +585,62 @@ public class FeatureFormat extends Tabul
                                 length = formatValue(value, table.append(separator), length);
                                 buffer.setLength(0);
                                 if (length < 0) break;      // Value is too long, abandon remaining iterations.
-                                separator = ", ";
-                                length += 2;
+                                separator = SEPARATOR;
+                                length += SEPARATOR.length();
                             }
                         }
                         break;
                     }
+                    /*
+                     * Characteristics are optional information attached to some values. For example if a property
+                     * value is a temperature measurement, a characteritic of that value may be the unit of measure.
+                     * Characteristics are handled as "attributes of attributes".
+                     */
                     case CHARACTERISTICS: {
                         if (propertyType instanceof AttributeType<?>) {
+                            int length = 0;
                             String separator = "";
-                            for (final AttributeType<?> attribute : ((AttributeType<?>) propertyType).characteristics().values()) {
-                                table.append(separator).append(toString(attribute.getName()));
-                                Object c = attribute.getDefaultValue();
+format:                     for (final AttributeType<?> ct : ((AttributeType<?>) propertyType).characteristics().values()) {
+                                /*
+                                 * Format the characteristic name. We will append the value(s) later.
+                                 * We keep trace of the text length in order to stop formatting if the
+                                 * text become too long.
+                                 */
+                                final GenericName cn = ct.getName();
+                                final String cs = toString(cn);
+                                table.append(separator).append(cs);
+                                length += separator.length() + cs.length();
+                                Collection<?> cv = CollectionsExt.singletonOrEmpty(ct.getDefaultValue());
                                 if (feature != null) {
-                                    final Property p = feature.getProperty(propertyType.getName().toString());
-                                    if (p instanceof Attribute<?>) {            // Should always be true, but we are paranoiac.
-                                        c = ((Attribute<?>) p).characteristics().get(attribute.getName().toString());
+                                    /*
+                                     * Usually, the property 'cp' below is null because all features use the same
+                                     * characteristic value (for example the same unit of measurement),  which is
+                                     * given by the default value 'cv'.  Nevertheless we have to check if current
+                                     * feature overrides this characteristic.
+                                     */
+                                    final Property cp = feature.getProperty(propertyType.getName().toString());
+                                    if (cp instanceof Attribute<?>) {            // Should always be true, but we are paranoiac.
+                                        Attribute<?> ca = ((Attribute<?>) cp).characteristics().get(cn.toString());
+                                        if (ca != null) cv = ca.getValues();
                                     }
                                 }
-                                if (c != null) {
-                                    formatValue(c, table.append(" = "), 0);
+                                /*
+                                 * Now format the value, separated from the name with " = ". Example: unit = m/s
+                                 * If the value accepts multi-occurrences, we will format the value between {…}.
+                                 * We use {…} because we may have more than one characteristic in the same cell,
+                                 * so we need a way to distinguish multi-values from multi-characteristics.
+                                 */
+                                final boolean multi = ct.getMaximumOccurs() > 1;
+                                String sep = multi ? " = {" : " = ";
+                                for (Object c : cv) {
+                                    length = formatValue(c, table.append(sep), length += sep.length());
+                                    if (length < 0) break format;   // Value is too long, abandon remaining iterations.
+                                    sep = SEPARATOR;
+                                }
+                                separator = SEPARATOR;
+                                if (multi && sep == SEPARATOR) {
+                                    table.append('}');
                                 }
-                                separator = ", ";
                             }
                         }
                         break;
@@ -635,7 +699,7 @@ public class FeatureFormat extends Tabul
      *         the length exceed the maximal length (in which case the caller should break iteration).
      */
     private int formatValue(final Object value, final TableAppender table, final int length) {
-        final String text;
+        String text;
         if (value instanceof InternationalString) {
             text = ((InternationalString) value).toString(displayLocale);
         } else if (value instanceof GenericName) {
@@ -644,7 +708,7 @@ public class FeatureFormat extends Tabul
             text = toString(((IdentifiedType) value).getName());
         } else if (value instanceof IdentifiedObject) {
             text = IdentifiedObjects.getIdentifierOrName((IdentifiedObject) value);
-        } else {
+        } else if ((text = Geometries.toString(value)) == null) {
             text = value.toString();
         }
         final int remaining = MAXIMAL_VALUE_LENGTH - length;

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -26,6 +26,7 @@ import com.esri.core.geometry.Point;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.math.Vector;
+import org.apache.sis.util.Classes;
 
 
 /**
@@ -48,6 +49,14 @@ final class ESRI extends Geometries<Geom
     }
 
     /**
+     * If the given object is a JTS geometry, returns a short string representation the class name.
+     */
+    @Override
+    final String tryGetLabel(Object geometry) {
+        return (geometry instanceof Geometry) ? Classes.getShortClassName(geometry) : null;
+    }
+
+    /**
      * If the given object is an ESRI geometry and its envelope is non-empty, returns
      * that envelope as an Apache SIS implementation. Otherwise returns {@code null}.
      *

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -178,7 +178,7 @@ public abstract class Geometries<G> {
     abstract GeneralEnvelope tryGetEnvelope(Object geometry);
 
     /**
-     * If the given object is one of the recognized type and its envelope is non-empty,
+     * If the given object is one of the recognized types and its envelope is non-empty,
      * returns that envelope as an Apache SIS implementation. Otherwise returns {@code null}.
      *
      * @param  geometry  the geometry from which to get the envelope, or {@code null}.
@@ -192,6 +192,35 @@ public abstract class Geometries<G> {
         }
         return null;
     }
+
+    /**
+     * If the given geometry is the type supported by this {@code Geometries} instance,
+     * returns a short string representation the class name. Otherwise returns {@code null}.
+     */
+    abstract String tryGetLabel(Object geometry);
+
+    /**
+     * If the given object is one of the recognized types, returns a short string representation
+     * (typically the class name and the bounds). Otherwise returns {@code null}.
+     *
+     * @param  geometry  the geometry from which to get a string representation, or {@code null}.
+     * @return a short string representation of the given geometry, or {@code null} if the given
+     *         object is not a recognized geometry.
+     */
+    public static String toString(final Object geometry) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
+            String s = g.tryGetLabel(geometry);
+            if (s != null) {
+                GeneralEnvelope env = g.tryGetEnvelope(geometry);
+                if (env != null) {
+                    final String bbox = env.toString();
+                    s += bbox.substring(bbox.indexOf('('));
+                }
+                return s;
+            }
+        }
+        return null;
+    }
 
     /**
      * Creates a two-dimensional point from the given coordinate. If the CRS is geographic, then the

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.math.Vector;
+import org.apache.sis.util.Classes;
 
 
 /**
@@ -62,6 +63,14 @@ final class JTS extends Geometries<Objec
     }
 
     /**
+     * If the given object is a JTS geometry, returns a short string representation the class name.
+     */
+    @Override
+    final String tryGetLabel(Object geometry) {
+        return (rootClass.isInstance(geometry)) ? Classes.getShortClassName(geometry) : null;
+    }
+
+    /**
      * If the given object is a JTS geometry and its envelope is non-empty, returns
      * that envelope as an Apache SIS implementation. Otherwise returns {@code null}.
      *

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -26,6 +26,7 @@ import org.apache.sis.geometry.GeneralEn
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.math.Vector;
+import org.apache.sis.util.Classes;
 
 
 /**
@@ -48,6 +49,21 @@ final class Java2D extends Geometries<Sh
     }
 
     /**
+     * If the given geometry is a Java2D geometry, returns a short string representation the class name,
+     * ignoring the primitive type specialization. For example if the class is {@code Rectangle2D.Float},
+     * then this method returns {@code "Rectangle2D"}.
+     */
+    @Override
+    final String tryGetLabel(Object geometry) {
+        if (geometry instanceof Shape) {
+            Class<?> c = geometry.getClass();
+            Class<?> e = c.getEnclosingClass();
+            return Classes.getShortName(e != null ? e : c);
+        }
+        return null;
+    }
+
+    /**
      * If the given object is a Java2D geometry and its envelope is non-empty, returns
      * that envelope as an Apache SIS implementation. Otherwise returns {@code null}.
      *

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1807850&r1=1807849&r2=1807850&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] Sat Sep  9 00:12:08 2017
@@ -157,16 +157,16 @@ public final strictfp class FeatureForma
         final FeatureFormat format = create();
         final String text = format.format(feature);
         assertMultilinesEquals("World metropolis\n" +
-                "┌──────────────┬─────────────────────┬─────────────┬──────────────┬─────────────────┐\n" +
-                "│ Name         │ Type                │ Cardinality │ Value        │ Characteristics │\n" +
-                "├──────────────┼─────────────────────┼─────────────┼──────────────┼─────────────────┤\n" +
-                "│ city         │ String              │ 1 ∈ [1 … 1] │ Tokyo        │                 │\n" +
-                "│ population   │ Integer             │ 1 ∈ [1 … 1] │ 13,185,502   │                 │\n" +
-                "│ region       │ InternationalString │ 0 ∉ [1 … 1] │              │                 │\n" +
-                "│ isGlobal     │ Boolean             │ 0 ∉ [1 … 1] │              │                 │\n" +
-                "│ universities │ String              │ 2 ∈ [0 … ∞] │ Waseda, Keio │                 │\n" +
-                "│ temperature  │ Float               │ 1 ∈ [1 … 1] │ NaN          │ accuracy, units │\n" +
-                "└──────────────┴─────────────────────┴─────────────┴──────────────┴─────────────────┘\n", text);
+                "┌──────────────┬─────────────────────┬─────────────┬──────────────┬────────────────────────────┐\n" +
+                "│ Name         │ Type                │ Cardinality │ Value        │ Characteristics            │\n" +
+                "├──────────────┼─────────────────────┼─────────────┼──────────────┼────────────────────────────┤\n" +
+                "│ city         │ String              │ 1 ∈ [1 … 1] │ Tokyo        │                            │\n" +
+                "│ population   │ Integer             │ 1 ∈ [1 … 1] │ 13,185,502   │                            │\n" +
+                "│ region       │ InternationalString │ 0 ∉ [1 … 1] │              │                            │\n" +
+                "│ isGlobal     │ Boolean             │ 0 ∉ [1 … 1] │              │                            │\n" +
+                "│ universities │ String              │ 2 ∈ [0 … ∞] │ Waseda, Keio │                            │\n" +
+                "│ temperature  │ Float               │ 1 ∈ [1 … 1] │ NaN          │ accuracy = 0.1, units = °C │\n" +
+                "└──────────────┴─────────────────────┴─────────────┴──────────────┴────────────────────────────┘\n", text);
     }
 
     /**