sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1427049 - in /sis/branches/JDK7: ./ sis-utility/src/main/java/org/apache/sis/internal/util/ sis-utility/src/main/java/org/apache/sis/measure/ sis-utility/src/main/java/org/apache/sis/util/ sis-utility/src/main/java/org/apache/sis/util/reso...
Date Mon, 31 Dec 2012 07:38:18 GMT
Author: desruisseaux
Date: Mon Dec 31 07:38:18 2012
New Revision: 1427049

URL: http://svn.apache.org/viewvc?rev=1427049&view=rev
Log:
Added an About class for providing information on the Apache SIS runtime environment.
The information provided in this class will be expanded in future version with things
like SIS data directory and URL to the EPSG database directory.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java   (with props)
Modified:
    sis/branches/JDK7/pom.xml
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Supervisor.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SupervisorMBean.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
    sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions.properties
    sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions_fr.properties
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Modified: sis/branches/JDK7/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/pom.xml?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/pom.xml (original)
+++ sis/branches/JDK7/pom.xml Mon Dec 31 07:38:18 2012
@@ -330,6 +330,7 @@ Apache SIS is a toolkit for describing l
             <index>false</index>
             <manifest>
               <addClasspath>true</addClasspath>
+              <mainClass>org.apache.sis.util.About</mainClass>
               <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
             </manifest>
             <manifestEntries>

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Supervisor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Supervisor.java?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Supervisor.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Supervisor.java Mon Dec 31 07:38:18 2012
@@ -32,9 +32,11 @@ import javax.management.JMException;
 import javax.management.NotCompliantMBeanException;
 import java.lang.management.ManagementFactory;
 
+import org.apache.sis.util.About;
 import org.apache.sis.util.Localized;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.collection.TreeTable;
 
 
 /**
@@ -126,22 +128,6 @@ public final class Supervisor extends St
     }
 
     /**
-     * If there is something wrong with the current Apache Supervisor status,
-     * returns descriptions of the problems. Otherwise returns {@code null}.
-     */
-    @Override
-    public List<String> warnings() {
-        final List<String> warnings = Threads.listDeadThreads();
-        if (warnings != null) {
-            final Errors resources = Errors.getResources(locale);
-            for (int i=warnings.size(); --i>=0;) {
-                warnings.set(i, resources.getString(Errors.Keys.DeadThread_1, warnings.get(i)));
-            }
-        }
-        return warnings;
-    }
-
-    /**
      * Returns the operations impact, which is {@code INFO}.
      */
     @Override
@@ -196,4 +182,31 @@ public final class Supervisor extends St
         return ResourceBundle.getBundle("org.apache.sis.internal.util.Descriptions",
                 locale, Supervisor.class.getClassLoader()).getString(resourceKey);
     }
+
+    // -----------------------------------------------------------------------
+    //               Implementation of SupervisorMBean interface
+    // -----------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TreeTable configuration() {
+        return About.configuration(locale);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> warnings() {
+        final List<String> warnings = Threads.listDeadThreads();
+        if (warnings != null) {
+            final Errors resources = Errors.getResources(locale);
+            for (int i=warnings.size(); --i>=0;) {
+                warnings.set(i, resources.getString(Errors.Keys.DeadThread_1, warnings.get(i)));
+            }
+        }
+        return warnings;
+    }
 }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SupervisorMBean.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SupervisorMBean.java?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SupervisorMBean.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SupervisorMBean.java Mon Dec 31 07:38:18 2012
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.util;
 
 import java.util.List;
+import org.apache.sis.util.collection.TreeTable;
 
 
 /**
@@ -29,6 +30,17 @@ import java.util.List;
  */
 public interface SupervisorMBean {
     /**
+     * Returns information about the current configuration.
+     * This method tries to focus on the information that are the most relevant to SIS.
+     * Those information are grouped in sections: a "Versions" section containing the
+     * Apache SIS version, Java version and operation system version; a "Classpath"
+     * section containing bootstrap, extension and user classpath, <i>etc</i>.
+     *
+     * @return Configuration information, as a tree for grouping some configuration by sections.
+     */
+    TreeTable configuration();
+
+    /**
      * If there is something wrong with the current Apache SIS status,
      * returns descriptions of the problems. Otherwise returns {@code null}.
      *

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java Mon Dec 31 07:38:18 2012
@@ -197,7 +197,7 @@ class SexagesimalConverter extends UnitC
                     if (min >= 0) deg++; else deg--;
                     min = 0;
                 } else {
-                    throw illegalField(angle, min, Vocabulary.Keys.Minutes);
+                    throw illegalField(angle, min, Vocabulary.Keys.AngularMinutes);
                 }
             }
             if (sec <= -60 || sec >= 60) { // Do not enter for NaN
@@ -205,7 +205,7 @@ class SexagesimalConverter extends UnitC
                     if (sec >= 0) min++; else min--;
                     sec = 0;
                 } else {
-                    throw illegalField(angle, sec, Vocabulary.Keys.Seconds);
+                    throw illegalField(angle, sec, Vocabulary.Keys.AngularSeconds);
                 }
             }
             return (sec/60 + min)/60 + deg;

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java?rev=1427049&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java Mon Dec 31 07:38:18 2012
@@ -0,0 +1,674 @@
+/*
+ * 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.util;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.MissingResourceException;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.io.Console;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.text.Format;
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.nio.charset.Charset;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.collection.TreeTables;
+import org.apache.sis.util.collection.DefaultTreeTable;
+
+import static java.lang.System.getProperty;
+import static org.apache.sis.util.collection.TableColumn.NAME;
+import static org.apache.sis.util.collection.TableColumn.VALUE_AS_TEXT;
+
+
+/**
+ * Provides information about the Apache SIS running environment.
+ * This class collects information from various places like {@link Version#SIS},
+ * {@link System#getProperties()}, {@link Locale#getDefault()} or {@link TimeZone#getDefault()}.
+ * This class does not collect every possible information. Instead, it tries to focus on the most
+ * important information for SIS, as determined by experience in troubleshooting.
+ * Some of those information are:
+ *
+ * <ul>
+ *   <li>Version numbers (SIS, Java, Operation system).</li>
+ *   <li>Default locale, timezone and character encoding.</li>
+ *   <li>Current directory, user home and Java home.</li>
+ *   <li>Libraries on the classpath and extension directories.</li>
+ * </ul>
+ *
+ * This class can be invoked from the command line.
+ * See the {@link #main(String[])} method for more information.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public enum About {
+    /**
+     * Information about software version numbers.
+     * This section includes:
+     *
+     * <ul>
+     *   <li>Apache SIS version</li>
+     *   <li>Java runtime version and vendor</li>
+     *   <li>Operation system name and version</li>
+     * </ul>
+     */
+    VERSIONS(Vocabulary.Keys.Versions),
+
+    /**
+     * Information about default locale, timezone and character encoding.
+     * This section includes:
+     *
+     * <ul>
+     *   <li>Default locale, completed by ISO 3-letter codes</li>
+     *   <li>Default timezone, completed by timezone offset</li>
+     *   <li>Current date and time in the default timezone</li>
+     *   <li>Default character encoding</li>
+     * </ul>
+     */
+    LOCALIZATION(Vocabulary.Keys.Localization),
+
+    /**
+     * Information about user home directory, java installation directory or other kind of data.
+     * This section includes:
+     *
+     * <ul>
+     *   <li>User directory</li>
+     *   <li>Default directory</li>
+     *   <li>Java home directory</li>
+     * </ul>
+     */
+    PATHS(Vocabulary.Keys.Paths),
+
+    /**
+     * Information about the libraries.
+     * This section includes:
+     *
+     * <ul>
+     *   <li>JAR files in the extension directories</li>
+     *   <li>JAR files and directories in the application classpath</li>
+     * </ul>
+     */
+    LIBRARIES(Vocabulary.Keys.Libraries);
+
+    /**
+     * The resource key for this section in the {@link Vocabulary} resources bundle.
+     */
+    private final int resourceKey;
+
+    /**
+     * Creates a new section to be formatted using the given resource.
+     */
+    private About(final int resourceKey) {
+        this.resourceKey = resourceKey;
+    }
+
+    /**
+     * Prints the information to the standard output stream.
+     * This method can be invoked from the command-line as below (the "{@code sis-utility}" file
+     * can be replaced by any SIS module, and its filename needs to be completed with the actual
+     * version number):
+     *
+     * {@preformat java
+     *     java -jar sis-utility.jar
+     * }
+     *
+     * By default this command prints all information except the {@link #LIBRARIES} section,
+     * which is verbose. Available options are:
+     *
+     * <ul>
+     *   <li>{@code --version}: prints only Apache SIS version number.</li>
+     *   <li>{@code --verbose}: prints all information including the libraries.</li>
+     * </ul>
+     *
+     * @param args Command-line options.
+     */
+    public static void main(final String[] args) {
+        final EnumSet<About> sections = EnumSet.allOf(About.class);
+        String configuration = null;
+        /*
+         * Command-line arguments processing.
+         */
+        if (args.length == 0) {
+            sections.remove(About.LIBRARIES);
+        } else {
+            final String arg = args[0];
+            if (arg.equals("--version")) {
+                configuration = "Apache SIS version " + Version.SIS;
+            } else if (!arg.equals("--verbose")) {
+                System.err.println(Errors.format(Errors.Keys.IllegalArgumentValue_2, 1, arg));
+                return;
+            }
+            if (args.length != 1) { // Checked only after we verified the first argument.
+                System.err.println(Errors.format(Errors.Keys.IllegalArgumentValue_2, 2, args[1]));
+                return;
+            }
+        }
+        /*
+         * Format the tree and write result to the console.
+         */
+        if (configuration == null) {
+            configuration = configuration(sections, Locale.getDefault()).toString();
+        }
+        final Console console = System.console();
+        if (console != null) {
+            final PrintWriter out = console.writer();
+            out.write(configuration);
+            out.write(System.lineSeparator());
+            out.flush();
+        } else {
+            final PrintStream out = System.out;
+            out.println(configuration);
+            out.flush();
+        }
+    }
+
+    /**
+     * Returns all known information about the current Apache SIS running environment.
+     *
+     * @param  locale The locale to use for formatting the texts in the tree.
+     * @return Configuration information, as a tree for grouping some configuration by sections.
+     */
+    public static TreeTable configuration(final Locale locale) {
+        return configuration(EnumSet.allOf(About.class), locale);
+    }
+
+    /**
+     * Returns a subset of the information about the current Apache SIS running environment.
+     *
+     * @param  sections The section for which information are desired.
+     * @param  locale The locale to use for formatting the texts in the tree.
+     * @return Configuration information, as a tree for grouping some configuration by sections.
+     */
+    public static TreeTable configuration(final Set<About> sections, final Locale locale) {
+        ArgumentChecks.ensureNonNull("sections", sections);
+        ArgumentChecks.ensureNonNull("locale", locale);
+        String userHome = null;
+        String javaHome = null;
+        final Date now = new Date();
+        final Vocabulary resources = Vocabulary.getResources(locale);
+        final DefaultTreeTable table = new DefaultTreeTable(NAME, VALUE_AS_TEXT);
+        final TreeTable.Node root = table.getRoot();
+        root.setValue(NAME, resources.getString(Vocabulary.Keys.LocalConfiguration));
+        table.setRoot(root);
+        /*
+         * Begin with the "Versions" section. The 'newSection' variable will be updated in the
+         * switch statement when new section will begin, and reset to 'null' after the 'section'
+         * variable has been updated accordingly.
+         */
+        TreeTable.Node section = null;
+        About newSection = VERSIONS;
+fill:   for (int i=0; ; i++) {
+            int      nameKey  = 0;    // The Vocabulary.Key for 'name', used only if name is null.
+            String   name     = null; // The value to put in the 'Name' column of the table.
+            Object   value    = null; // The value to put in the 'Value' column of the table.
+            String[] children = null; // Optional children to write below the node.
+            switch (i) {
+                case 0: {
+                    if (sections.contains(VERSIONS)) {
+                        name  = "Apache SIS";
+                        value = Version.SIS;
+                    }
+                    break;
+                }
+                case 1: {
+                    if (sections.contains(VERSIONS)) {
+                        name  = "Java";
+                        value = concatenate(getProperty("java.version"), getProperty("java.vendor"), true);
+                    }
+                    break;
+                }
+                case 2: {
+                    if (sections.contains(VERSIONS)) {
+                        nameKey = Vocabulary.Keys.OperatingSystem;
+                        value = concatenate(concatenate(getProperty("os.name"),
+                                getProperty("os.version"), false), getProperty("os.arch"), true);
+                    }
+                    break;
+                }
+                case 3: {
+                    newSection = LOCALIZATION;
+                    if (sections.contains(LOCALIZATION)) {
+                        final Locale current = Locale.getDefault();
+                        if (current != null) {
+                            nameKey = Vocabulary.Keys.Locale;
+                            value = current.getDisplayName(locale);
+                            final CharSequence code = concatenate(getCode(locale, false), getCode(locale, true), true);
+                            if (code != null) {
+                                children = new String[] {resources.getString(Vocabulary.Keys.Code_1, "ISO"), code.toString()};
+                            }
+                        }
+                    }
+                    break;
+                }
+                case 4: {
+                    if (sections.contains(LOCALIZATION)) {
+                        final TimeZone current = TimeZone.getDefault();
+                        if (current != null) {
+                            nameKey = Vocabulary.Keys.Timezone;
+                            final boolean inDaylightTime = current.inDaylightTime(now);
+                            value = concatenate(current.getDisplayName(inDaylightTime, TimeZone.LONG, locale), current.getID(), true);
+                            final DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
+                            df.setTimeZone(TimeZone.getTimeZone("UTC"));
+                            int offset = current.getOffset(now.getTime());
+                            StringBuffer buffer = format(df, offset, new StringBuffer("UTC "));
+                            offset -= current.getRawOffset();
+                            if (offset != 0) {
+                                buffer = format(df, offset, buffer.append(" (")
+                                        .append(resources.getString(Vocabulary.Keys.DaylightTime)).append(' ')).append(')');
+                            }
+                            children = new String[] {resources.getString(Vocabulary.Keys.Offset), buffer.toString()};
+                        }
+                    }
+                    break;
+                }
+                case 5: {
+                    if (sections.contains(LOCALIZATION)) {
+                        nameKey = Vocabulary.Keys.CurrentDateTime;
+                        value = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale).format(now);
+                    }
+                    break;
+                }
+                case 6: {
+                    if (sections.contains(LOCALIZATION)) {
+                        final Charset current = Charset.defaultCharset();
+                        if (current != null) {
+                            nameKey = Vocabulary.Keys.CharacterEncoding;
+                            value = current.displayName(locale);
+                            final Set<String> aliases = current.aliases();
+                            if (aliases != null && !aliases.isEmpty()) {
+                                final StringBuilder buffer = new StringBuilder((String) value);
+                                String separator = " (";
+                                for (final String alias : aliases) {
+                                    buffer.append(separator).append(alias);
+                                    separator = ", ";
+                                }
+                                value = buffer.append(')');
+                            }
+                        }
+                    }
+                    break;
+                }
+                case 7: {
+                    newSection = PATHS;
+                    if (sections.contains(PATHS)) {
+                        nameKey = Vocabulary.Keys.UserHome;
+                        value = userHome = getProperty("user.home");
+                    }
+                    break;
+                }
+                case 8: {
+                    if (sections.contains(PATHS)) {
+                        nameKey = Vocabulary.Keys.CurrentDirectory;
+                        value = getProperty("user.dir");
+                    }
+                    break;
+                }
+                case 9: {
+                    if (sections.contains(PATHS)) {
+                        nameKey = Vocabulary.Keys.TemporaryFiles;
+                        value = getProperty("java.io.tmpdir");
+                    }
+                    break;
+                }
+                case 10: {
+                    if (sections.contains(PATHS)) {
+                        nameKey = Vocabulary.Keys.JavaHome;
+                        value = javaHome = getProperty("java.home");
+                    }
+                    break;
+                }
+                case 11: {
+                    newSection = LIBRARIES;
+                    if (sections.contains(LIBRARIES)) {
+                        nameKey = Vocabulary.Keys.JavaExtensions;
+                        value = classpath(getProperty("java.ext.dirs"), true);
+                    }
+                    break;
+                }
+                case 12: {
+                    if (sections.contains(LIBRARIES)) {
+                        nameKey = Vocabulary.Keys.Classpath;
+                        value = classpath(getProperty("java.class.path"), false);
+                    }
+                    break;
+                }
+                default: break fill;
+            }
+            /*
+             * At this point, we have the information about one node to create.
+             * If the 'newSection' variable is non-null, then this new node shall
+             * appear in a new section.
+             */
+            if (value == null) {
+                continue;
+            }
+            if (newSection != null) {
+                section = root.newChild();
+                section.setValue(NAME, resources.getString(newSection.resourceKey));
+                newSection = null;
+            }
+            if (name == null) {
+                name = resources.getString(nameKey);
+            }
+            final TreeTable.Node node = section.newChild();
+            node.setValue(NAME, name);
+            if (children != null) {
+                for (int j=0; j<children.length; j+=2) {
+                    final String c = children[j+1];
+                    if (c != null) {
+                        final TreeTable.Node child = node.newChild();
+                        child.setValue(NAME, children[j]);
+                        child.setValue(VALUE_AS_TEXT, c);
+                    }
+                }
+            }
+            if (!(value instanceof Map<?,?>)) {
+                node.setValue(VALUE_AS_TEXT, value.toString());
+                continue;
+            }
+            /*
+             * Special case for values of kind Map<File,String>.
+             * They are extension paths or application class paths.
+             */
+            @SuppressWarnings("unchecked")
+            final Map<File,String> paths = (Map<File,String>) value;
+pathTree:   for (int j=0; ; j++) {
+                TreeTable.Node directory = null;
+                final String home;
+                final int homeKey;
+                switch (j) {
+                    case 0: home = javaHome; homeKey = Vocabulary.Keys.JavaHome; break;
+                    case 1: home = userHome; homeKey = Vocabulary.Keys.UserHome; break;
+                    case 2: home = "";       homeKey = 0; directory = node;      break;
+                    default: break pathTree;
+                }
+                if (home == null) {
+                    // Should never happen since "user.home" and "java.home" are
+                    // standard properties of the Java platform, but let be safe.
+                    continue;
+                }
+                final File homeDirectory = home.isEmpty() ? null : new File(home);
+                for (final Iterator<Map.Entry<File,String>> it=paths.entrySet().iterator(); it.hasNext();) {
+                    final Map.Entry<File,String> entry = it.next();
+                    File file = entry.getKey();
+                    if (homeDirectory != null) {
+                        file = relativize(homeDirectory, file);
+                        if (file == null) continue;
+                    }
+                    if (directory == null) {
+                        directory = node.newChild();
+                        directory.setValue(NAME, parenthesis(resources.getString(homeKey)));
+                    }
+                    CharSequence description = entry.getValue();
+                    if (description == null) {
+                        description = parenthesis(resources.getString(entry.getKey().isDirectory() ?
+                                Vocabulary.Keys.Directory : Vocabulary.Keys.Untitled).toLowerCase(locale));
+                    }
+                    TreeTables.nodeForPath(directory, NAME, file).setValue(VALUE_AS_TEXT, description);
+                    it.remove();
+                }
+                if (directory != null) {
+                    concatenateSingletons(directory, true);
+                    omitMavenRedundancy(directory);
+                }
+            }
+        }
+        TreeTables.valuesAsStrings(table, locale);
+        return table;
+    }
+
+    /**
+     * Returns a map of all JAR files or class directories found in the given paths,
+     * associated to a description obtained from their {@code META-INF/MANIFEST.MF}.
+     *
+     * @param paths The paths, separated by {@link File#pathSeparatorChar}.
+     * @param asDirectories {@code true} if the paths shall contain directories,
+     *        or {@code false} if it shall contain JAR files.
+     */
+    private static Map<File,CharSequence> classpath(final String paths, final boolean asDirectories) {
+        if (paths == null) {
+            return null;
+        }
+        final Map<File,CharSequence> files = new LinkedHashMap<>();
+        for (final CharSequence path : CharSequences.split(paths, File.pathSeparatorChar)) {
+            final File file = new File(path.toString());
+            if (file.exists()) {
+                if (!asDirectories) {
+                    files.put(file, null);
+                } else {
+                    // If we are scanning extensions, then the path are directories
+                    // rather than files. So we need to scan the directory content.
+                    final JARFilter filter = new JARFilter();
+                    final File[] list = file.listFiles(filter);
+                    if (list != null) {
+                        Arrays.sort(list);
+                        for (final File ext : list) {
+                            files.put(ext, null);
+                        }
+                    }
+                }
+            }
+        }
+        /*
+         * At this point, we have collected all JAR files.
+         * Now set the description from the MANIFEST.MF file.
+         */
+        IOException error = null;
+        for (final Map.Entry<File,CharSequence> entry : files.entrySet()) {
+            final File file = entry.getKey();
+            if (file.isFile()) {
+                CharSequence name = null;
+                try (final JarFile jar = new JarFile(file)) {
+                    final Manifest manifest = jar.getManifest();
+                    if (manifest != null) {
+                        final Attributes attributes = manifest.getMainAttributes();
+                        if (attributes != null) {
+                            name = concatenate(attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE),
+                                    attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION), false);
+                            if (name == null) {
+                                name = concatenate(attributes.getValue(Attributes.Name.SPECIFICATION_TITLE),
+                                        attributes.getValue(Attributes.Name.SPECIFICATION_VERSION), false);
+                            }
+                        }
+                    }
+                } catch (IOException e) {
+                    if (error == null) {
+                        error = e;
+                    } else {
+                        error.addSuppressed(e);
+                    }
+                    continue;
+                }
+                entry.setValue(name);
+            }
+        }
+        if (error != null) {
+            Logging.unexpectedException(About.class, "configuration", error);
+        }
+        return files;
+    }
+
+    /**
+     * If a file path in the given node or any children follow the Maven pattern, remove the
+     * artefact name and version numbers redundancies in order to make the name more compact.
+     * For example this method replaces {@code "org/opengis/geoapi/3.0.0/geoapi-3.0.0.jar"}
+     * by {@code "org/opengis/(…)/geoapi-3.0.0.jar"}.
+     */
+    private static void omitMavenRedundancy(final TreeTable.Node node) {
+        for (final TreeTable.Node child : node.getChildren()) {
+            omitMavenRedundancy(child);
+        }
+        final CharSequence name = node.getValue(NAME);
+        final int length = name.length();
+        final int s2 = CharSequences.lastIndexOf(name, File.separatorChar, 0, length);
+        if (s2 >= 0) {
+            final int s1 = CharSequences.lastIndexOf(name, File.separatorChar, 0, s2);
+            if (s1 >= 0) {
+                final int s0 = CharSequences.lastIndexOf(name, File.separatorChar, 0, s1) + 1;
+                final StringBuilder buffer = new StringBuilder(s2 - s0).append(name, s0, s2);
+                buffer.setCharAt(s1-s0, '-');
+                if (CharSequences.regionMatches(name, s2+1, buffer)) {
+                    buffer.setLength(0);
+                    node.setValue(NAME, buffer.append(name, 0, s0).append("(…)").append(name, s2, length));
+                }
+            }
+        }
+    }
+
+    /**
+     * For every branch containing only one child and no value, merges in-place that branch and the
+     * node together. This method is used for simplifying depth trees into something less verbose.
+     * However for any column other than {@code NAME}, this method preserves the values of the child
+     * node but lost all value of the parent node. For this reason, we perform the merge only if the
+     * parent has no value.
+     *
+     * <p>See the "<cite>Reduce the depth of a tree</cite>" example in {@link TreeTables}
+     * for more information.</p>
+     *
+     * @param  node The root of the node to simplify.
+     * @param  skip {@code true} for disabling concatenation of root node.
+     * @return The root of the simplified tree. May be the given {@code node} or a child.
+     */
+    private static TreeTable.Node concatenateSingletons(final TreeTable.Node node, final boolean skip) {
+        final List<TreeTable.Node> children = node.getChildren();
+        final int size = children.size();
+        for (int i=0; i<size; i++) {
+            children.set(i, concatenateSingletons(children.get(i), false));
+        }
+        if (!skip && size == 1) {
+            if (node.getValue(VALUE_AS_TEXT) == null) {
+                final TreeTable.Node child = children.remove(0);
+                final StringBuilder name = new StringBuilder(node.getValue(NAME));
+                if (!File.separator.contentEquals(name)) {
+                    name.append(File.separatorChar);
+                }
+                child.setValue(NAME, name.append(child.getValue(NAME)));
+                return child;
+            }
+        }
+        return node;
+    }
+
+    /**
+     * Concatenates the given strings in the format "main (complement)".
+     * Any of the given strings can be null.
+     *
+     * @param main        The main string to show first.
+     * @param complement  The string to show after the main one.
+     * @param parenthesis {@code true} for writing the complement between parenthesis.
+     */
+    private static CharSequence concatenate(final CharSequence main, final CharSequence complement, final boolean parenthesis) {
+        if (main != null && main.length() != 0) {
+            if (complement != null && complement.length() != 0) {
+                final StringBuilder buffer = (main instanceof StringBuilder)
+                        ? (StringBuilder) main : new StringBuilder(main);
+                buffer.append(' ');
+                if (parenthesis) buffer.append('(');
+                buffer.append(complement);
+                if (parenthesis) buffer.append(')');
+                return buffer;
+            }
+            return main;
+        }
+        return complement;
+    }
+
+    /**
+     * Returns the given text between parenthesis.
+     */
+    private static CharSequence parenthesis(final String text) {
+        return new StringBuilder(text.length() + 2).append('(').append(text).append(')');
+    }
+
+    /**
+     * Returns the ISO language or country code for the given locale.
+     */
+    private static String getCode(final Locale locale, final boolean country) {
+        try {
+            return country ? locale.getISO3Country() : locale.getISO3Language();
+        } catch (MissingResourceException e) {
+            Logging.recoverableException(About.class, "configuration", e);
+            return null;
+        }
+    }
+
+    /**
+     * Formats the given value preceded by a plus or minus sign.
+     * This method is used for formatting timezone offset.
+     *
+     * @param df     The {@link DateFormat} to use for formatting the offset.
+     * @param offset The offset to format, as a positive or negative value.
+     * @param buffer The buffer where to format the offset.
+     * @return       The given buffer, returned for convenience.
+     */
+    private static StringBuffer format(final Format df, final int offset, final StringBuffer buffer) {
+        return df.format(Math.abs(offset), buffer.append(offset < 0 ? '-' : '+').append(' '), new FieldPosition(0));
+    }
+
+    /**
+     * Filters the JAR files in an extension directory.
+     */
+    private static final class JARFilter implements FileFilter {
+        @Override public boolean accept(final File pathname) {
+            return pathname.getName().endsWith(".jar");
+        }
+    }
+
+    /**
+     * Returns the given file relative to the given root, or {@code null} if the root is not
+     * a parent of that file.
+     *
+     * @param  root The root directory (typically Java home or user home directory).
+     * @param  file The file to make relative to the root.
+     * @return The file relative to the given root, or {@code null} if none.
+     */
+    private static File relativize(final File root, final File file) {
+        File parent = file.getParentFile();
+        if (parent == null) {
+            return null;
+        }
+        if (root.equals(parent)) {
+            parent = null;
+        } else {
+            parent = relativize(root, parent);
+            if (parent == null) {
+                return null;
+            }
+        }
+        return new File(parent, file.getName());
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/About.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java Mon Dec 31 07:38:18 2012
@@ -61,7 +61,82 @@ public final class Vocabulary extends In
         /**
          * Degrees
          */
-        public static final int Degrees = 10;
+        public static final int AngularDegrees = 10;
+
+        /**
+         * Minutes
+         */
+        public static final int AngularMinutes = 11;
+
+        /**
+         * Seconds
+         */
+        public static final int AngularSeconds = 12;
+
+        /**
+         * Character encoding
+         */
+        public static final int CharacterEncoding = 17;
+
+        /**
+         * Classpath
+         */
+        public static final int Classpath = 29;
+
+        /**
+         * {0} code
+         */
+        public static final int Code_1 = 21;
+
+        /**
+         * Current date and time
+         */
+        public static final int CurrentDateTime = 25;
+
+        /**
+         * Current directory
+         */
+        public static final int CurrentDirectory = 33;
+
+        /**
+         * Daylight time
+         */
+        public static final int DaylightTime = 24;
+
+        /**
+         * Directory
+         */
+        public static final int Directory = 36;
+
+        /**
+         * Java extensions
+         */
+        public static final int JavaExtensions = 26;
+
+        /**
+         * Java home directory
+         */
+        public static final int JavaHome = 30;
+
+        /**
+         * Libraries
+         */
+        public static final int Libraries = 35;
+
+        /**
+         * Local configuration
+         */
+        public static final int LocalConfiguration = 14;
+
+        /**
+         * Locale
+         */
+        public static final int Locale = 18;
+
+        /**
+         * Localization
+         */
+        public static final int Localization = 19;
 
         /**
          * Maximum value
@@ -79,11 +154,6 @@ public final class Vocabulary extends In
         public static final int MinimumValue = 4;
 
         /**
-         * Minutes
-         */
-        public static final int Minutes = 11;
-
-        /**
          * Name
          */
         public static final int Name = 0;
@@ -99,14 +169,39 @@ public final class Vocabulary extends In
         public static final int NumberOfValues = 2;
 
         /**
+         * Offset
+         */
+        public static final int Offset = 22;
+
+        /**
+         * Operating system
+         */
+        public static final int OperatingSystem = 16;
+
+        /**
+         * Others
+         */
+        public static final int Others = 34;
+
+        /**
+         * Paths
+         */
+        public static final int Paths = 27;
+
+        /**
+         * Root
+         */
+        public static final int Root = 28;
+
+        /**
          * Root Mean Square
          */
         public static final int RootMeanSquare = 7;
 
         /**
-         * Seconds
+         * Scale
          */
-        public static final int Seconds = 12;
+        public static final int Scale = 23;
 
         /**
          * Standard deviation
@@ -114,9 +209,39 @@ public final class Vocabulary extends In
         public static final int StandardDeviation = 8;
 
         /**
+         * Temporary files
+         */
+        public static final int TemporaryFiles = 31;
+
+        /**
+         * Timezone
+         */
+        public static final int Timezone = 20;
+
+        /**
          * Type
          */
         public static final int Type = 1;
+
+        /**
+         * Untitled
+         */
+        public static final int Untitled = 37;
+
+        /**
+         * User home directory
+         */
+        public static final int UserHome = 32;
+
+        /**
+         * Value
+         */
+        public static final int Value = 13;
+
+        /**
+         * Versions
+         */
+        public static final int Versions = 15;
     }
 
     /**

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties Mon Dec 31 07:38:18 2012
@@ -14,16 +14,41 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-Angle             = Angle
-Degrees           = Degrees
-MaximumValue      = Maximum value
-MeanValue         = Mean value
-MinimumValue      = Minimum value
-Minutes           = Minutes
-Name              = Name
-NumberOfValues    = Number of values
-NumberOfNaN       = Number of \u2018NaN\u2019
-RootMeanSquare    = Root Mean Square
-Seconds           = Seconds
-StandardDeviation = Standard deviation
-Type              = Type
+Angle              = Angle
+AngularDegrees     = Degrees
+AngularMinutes     = Minutes
+AngularSeconds     = Seconds
+CharacterEncoding  = Character encoding
+Classpath          = Classpath
+Code_1             = {0} code
+CurrentDateTime    = Current date and time
+CurrentDirectory   = Current directory
+DaylightTime       = Daylight time
+Directory          = Directory
+JavaExtensions     = Java extensions
+JavaHome           = Java home directory
+Libraries          = Libraries
+LocalConfiguration = Local configuration
+Locale             = Locale
+Localization       = Localization
+MaximumValue       = Maximum value
+MeanValue          = Mean value
+MinimumValue       = Minimum value
+Name               = Name
+NumberOfValues     = Number of values
+NumberOfNaN        = Number of \u2018NaN\u2019
+Offset             = Offset
+OperatingSystem    = Operating system
+Others             = Others
+Paths              = Paths
+Root               = Root
+RootMeanSquare     = Root Mean Square
+Scale              = Scale
+StandardDeviation  = Standard deviation
+TemporaryFiles     = Temporary files
+Timezone           = Timezone
+Type               = Type
+Untitled           = Untitled
+UserHome           = User home directory
+Value              = Value
+Versions           = Versions

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties Mon Dec 31 07:38:18 2012
@@ -14,16 +14,41 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-Angle             = Angle
-Degrees           = Degr\u00e9s
-MaximumValue      = Valeur maximale
-MeanValue         = Valeur moyenne
-MinimumValue      = Valeur minimale
-Minutes           = Minutes
-Name              = Nom
-NumberOfValues    = Nombre de valeurs
-NumberOfNaN       = Nombre de \u2018NaN\u2019
-RootMeanSquare    = Moyenne quadratique
-Seconds           = Secondes
-StandardDeviation = \u00c9cart type
-Type              = Type
+Angle              = Angle
+AngularDegrees     = Degr\u00e9s
+AngularMinutes     = Minutes
+AngularSeconds     = Secondes
+CharacterEncoding  = Encodage des caract\u00e8res
+Classpath          = Chemin de classes
+Code_1             = Code {0}
+CurrentDateTime    = Date et heure courantes
+CurrentDirectory   = R\u00e9pertoire courant
+DaylightTime       = Heure normale
+Directory          = R\u00e9pertoire
+JavaExtensions     = Extensions du Java
+JavaHome           = R\u00e9pertoire du Java
+Libraries          = Biblioth\u00e8ques
+LocalConfiguration = Configuration locale
+Locale             = Locale
+Localization       = R\u00e9gionalisation
+MaximumValue       = Valeur maximale
+MeanValue          = Valeur moyenne
+MinimumValue       = Valeur minimale
+Name               = Nom
+NumberOfValues     = Nombre de valeurs
+NumberOfNaN        = Nombre de \u2018NaN\u2019
+Offset             = D\u00e9calage
+OperatingSystem    = Syst\u00e8me d'exploitation
+Others             = Autres
+Paths              = Chemins
+Root               = Racine
+RootMeanSquare     = Moyenne quadratique
+Scale              = \u00c9chelle
+StandardDeviation  = \u00c9cart type
+TemporaryFiles     = Fichiers temporaires
+Timezone           = Fuseau horaire
+Type               = Type
+Untitled           = Sans titre
+UserHome           = R\u00e9pertoire de l'utilisateur
+Value              = Valeur
+Versions           = Versions

Modified: sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions.properties?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions.properties Mon Dec 31 07:38:18 2012
@@ -1,5 +1,6 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.
-supervisor = Provides information about the state of a running Apache SIS library.
-org.apache.sis.internal.util.Supervisor = Creates a new supervisor.
-locale = The language of supervisor messages.
-warnings = List of problems detected in the running Apache SIS library. If this list contains any item, then an application reboot is strongly recommended.
+supervisor=Provides information about the state of a running Apache SIS library.
+org.apache.sis.internal.util.Supervisor=Creates a new supervisor.
+locale=The language of supervisor messages.
+configuration=Tree of information about the Apache SIS running environment.
+warnings=List of problems detected in the running Apache SIS library. If this list contains any item, then an application reboot is strongly recommended.

Modified: sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions_fr.properties?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions_fr.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/resources/org/apache/sis/internal/util/Descriptions_fr.properties Mon Dec 31 07:38:18 2012
@@ -1,5 +1,6 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.
-supervisor = Fournit des informations \u00e0 propos de l\u2019\u00e9tat d\u2019une biblioth\u00e8que Apache SIS en cours d\u2019ex\u00e9cution.
-org.apache.sis.internal.util.Supervisor = Construit un nouveau superviseur.
-locale = La langue des messages produits par le superviseur.
-warnings = Liste des probl\u00e8mes d\u00e9tect\u00e9s dans la biblioth\u00e8que Apache SIS en cours d\u2019ex\u00e9cution. Si cette liste contient des items, alors un red\u00e9marrage de l\u2019application est fortement recommand\u00e9.
+supervisor=Fournit des informations \u00e0 propos de l\u2019\u00e9tat d\u2019une biblioth\u00e8que Apache SIS en cours d\u2019ex\u00e9cution.
+org.apache.sis.internal.util.Supervisor=Construit un nouveau superviseur.
+locale=La langue des messages produits par le superviseur.
+configuration=Arborescence d'information concernant l\u2019environnement d\u2019ex\u00e9cution de Apache SIS.
+warnings=Liste des probl\u00e8mes d\u00e9tect\u00e9s dans la biblioth\u00e8que Apache SIS en cours d\u2019ex\u00e9cution. Si cette liste contient des items, alors un red\u00e9marrage de l\u2019application est fortement recommand\u00e9.

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1427049&r1=1427048&r2=1427049&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java Mon Dec 31 07:38:18 2012
@@ -57,6 +57,7 @@ import org.junit.runners.Suite;
     org.apache.sis.util.collection.DerivedMapTest.class,
     org.apache.sis.util.collection.TableColumnTest.class,
     org.apache.sis.util.collection.DefaultTreeTableTest.class,
+    org.apache.sis.util.collection.TreeTablesTest.class,
 
     // GeoAPI most basic types.
     org.apache.sis.util.iso.TypesTest.class,



Mime
View raw message