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 2013/05/01 16:29:01 UTC

svn commit: r1478022 - in /sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata: MetadataTreeNode.java MetadataTreeTable.java

Author: desruisseaux
Date: Wed May  1 14:29:01 2013
New Revision: 1478022

URL: http://svn.apache.org/r1478022
Log:
Enable AbstractMetadata.toString(). Not yet fully completed.

Modified:
    sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
    sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeTable.java

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java?rev=1478022&r1=1478021&r2=1478022&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeNode.java [UTF-8] Wed May  1 14:29:01 2013
@@ -56,6 +56,26 @@ class MetadataTreeNode implements TreeTa
     private static final long serialVersionUID = -3499128444388320L;
 
     /**
+     * The collection of {@linkplain #children} to return when the node does not allow children
+     * (i.e. is a leaf). This constant is also used as a sentinel value by {@link #isLeaf()}.
+     *
+     * <p>We choose an empty set instead than an empty list because {@link MetadataTreeChildren}
+     * does not implement the {@link List} interface. So we are better to never give to the user
+     * a collection implementing {@code List} in order to signal incorrect casts sooner.</p>
+     */
+    private static final Collection<TreeTable.Node> LEAF = Collections.emptySet();
+
+    /**
+     * A sentinel value meaning that the node is known to allow {@linkplain #children}, but
+     * the children collection have not yet been created. This is different than {@code null}
+     * which means that we don't even know if the node can have children or not.
+     *
+     * <p>Any value distinct than {@link #LEAF} is okay. This value will never be visible
+     * to the user.</p>
+     */
+    private static final Collection<TreeTable.Node> PENDING = Collections.emptyList();
+
+    /**
      * The table for which this node is an element. Contains information like
      * the metadata standard and the value existence policy.
      *
@@ -77,10 +97,10 @@ class MetadataTreeNode implements TreeTa
      * The value is fetched in different ways, which depend on the {@code MetadataTreeNode} subclass:
      *
      * <ul>
-     *   <li>For {@code MetadataTreeNode} (usually the root of the tree),
-     *       this is the value to return directly.</li>
-     *   <li>For {@link Element} (a metadata property which is not a collection)
-     *       The value is {@code accessor.get(indexInData, metadata)}.</li>
+     *   <li>For {@code MetadataTreeNode} (the root of the tree),
+     *       the value is directly {@link #metadata}.</li>
+     *   <li>For {@link Element} (a metadata property which is not a collection),
+     *       the value is {@code accessor.get(indexInData, metadata)}.</li>
      *   <li>For {@link CollectionElement} (an element in a collection),
      *       an other index is used for fetching the element in that collection.</li>
      * </ul>
@@ -101,7 +121,7 @@ class MetadataTreeNode implements TreeTa
     /**
      * The children of this node, or {@code null} if not yet computed. If and only if the node
      * can not have children (i.e. {@linkplain #isLeaf() is a leaf}), then this field is set to
-     * {@link Collections#EMPTY_SET}.
+     * {@link #LEAF}.
      *
      * @see #getChildren()
      */
@@ -121,6 +141,7 @@ class MetadataTreeNode implements TreeTa
 
     /**
      * Creates a new child for an element of the given metadata.
+     * This constructor is for the {@link Element} subclass only.
      *
      * @param  parent   The parent of this node.
      * @param  metadata The metadata object for which this node will be a value.
@@ -137,18 +158,15 @@ class MetadataTreeNode implements TreeTa
      */
     String getName() {
         final Class<?> type = metadata.getClass();
-        String name = Types.getStandardName(type);
-        if (name == null) {
-            name = Classes.getShortName(type);
-        }
-        return name;
+        final String name = Types.getStandardName(type);
+        return (name != null) ? name : Classes.getShortName(type);
     }
 
     /**
      * Appends an identifier for this node in the given buffer, for {@link #toString()} implementation.
      * The default implementation is suitable only for the root node - subclasses must override.
      */
-    void identifier(final StringBuilder buffer) {
+    void appendIdentifier(final StringBuilder buffer) {
         buffer.append(Classes.getShortClassName(metadata));
     }
 
@@ -175,8 +193,7 @@ class MetadataTreeNode implements TreeTa
      * @throws UnsupportedOperationException If the metadata value is not writable.
      */
     void setUserObject(final Object value) throws UnsupportedOperationException {
-        throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableCellValue_2,
-                getValue(TableColumn.NAME), TableColumn.VALUE.getHeader()));
+        throw new UnsupportedOperationException(unmodifiableCellValue(TableColumn.VALUE));
     }
 
     /**
@@ -187,6 +204,9 @@ class MetadataTreeNode implements TreeTa
         return false;
     }
 
+
+
+
     /**
      * A node for a metadata property value. This class does not store the property value directly.
      * Instead, is stores a reference to the metadata object that contains the property values,
@@ -236,8 +256,8 @@ class MetadataTreeNode implements TreeTa
          * Appends an identifier for this node in the given buffer, for {@link #toString()} implementation.
          */
         @Override
-        void identifier(final StringBuilder buffer) {
-            super.identifier(buffer);
+        void appendIdentifier(final StringBuilder buffer) {
+            super.appendIdentifier(buffer);
             buffer.append('.').append(accessor.name(indexInData, KeyNamePolicy.JAVABEANS_PROPERTY));
         }
 
@@ -285,6 +305,9 @@ class MetadataTreeNode implements TreeTa
         }
     }
 
+
+
+
     /**
      * A node for an element in a collection. This class needs the iteration order to be stable.
      */
@@ -319,8 +342,8 @@ class MetadataTreeNode implements TreeTa
          * Appends an identifier for this node in the given buffer, for {@link #toString()} implementation.
          */
         @Override
-        void identifier(final StringBuilder buffer) {
-            super.identifier(buffer);
+        void appendIdentifier(final StringBuilder buffer) {
+            super.appendIdentifier(buffer);
             buffer.append('[').append(indexInList).append(']');
         }
 
@@ -361,6 +384,10 @@ class MetadataTreeNode implements TreeTa
         }
     }
 
+
+    // -------- Final methods (defined in terms of above methods only) ----------------------------
+
+
     /**
      * Returns the parent node, or {@code null} if this node is the root of the tree.
      */
@@ -375,7 +402,17 @@ class MetadataTreeNode implements TreeTa
      */
     @Override
     public final boolean isLeaf() {
-        return !table.standard.isMetadata(getElementType());
+        if (children == LEAF) {
+            return true;
+        }
+        if (children == null) {
+            if (!table.standard.isMetadata(getElementType())) {
+                children = LEAF;
+                return true;
+            }
+            children = PENDING;
+        }
+        return false;
     }
 
     /**
@@ -385,10 +422,10 @@ class MetadataTreeNode implements TreeTa
     @Override
     public final Collection<TreeTable.Node> getChildren() {
         /*
-         * 'children' is set to EMPTY_SET if an only if the node *can not* have children,
+         * 'children' is set to LEAF if an only if the node *can not* have children,
          * in which case we do not need to check for changes in the underlying metadata.
          */
-        if (children != Collections.EMPTY_SET) {
+        if (!isLeaf()) {
             final Object value = getUserObject();
             if (value == null) {
                 /*
@@ -396,8 +433,8 @@ class MetadataTreeNode implements TreeTa
                  * to that set, in order to allow this method to check again the next time
                  * that this method is invoked.
                  */
-                children = null; // Let GC do its work.
-                return Collections.emptySet();
+                children = PENDING; // Let GC do its work.
+                return LEAF;
             }
             /*
              * If there is a value, check if the cached collection is still applicable.
@@ -409,16 +446,10 @@ class MetadataTreeNode implements TreeTa
                 }
             }
             /*
-             * At this point, we need to create a new collection. The property accessor will
-             * be null if the value is not a metadata object, in which case we will remember
-             * that fact by setting the children collection definitively to an empty set.
+             * At this point, we need to create a new collection. The property accessor shall
+             * exist, otherwise the call to 'isLeaf()' above would have returned 'true'.
              */
-            final PropertyAccessor accessor = table.standard.getAccessor(value.getClass(), false);
-            if (accessor != null) {
-                children = new MetadataTreeChildren(this, value, accessor);
-            } else {
-                children = Collections.emptySet();
-            }
+            children = new MetadataTreeChildren(this, value, table.standard.getAccessor(value.getClass(), true));
         }
         return children;
     }
@@ -447,7 +478,9 @@ class MetadataTreeNode implements TreeTa
                 value = name = getName();
             }
         } else if (column == TableColumn.VALUE) {
-            value = getUserObject();
+            if (isLeaf()) {
+                value = getUserObject();
+            }
         } else if (column == TableColumn.TYPE) {
             value = getElementType();
         }
@@ -464,20 +497,26 @@ class MetadataTreeNode implements TreeTa
         if (column == TableColumn.VALUE) {
             setUserObject(value);
         } else if (MetadataTreeTable.COLUMNS.contains(column)) {
-            throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableCellValue_2,
-                    getValue(TableColumn.NAME), column.getHeader()));
+            throw new UnsupportedOperationException(unmodifiableCellValue(column));
         } else {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "column", column));
         }
     }
 
     /**
+     * Returns the error message for an unmodifiable cell value in the given column.
+     */
+    private String unmodifiableCellValue(final TableColumn<?> column) {
+        return Errors.format(Errors.Keys.UnmodifiableCellValue_2, getValue(TableColumn.NAME), column.getHeader());
+    }
+
+    /**
      * Returns {@code true} if the given column is {@link TableColumn#VALUE} and the property is writable,
      * or {@code false} in all other cases. This method verifies the {@code column} argument, then delegates
      * to {@link #isWritable()}.
      */
     @Override
-    public boolean isEditable(final TableColumn<?> column) {
+    public final boolean isEditable(final TableColumn<?> column) {
         ArgumentChecks.ensureNonNull("column", column);
         return (column == TableColumn.VALUE) && isWritable();
     }
@@ -498,7 +537,7 @@ class MetadataTreeNode implements TreeTa
      * in the given buffer.
      */
     final void toString(final StringBuilder buffer) {
-        identifier(buffer.append("Node["));
+        appendIdentifier(buffer.append("Node["));
         buffer.append(" : ").append(Classes.getShortName(getElementType())).append(']');
     }
 }

Modified: sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeTable.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeTable.java?rev=1478022&r1=1478021&r2=1478022&view=diff
==============================================================================
--- sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeTable.java [UTF-8] (original)
+++ sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataTreeTable.java [UTF-8] Wed May  1 14:29:01 2013
@@ -17,6 +17,7 @@
 package org.apache.sis.metadata;
 
 import java.util.List;
+import java.text.Format;
 import java.io.Serializable;
 import org.apache.sis.util.collection.TreeTable;
 import org.apache.sis.util.collection.TableColumn;
@@ -55,6 +56,12 @@ final class MetadataTreeTable implements
     });
 
     /**
+     * The {@link TreeTableFormat} to use for the {@link #toString()} method implementation.
+     * Created when first needed.
+     */
+    private static Format format;
+
+    /**
      * The root of the metadata tree.
      */
     private final Node root;
@@ -109,6 +116,13 @@ final class MetadataTreeTable implements
      */
     @Override
     public String toString() {
-        return ""; // TODO TreeTableFormat.toString(this);
+        synchronized (MetadataTreeTable.class) {
+            if (format == null) {
+                final TreeTableFormat f = new TreeTableFormat(null, null);
+                f.setColumns(TableColumn.NAME, TableColumn.VALUE);
+                format = f;
+            }
+            return format.format(this);
+        }
     }
 }