sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1766833 [1/2] - in /sis/branches/JDK7: ./ core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/ core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ core/sis-utility/src/main/java/org/apache/sis/i...
Date Thu, 27 Oct 2016 14:15:19 GMT
Author: desruisseaux
Date: Thu Oct 27 14:15:18 2016
New Revision: 1766833

URL: http://svn.apache.org/viewvc?rev=1766833&view=rev
Log:
Merge JSR-363 work from the JDK8 branch.

Added:
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
      - copied, changed from r1766829, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java
    sis/branches/JDK7/core/sis-utility/src/main/resources/META-INF/services/javax.measure.spi.ServiceProvider
      - copied unchanged from r1766829, sis/branches/JDK8/core/sis-utility/src/main/resources/META-INF/services/javax.measure.spi.ServiceProvider
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java
      - copied unchanged from r1766829, sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/UnitServicesTest.java
Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/Measure.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
    sis/branches/JDK7/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames.properties
    sis/branches/JDK7/core/sis-utility/src/main/resources/org/apache/sis/measure/UnitNames_fr.properties
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/MeasureTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/ConventionalUnitTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/LinearConverterTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
    sis/branches/JDK7/ide-project/NetBeans/build.xml

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct 27 14:15:18 2016
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1766500
+/sis/branches/JDK8:1584960-1766829
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -548,7 +548,7 @@ public class BursaWolfParameters extends
          * elements should have the same value, but we tolerate slight deviation
          * (this will be verified later).
          */
-        final DoubleDouble S = new DoubleDouble(getNumber(matrix, 0,0));
+        final DoubleDouble S = DoubleDouble.castOrCopy(getNumber(matrix, 0,0));
         S.add(getNumber(matrix, 1,1));
         S.add(getNumber(matrix, 2,2));
         S.divide(3, 0);

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -92,7 +92,7 @@ public final strictfp class NTv2Test ext
      * because Apache SIS does not redistribute the {@code "NTF_R93.gsb"}. But developers can invoke this method
      * explicitely if they can provide a path to the {@code "NTF_R93.gsb"} file.
      *
-     * @param  file Path to the official {@code "NTF_R93.gsb"} file.
+     * @param  file  path to the official {@code "NTF_R93.gsb"} file.
      * @throws IOException if an error occurred while loading the grid.
      * @throws FactoryException if an error occurred while computing the grid.
      * @throws TransformException if an error occurred while computing the envelope or testing the point.
@@ -104,10 +104,10 @@ public final strictfp class NTv2Test ext
     /**
      * Implementation of {@link #testLoader()} and {@link #testRGF93(Path)}.
      *
-     * @param xmin Negative of value of {@code "W_LONG"} record.
-     * @param xmax Negative of value of {@code "E_LONG"} record.
-     * @param ymin Value of the {@code "S_LAT"} record.
-     * @param ymax Value of the {@code "N_LAT"} record.
+     * @param  xmin  negative of value of {@code "W_LONG"} record.
+     * @param  xmax  negative of value of {@code "E_LONG"} record.
+     * @param  ymin  value of the {@code "S_LAT"} record.
+     * @param  ymax  value of the {@code "N_LAT"} record.
      */
     private static void testRGF93(final Path file, final double xmin, final double xmax,
             final double ymin, final double ymax) throws IOException, FactoryException, TransformException
@@ -198,12 +198,12 @@ public final strictfp class NTv2Test ext
      * is rounding errors. This is usually the case when using the {@code "SECONDS"} unit of measurement.
      * This assumption does not apply to the shift values.
      *
-     * @param grid  The full grid from which to extract a few values.
-     * @param out   Where to write the test file.
-     * @param gridX Index along the longitude axis of the first cell to write.
-     * @param gridY Index along the latitude axis of the first cell to write.
-     * @param nx    Number of cells to write along the longitude axis.
-     * @param ny    Number of cells to write along the latitude axis.
+     * @param  grid   the full grid from which to extract a few values.
+     * @param  out    where to write the test file.
+     * @param  gridX  index along the longitude axis of the first cell to write.
+     * @param  gridY  index along the latitude axis of the first cell to write.
+     * @param  nx     number of cells to write along the longitude axis.
+     * @param  ny     number of cells to write along the latitude axis.
      * @throws TransformException if an error occurred while computing the envelope.
      * @throws IOException if an error occurred while writing the test file.
      */
@@ -219,12 +219,12 @@ public final strictfp class NTv2Test ext
         writeString(buffer, "NUM_FILE"); buffer.putInt(1); nextRecord(buffer);
         writeString(buffer, "GS_TYPE");  writeString(buffer, "SECONDS");
         writeString(buffer, "VERSION");  writeString(buffer, "SIS_TEST");   // Last overview record.
-        writeString(buffer, "S_LAT");    buffer.putDouble(Math.rint( envelope.getMinimum(1)));
-        writeString(buffer, "N_LAT");    buffer.putDouble(Math.rint( envelope.getMaximum(1)));
-        writeString(buffer, "E_LONG");   buffer.putDouble(Math.rint(-envelope.getMaximum(0)));  // Sign reversed.
-        writeString(buffer, "W_LONG");   buffer.putDouble(Math.rint(-envelope.getMinimum(0)));
-        writeString(buffer, "LAT_INC");  buffer.putDouble(Math.rint( envelope.getSpan(1) / (ny - 1)));
-        writeString(buffer, "LONG_INC"); buffer.putDouble(Math.rint( envelope.getSpan(0) / (nx - 1)));
+        writeString(buffer, "S_LAT");    buffer.putDouble(StrictMath.rint( envelope.getMinimum(1)));
+        writeString(buffer, "N_LAT");    buffer.putDouble(StrictMath.rint( envelope.getMaximum(1)));
+        writeString(buffer, "E_LONG");   buffer.putDouble(StrictMath.rint(-envelope.getMaximum(0)));  // Sign reversed.
+        writeString(buffer, "W_LONG");   buffer.putDouble(StrictMath.rint(-envelope.getMinimum(0)));
+        writeString(buffer, "LAT_INC");  buffer.putDouble(StrictMath.rint( envelope.getSpan(1) / (ny - 1)));
+        writeString(buffer, "LONG_INC"); buffer.putDouble(StrictMath.rint( envelope.getSpan(0) / (nx - 1)));
         writeString(buffer, "GS_COUNT"); buffer.putInt(nx * ny); nextRecord(buffer);
         for (int y=0; y<ny; y++) {
             for (int x=0; x<nx; x++) {

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -201,14 +201,14 @@ public final class Context extends Marsh
      *     }
      * }
      *
-     * @param  bitMasks        A combination of {@link #MARSHALLING}, {@code SUBSTITUTE_*} or other bit masks.
-     * @param  locale          The locale, or {@code null} if unspecified.
-     * @param  timezone        The timezone, or {@code null} if unspecified.
-     * @param  schemas         The schemas root URL, or {@code null} if none.
-     * @param  versionGML      The GML version, or {@code null}.
-     * @param  resolver        The resolver in use.
-     * @param  converter       The converter in use.
-     * @param  warningListener The object to inform about warnings.
+     * @param  bitMasks         a combination of {@link #MARSHALLING}, {@code SUBSTITUTE_*} or other bit masks.
+     * @param  locale           the locale, or {@code null} if unspecified.
+     * @param  timezone         the timezone, or {@code null} if unspecified.
+     * @param  schemas          the schemas root URL, or {@code null} if none.
+     * @param  versionGML       the GML version, or {@code null}.
+     * @param  resolver         the resolver in use.
+     * @param  converter        the converter in use.
+     * @param  warningListener  the object to inform about warnings.
      */
     @SuppressWarnings("ThisEscapedInObjectConstruction")
     public Context(final int                bitMasks,
@@ -220,7 +220,7 @@ public final class Context extends Marsh
         this.bitMasks          = bitMasks;
         this.locales           = new LinkedList<>();
         this.timezone          = timezone;
-        this.schemas           = schemas; // No clone, because this class is internal.
+        this.schemas           = schemas;               // No clone, because this class is internal.
         this.versionGML        = versionGML;
         this.resolver          = resolver;
         this.converter         = converter;
@@ -242,7 +242,7 @@ public final class Context extends Marsh
     /**
      * Returns the locale to use for marshalling, or {@code null} if no locale were explicitly specified.
      *
-     * @return The locale in the context of current (un)marshalling process.
+     * @return the locale in the context of current (un)marshalling process.
      */
     @Override
     public final Locale getLocale() {
@@ -252,7 +252,7 @@ public final class Context extends Marsh
     /**
      * Returns the timezone to use for marshalling, or {@code null} if none were explicitely specified.
      *
-     * @return The timezone in the context of current (un)marshalling process.
+     * @return the timezone in the context of current (un)marshalling process.
      */
     @Override
     public final TimeZone getTimeZone() {
@@ -263,7 +263,7 @@ public final class Context extends Marsh
      * Returns the schema version of the XML document being (un)marshalled.
      * See the super-class javadoc for the list of prefix that we shall support.
      *
-     * @return The version in the context of current (un)marshalling process.
+     * @return the version in the context of current (un)marshalling process.
      */
     @Override
     public final Version getVersion(final String prefix) {
@@ -291,7 +291,7 @@ public final class Context extends Marsh
      * Returns the context of the XML (un)marshalling currently progressing in the current thread,
      * or {@code null} if none.
      *
-     * @return The current (un)marshalling context, or {@code null} if none.
+     * @return the current (un)marshalling context, or {@code null} if none.
      */
     public static Context current() {
         return CURRENT.get();
@@ -313,7 +313,7 @@ public final class Context extends Marsh
      *     }
      * }
      *
-     * @param locale The locale to set, or {@code null}.
+     * @param  locale  the locale to set, or {@code null}.
      */
     public static void push(Locale locale) {
         final Context current = current();
@@ -339,9 +339,9 @@ public final class Context extends Marsh
     /**
      * Returns {@code true} if the given flag is set.
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  flag One of {@link #MARSHALLING}, {@link #SUBSTITUTE_LANGUAGE},
-     *         {@link #SUBSTITUTE_COUNTRY} or other bit masks.
+     * @param  context  the current context, or {@code null} if none.
+     * @param  flag     one of {@link #MARSHALLING}, {@link #SUBSTITUTE_LANGUAGE}, {@link #SUBSTITUTE_COUNTRY}
+     *                  or other bit masks.
      * @return {@code true} if the given flag is set.
      */
     public static boolean isFlagSet(final Context context, final int flag) {
@@ -356,8 +356,8 @@ public final class Context extends Marsh
      * <div class="note"><b>API note:</b>
      * This method is static for the convenience of performing the check for null context.</div>
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  version The version to compare to.
+     * @param  context  the current context, or {@code null} if none.
+     * @param  version  the version to compare to.
      * @return {@code true} if the GML version is equals or newer than the specified version.
      *
      * @see #getVersion(String)
@@ -380,11 +380,11 @@ public final class Context extends Marsh
      * <div class="note"><b>API note:</b>
      * This method is static for the convenience of performing the check for null context.</div>
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  key One of the value documented in the <cite>"Map key"</cite> column of
-     *         {@link org.apache.sis.xml.XML#SCHEMAS}.
-     * @param  defaultSchema The value to return if no schema is found for the given key.
-     * @return The base URL of the schema, or an empty buffer if none were specified.
+     * @param  context        the current context, or {@code null} if none.
+     * @param  key            one of the value documented in the <cite>"Map key"</cite> column of
+     *                        {@link org.apache.sis.xml.XML#SCHEMAS}.
+     * @param  defaultSchema  the value to return if no schema is found for the given key.
+     * @return the base URL of the schema, or an empty buffer if none were specified.
      */
     public static StringBuilder schema(final Context context, final String key, String defaultSchema) {
         final StringBuilder buffer = new StringBuilder(128);
@@ -429,8 +429,8 @@ public final class Context extends Marsh
      * For performance reasons, this {@code wrapper} information is not provided by default.
      * See {@link #setWrapper(Context, PropertyType)} for more information.
      *
-     * @param  context The current context, or {@code null} if none.
-     * @return The {@code <gml:*PropertyType>} which is wrapping the {@code <gml:*Type>} object to (un)marshal,
+     * @param  context  the current context, or {@code null} if none.
+     * @return the {@code <gml:*PropertyType>} which is wrapping the {@code <gml:*Type>} object to (un)marshal,
      *         or {@code null} if unknown.
      */
     public static PropertyType<?,?> getWrapper(final Context context) {
@@ -446,9 +446,9 @@ public final class Context extends Marsh
      * {@code beforeUnmarshal(…)} method. For an implementation example, see
      * {@link org.apache.sis.internal.jaxb.referencing.CC_OperationParameter}.</p>
      *
-     * @param context The current context, or {@code null} if none.
-     * @param wrapper The {@code <gml:*PropertyType>} which is wrapping the {@code <gml:*Type>} object to (un)marshal,
-     *                or {@code null} if unknown.
+     * @param context  the current context, or {@code null} if none.
+     * @param wrapper  the {@code <gml:*PropertyType>} which is wrapping the {@code <gml:*Type>} object to (un)marshal,
+     *                 or {@code null} if unknown.
      */
     public static void setWrapper(final Context context, final PropertyType<?,?> wrapper) {
         if (context != null) {
@@ -460,9 +460,9 @@ public final class Context extends Marsh
      * If a {@code gml:id} value has already been used for the given object in the current XML document,
      * returns that identifier. Otherwise returns {@code null}.
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  object  The object for which to get the {@code gml:id}.
-     * @return The identifier used in the current XML document for the given object, or {@code null} if none.
+     * @param  context  the current context, or {@code null} if none.
+     * @param  object   the object for which to get the {@code gml:id}.
+     * @return the identifier used in the current XML document for the given object, or {@code null} if none.
      *
      * @since 0.7
      */
@@ -474,9 +474,9 @@ public final class Context extends Marsh
      * Returns the object for the given {@code gml:id}, or {@code null} if none.
      * This association is valid only for the current XML document.
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  id      The identifier for which to get the object.
-     * @return The object associated to the given identifier, or {@code null} if none.
+     * @param  context  the current context, or {@code null} if none.
+     * @param  id       the identifier for which to get the object.
+     * @return the object associated to the given identifier, or {@code null} if none.
      *
      * @since 0.7
      */
@@ -490,9 +490,9 @@ public final class Context extends Marsh
      * invocation of {@code Context} method.  If this method returns {@code false}, then the caller is responsible
      * for computing an other identifier candidate.
      *
-     * @param  context The current context, or {@code null} if none.
-     * @param  object  The object for which to assign the {@code gml:id}.
-     * @param  id      The identifier to assign to the given object.
+     * @param  context  the current context, or {@code null} if none.
+     * @param  object   the object for which to assign the {@code gml:id}.
+     * @param  id       the identifier to assign to the given object.
      * @return {@code true} if the given identifier can be used.
      *
      * @since 0.7
@@ -518,8 +518,8 @@ public final class Context extends Marsh
      * <div class="note"><b>API note:</b>
      * This method is static for the convenience of performing the check for null context.</div>
      *
-     * @param  context The current context, or {@code null} if none.
-     * @return The current reference resolver (never null).
+     * @param  context  the current context, or {@code null} if none.
+     * @return the current reference resolver (never null).
      */
     public static ReferenceResolver resolver(final Context context) {
         if (context != null) {
@@ -538,8 +538,8 @@ public final class Context extends Marsh
      * <div class="note"><b>API note:</b>
      * This method is static for the convenience of performing the check for null context.</div>
      *
-     * @param  context The current context, or {@code null} if none.
-     * @return The current value converter (never null).
+     * @param  context  the current context, or {@code null} if none.
+     * @return the current value converter (never null).
      */
     public static ValueConverter converter(final Context context) {
         if (context != null) {
@@ -558,14 +558,14 @@ public final class Context extends Marsh
      * <p>If the given {@code resources} is {@code null}, then this method will build the log
      * message from the {@code exception}.</p>
      *
-     * @param context   The current context, or {@code null} if none.
-     * @param level     The logging level.
-     * @param classe    The class to declare as the warning source.
-     * @param method    The name of the method to declare as the warning source.
-     * @param exception The exception thrown, or {@code null} if none.
-     * @param resources Either {@code Errors.class}, {@code Messages.class} or {@code null} for the exception message.
-     * @param key       The resource keys as one of the constants defined in the {@code Keys} inner class.
-     * @param arguments The arguments to be given to {@code MessageFormat} for formatting the log message.
+     * @param  context    the current context, or {@code null} if none.
+     * @param  level      the logging level.
+     * @param  classe     the class to declare as the warning source.
+     * @param  method     the name of the method to declare as the warning source.
+     * @param  exception  the exception thrown, or {@code null} if none.
+     * @param  resources  either {@code Errors.class}, {@code Messages.class} or {@code null} for the exception message.
+     * @param  key        the resource keys as one of the constants defined in the {@code Keys} inner class.
+     * @param  arguments  the arguments to be given to {@code MessageFormat} for formatting the log message.
      *
      * @since 0.5
      */
@@ -610,12 +610,12 @@ public final class Context extends Marsh
      * Convenience method for sending a warning for the given message from the {@link Errors} or {@link Messages}
      * resources. The message will be logged at {@link Level#WARNING}.
      *
-     * @param context   The current context, or {@code null} if none.
-     * @param classe    The class to declare as the warning source.
-     * @param method    The name of the method to declare as the warning source.
-     * @param resources Either {@code Errors.class} or {@code Messages.class}.
-     * @param key       The resource keys as one of the constants defined in the {@code Keys} inner class.
-     * @param arguments The arguments to be given to {@code MessageFormat} for formatting the log message.
+     * @param  context    the current context, or {@code null} if none.
+     * @param  classe     the class to declare as the warning source.
+     * @param  method     the name of the method to declare as the warning source.
+     * @param  resources  either {@code Errors.class} or {@code Messages.class}.
+     * @param  key        the resource keys as one of the constants defined in the {@code Keys} inner class.
+     * @param  arguments  the arguments to be given to {@code MessageFormat} for formatting the log message.
      *
      * @since 0.5
      */
@@ -629,11 +629,11 @@ public final class Context extends Marsh
      * Convenience method for sending a warning for the given exception.
      * The logger will be {@code "org.apache.sis.xml"}.
      *
-     * @param context   The current context, or {@code null} if none.
-     * @param classe    The class to declare as the warning source.
-     * @param method    The name of the method to declare as the warning source.
-     * @param cause     The exception which occurred.
-     * @param isWarning {@code true} for {@link Level#WARNING}, or {@code false} for {@link Level#FINE}.
+     * @param  context    the current context, or {@code null} if none.
+     * @param  classe     the class to declare as the warning source.
+     * @param  method     the name of the method to declare as the warning source.
+     * @param  cause      the exception which occurred.
+     * @param  isWarning  {@code true} for {@link Level#WARNING}, or {@code false} for {@link Level#FINE}.
      */
     public static void warningOccured(final Context context, final Class<?> classe,
             final String method, final Exception cause, final boolean isWarning)

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/Measure.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/Measure.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/Measure.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/Measure.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -122,7 +122,7 @@ public final class Measure {
      *     http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])
      * }
      *
-     * @return The string representation of the unit of measure.
+     * @return the string representation of the unit of measure.
      *
      * @todo Strictly speaking, the above URL should be used only for "m", "deg" and "rad" units because they
      *       are the only ones defined in the <code>gmxUom.xml</code> file. What should we do for other units?
@@ -137,10 +137,10 @@ public final class Measure {
      * {@code uom} attribute, instead of letting the {@code uom} attribute on the measurement value.
      * The main example is {@link org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis}.
      *
-     * @param  unit The unit to format.
+     * @param  unit       the unit to format.
      * @param  asXPointer {@code true} if the units shall be formatted as {@code xpointer}.
-     * @param  inAxis {@code true} for a unit used in Coordinate System Axis definition.
-     * @return The string representation of the unit of measure.
+     * @param  inAxis     {@code true} for a unit used in Coordinate System Axis definition.
+     * @return the string representation of the unit of measure.
      */
     public static String getUOM(final Unit<?> unit, final boolean asXPointer, final boolean inAxis) {
         if (!asXPointer) {
@@ -159,8 +159,8 @@ public final class Measure {
     /**
      * Sets the unit of measure. This method is invoked by JAXB at unmarshalling time.
      *
-     * @param uom The unit of measure as a string.
-     * @throws URISyntaxException If the {@code uom} looks like a URI, but can not be parsed.
+     * @param  uom  the unit of measure as a string.
+     * @throws URISyntaxException if the {@code uom} looks like a URI, but can not be parsed.
      */
     public void setUOM(String uom) throws URISyntaxException {
         final Context context = Context.current();
@@ -173,9 +173,9 @@ public final class Measure {
      * @todo For now, this method does not format useful error message in case of wrong unit type.
      *       We define this method merely as a placeholder for future improvement in error handling.
      *
-     * @param  <Q>  Compile-time type of the {@code type} argument.
-     * @param  type The quantity for the desired unit.
-     * @return A unit compatible with the given type, or {@code null} if none.
+     * @param  <Q>   compile-time type of the {@code type} argument.
+     * @param  type  the quantity for the desired unit.
+     * @return a unit compatible with the given type, or {@code null} if none.
      */
     public <Q extends Quantity<Q>> Unit<Q> getUnit(final Class<Q> type) {
         return (unit != null) ? unit.asType(type) : null;
@@ -190,7 +190,7 @@ public final class Measure {
      * The SIS adapter forces the unit to {@link Units#UNITY}, but we want to let the user
      * know that he probably did something wrong.</div>
      *
-     * @param  newUnit The new unit (can not be null).
+     * @param  newUnit  the new unit (can not be null).
      * @return {@code true} if a different unit was defined before this method call.
      */
     public boolean setUnit(final Unit<?> newUnit) {
@@ -202,8 +202,8 @@ public final class Measure {
     /**
      * Sends a warning for a missing {@code "uom"} attribute.
      *
-     * @param caller     The class of the method invoking this method.
-     * @param methodName The name of the method invoking this method.
+     * @param  caller      the class of the method invoking this method.
+     * @param  methodName  the name of the method invoking this method.
      */
     public static void missingUOM(final Class<?> caller, final String methodName) {
         Context.warningOccured(Context.current(), caller, methodName,

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -57,6 +57,11 @@ public final class Loggers extends Stati
     public static final String MATH = "org.apache.sis.math";
 
     /**
+     * The logger for operations related to units of measurement.
+     */
+    public static final String MEASURE = "org.apache.sis.measure";
+
+    /**
      * The logger for operations related to JDBC operations.
      */
     public static final String SQL = "org.apache.sis.sql";

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -17,10 +17,12 @@
 package org.apache.sis.internal.util;
 
 import java.util.Arrays;
+import java.math.BigInteger;
+import java.math.BigDecimal;
+import java.math.MathContext;
 import org.apache.sis.math.Fraction;
 import org.apache.sis.math.MathFunctions;
 import org.apache.sis.math.DecimalFunctions;
-// No BigDecimal dependency - see class javadoc
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.JDK8;
@@ -47,8 +49,6 @@ import org.apache.sis.internal.jdk8.JDK8
  *     BigDecimal decimal = new BigDecimal(dd.value).add(new BigDecimal(dd.error));
  * }
  *
- * We do not provide convenience method for the above in order to avoid dependency to {@code BigDecimal}.
- *
  * <div class="section">Impact of availability of FMA instructions</div>
  * If <cite>fused multiply-add</cite> (FMA) instruction are available in a future Java version
  * (see <a href="https://issues.apache.org/jira/browse/SIS-136">SIS-136</a> on Apache SIS JIRA),
@@ -204,17 +204,28 @@ public final class DoubleDouble extends
 
     /**
      * Creates a new value initialized to the given number. If the given number is an instance of
-     * {@code DoubleDouble} or {@link Fraction}, then the error term will be taken in account.
+     * {@code DoubleDouble}, {@link BigDecimal}, {@link BigInteger} or {@link Fraction}, then the
+     * error term will be taken in account.
      *
      * @param  otherValue  the initial value.
      */
-    public DoubleDouble(final Number otherValue) {
+    public DoubleDouble(Number otherValue) {
         if (otherValue instanceof Fraction) {
             value = ((Fraction) otherValue).denominator;
             inverseDivide(((Fraction) otherValue).numerator, 0);
         } else {
+            if (otherValue instanceof BigInteger) {
+                otherValue = new BigDecimal((BigInteger) otherValue, MathContext.DECIMAL128);
+            }
             value = otherValue.doubleValue();
-            error = (otherValue instanceof DoubleDouble) ? ((DoubleDouble) otherValue).error : errorForWellKnownValue(value);
+            if (otherValue instanceof DoubleDouble) {
+                error = ((DoubleDouble) otherValue).error;
+            } else if (otherValue instanceof BigDecimal) {
+                // Really need new BigDecimal(value) below, not BigDecimal.valueOf(value).
+                error = ((BigDecimal) otherValue).subtract(new BigDecimal(value), MathContext.DECIMAL64).doubleValue();
+            } else {
+                error = errorForWellKnownValue(value);
+            }
         }
     }
 
@@ -229,7 +240,7 @@ public final class DoubleDouble extends
      * @since 0.8
      */
     public static boolean shouldConvert(final Number value) {
-        return (value instanceof Fraction);
+        return (value instanceof Fraction) || (value instanceof BigInteger) || (value instanceof BigDecimal);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/AbstractUnit.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -25,6 +25,7 @@ import java.io.Serializable;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 import org.apache.sis.math.Fraction;
+import org.apache.sis.util.Characters;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
@@ -65,6 +66,12 @@ abstract class AbstractUnit<Q extends Qu
     /**
      * The unit symbol, or {@code null} if this unit has no specific symbol. If {@code null},
      * then the {@link #toString()} method is responsible for creating a representation on the fly.
+     * If non-null, this symbol should complies with the {@link UnitFormat.Style#SYMBOL} formatting
+     * (<strong>not</strong> the UCUM format). In particular, this symbol uses Unicode characters
+     * for arithmetic operators and superscripts, as in “m/s²”. However this symbol should never
+     * contains the unit conversion terms. For example “km” is okay, but “1000⋅m” is not.
+     * The intend of those rules is to make easier to analyze the symbol in methods like
+     * {@link ConventionalUnit#power(String)}.
      *
      * <p>Users can override this symbol by call to {@link UnitFormat#label(Unit, String)},
      * but such overriding applies only to the target {@code UnitFormat} instance.</p>
@@ -73,6 +80,7 @@ abstract class AbstractUnit<Q extends Qu
      * for fetching a localized name from the resource bundle.</p>
      *
      * @see #getSymbol()
+     * @see SystemUnit#alternate(String)
      */
     private final String symbol;
 
@@ -95,7 +103,7 @@ abstract class AbstractUnit<Q extends Qu
      *
      * @param  symbol  the unit symbol, or {@code null} if this unit has no specific symbol.
      * @param  scope   {@link UnitRegistry#SI}, {@link UnitRegistry#ACCEPTED}, other constants or 0 if unknown.
-     * @param  epsg    the EPSG code,   or 0 if this unit has no EPSG code.
+     * @param  epsg    the EPSG code, or 0 if this unit has no EPSG code.
      */
     AbstractUnit(final String symbol, final byte scope, final short epsg) {
         this.symbol = symbol;
@@ -190,7 +198,7 @@ abstract class AbstractUnit<Q extends Qu
      */
     @Override
     public final Unit<Q> shift(final double offset) {
-        return transform(LinearConverter.create(1, offset));
+        return transform(LinearConverter.offset(offset, 1));
     }
 
     /**
@@ -202,7 +210,11 @@ abstract class AbstractUnit<Q extends Qu
      */
     @Override
     public final Unit<Q> multiply(final double multiplier) {
-        return transform(LinearConverter.create(multiplier, 0));
+        final double r = inverse(multiplier);
+        if (!Double.isNaN(r)) {
+            return divide(r);
+        }
+        return transform(LinearConverter.scale(multiplier, 1));
     }
 
     /**
@@ -214,7 +226,27 @@ abstract class AbstractUnit<Q extends Qu
      */
     @Override
     public final Unit<Q> divide(final double divisor) {
-        return transform(LinearConverter.create(1/divisor, 0));
+        final double r = inverse(divisor);
+        if (!Double.isNaN(r)) {
+            return multiply(r);
+        }
+        return transform(LinearConverter.scale(1, divisor));
+    }
+
+    /**
+     * If the inverse of the given multiplier is an integer, returns that inverse. Otherwise returns NaN.
+     * This method is used for replacing e.g. {@code multiply(0.001)} calls by {@code divide(1000)} calls.
+     * The later allows more accurate operations because of the way {@link LinearConverter} is implemented.
+     */
+    private static double inverse(final double multiplier) {
+        if (Math.abs(multiplier) < 1) {
+            final double inverse = 1 / multiplier;
+            final double r = Math.rint(inverse);
+            if (Math.abs(inverse - r) <= Math.ulp(inverse)) {
+                return r;
+            }
+        }
+        return Double.NaN;
     }
 
     /**
@@ -266,13 +298,26 @@ abstract class AbstractUnit<Q extends Qu
     }
 
     /**
+     * Returns {@code true} if the given Unicode code point is a valid character for a unit symbol.
+     * Current implementation accepts only letters and subscripts, but the set of legal characters
+     * may be expanded in any future SIS version. The most important goal is to avoid confusion with
+     * exponents.
+     *
+     * <p>Note that some units defined in the {@link Units} class break this rule. But the hard-coded
+     * symbols in that class are known to be consistent with SI usage or with {@link UnitFormat} work.</p>
+     */
+    static boolean isSymbolChar(final int c) {
+        return Character.isLetter(c) || Characters.isSubScript(c);
+    }
+
+    /**
      * Invoked on deserialization for returning a unique instance of {@code AbstractUnit} if possible.
      */
     final Object readResolve() throws ObjectStreamException {
         if (symbol != null && Units.initialized) {              // Force Units class initialization.
-            final Unit<?> exising = (Unit<?>) UnitRegistry.putIfAbsent(symbol, this);
-            if (equals(exising)) {
-                return exising;
+            final Object existing = UnitRegistry.putIfAbsent(symbol, this);
+            if (equals(existing)) {
+                return (Unit<?>) existing;
             }
         }
         return this;

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -25,7 +25,10 @@ import javax.measure.UnconvertibleExcept
 import javax.measure.IncommensurableException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Characters;
 import org.apache.sis.math.Fraction;
+import org.apache.sis.math.MathFunctions;
+import org.apache.sis.internal.util.Numerics;
 
 
 /**
@@ -43,6 +46,19 @@ final class ConventionalUnit<Q extends Q
     private static final long serialVersionUID = 6963634855104019466L;
 
     /**
+     * The SI prefixes form smallest to largest. Power of tens go from -24 to +24 inclusive with a step of 3,
+     * except for the addition of -2, -1, +1, +2 and the omission of 0.
+     *
+     * @see #prefix(double)
+     */
+    private static final char[] PREFIXES = {'y','z','a','f','p','n','µ','m','c','d','㍲','h','k','M','G','T','P','E','Z','Y'};
+
+    /**
+     * The maximal power of 1000 for the prefixes in the {@link #PREFIXES} array. Note that 1000⁸ = 1E+24.
+     */
+    static final int MAX_POWER = 8;
+
+    /**
      * The base, derived or alternate units to which this {@code ConventionalUnit} is related.
      * This is called "preferred unit" in GML.
      */
@@ -56,11 +72,11 @@ final class ConventionalUnit<Q extends Q
     /**
      * Creates a new unit having the given symbol and EPSG code.
      *
-     * @param  target     the base or derived units to which this {@code ConventionalUnit} is related.
-     * @param  toTarget   the conversion from this unit to the {@code target} unit.
-     * @param  symbol     the unit symbol, or {@code null} if this unit has no specific symbol.
-     * @param  scope   {@link UnitRegistry#SI}, {@link UnitRegistry#ACCEPTED}, other constants or 0 if unknown.
-     * @param  epsg       the EPSG code,   or 0 if this unit has no EPSG code.
+     * @param  target    the base or derived units to which this {@code ConventionalUnit} is related.
+     * @param  toTarget  the conversion from this unit to the {@code target} unit.
+     * @param  symbol    the unit symbol, or {@code null} if this unit has no specific symbol.
+     * @param  scope     {@link UnitRegistry#SI}, {@link UnitRegistry#ACCEPTED}, other constants or 0 if unknown.
+     * @param  epsg      the EPSG code, or 0 if this unit has no EPSG code.
      */
     ConventionalUnit(final SystemUnit<Q> target, final UnitConverter toTarget, final String symbol, final byte scope, final short epsg) {
         super(symbol, scope, epsg);
@@ -71,12 +87,140 @@ final class ConventionalUnit<Q extends Q
     /**
      * Creates a new unit with default name and symbol for the given converter.
      */
+    @SuppressWarnings("unchecked")
     static <Q extends Quantity<Q>> AbstractUnit<Q> create(final SystemUnit<Q> target, final UnitConverter toTarget) {
         if (toTarget.isIdentity()) {
             return target;
         }
-        // TODO: check for existing unit.
-        return new ConventionalUnit<>(target, toTarget, null, (byte) 0, (short) 0);
+        /*
+         * If the unit is a SI unit, try to create the SI symbol by the concatenation of the SI prefix
+         * with the system unit symbol. The unit symbol are used later as a key for searching existing
+         * unit instances.
+         */
+        String symbol = null;
+        if (target.scope == UnitRegistry.SI) {
+            final String ts = target.getSymbol();
+            if (ts != null && !ts.isEmpty() && toTarget.isLinear()) {
+                final int power = power(ts);
+                if (power != 0) {
+                    double scale = toTarget.convert(1);
+                    switch (power) {
+                        case 1:  break;
+                        case 2:  scale = Math.sqrt(scale); break;
+                        case 3:  scale = Math.cbrt(scale); break;
+                        default: scale = Math.pow(scale, 1.0/power);
+                    }
+                    final char prefix = prefix(scale);
+                    if (prefix != 0) {
+                        if (prefix == '㍲') {
+                            symbol = UnitFormat.DECA + ts;
+                        } else {
+                            symbol = prefix + ts;
+                        }
+                    }
+                }
+            }
+        }
+        /*
+         * Create the unit, but we may discard it later if an equivalent unit already exists in the cache.
+         * The use of the cache is not only for sharing instances, but also because existing instances may
+         * have more information.  For example instances provided by Units static constants may contain an
+         * EPSG code, or even an alternative symbol (e.g. “hm²” will be replaced by “ha” for hectare).
+         */
+        final ConventionalUnit<Q> unit = new ConventionalUnit<>(target, toTarget, symbol, (byte) 0, (short) 0);
+        if (symbol != null) {
+            final Object existing = UnitRegistry.putIfAbsent(symbol, unit);
+            if (existing instanceof ConventionalUnit<?>) {
+                final ConventionalUnit<?> c = (ConventionalUnit<?>) existing;
+                if (target.equals(c.target)) {
+                    final boolean equivalent;
+                    if (toTarget instanceof LinearConverter && c.toTarget instanceof LinearConverter) {
+                        equivalent = ((LinearConverter) toTarget).equivalent((LinearConverter) c.toTarget);
+                    } else {
+                        equivalent = toTarget.equals(c.toTarget);   // Fallback for unknown implementations.
+                    }
+                    if (equivalent) {
+                        return (ConventionalUnit<Q>) c;
+                    }
+                }
+            }
+        }
+        return unit;
+    }
+
+    /**
+     * Returns the positive power after the given unit symbol, or in case of doubt.
+     * For example this method returns 1 for “m” and 2 for “m²”. We parse the unit symbol instead
+     * than the {@link SystemUnit#dimension} because we can not extract easily the power from the
+     * product of dimensions (e.g. what is the M⋅L²∕T³ power?) Furthermore the power will be used
+     * for choosing a symbol prefix, so we want it to be consistent with the symbol more than the
+     * internal representation.
+     *
+     * <p>If the unit is itself a product of other units, then this method returns the power of
+     * the first unit. For example the power of “m/s²” is 1. This means that the “k” prefix in
+     * “km/s²” apply only to the “m” unit.</p>
+     */
+    static int power(final String symbol) {
+        final int length = symbol.length();
+        int i = 0, c;
+        do {
+            if (i >= length) return 1;              // Single symbol (no product, no exponent).
+            c = symbol.codePointAt(i);
+            i += Character.charCount(c);
+        } while (isSymbolChar(c));
+        /*
+         * At this point we found the first character which is not part of a unit symbol.
+         * We may have found the exponent as in “m²”, or we may have found an arithmetic
+         * operator like the “/” in “m/s²”. In any cases we stop here because we want the
+         * exponent of the first symbol, not the “²” in “m/s²”.
+         */
+        if (Character.isBmpCodePoint(c)) {
+            final int p = Characters.toNormalScript((char) c) - '0';
+            if (p >= 0 && p <= 9) {
+                if (i < length) {
+                    c = symbol.codePointAt(i);
+                    if (isSymbolChar(c)) {
+                        // Exponent is immediately followed by a another unit symbol character.
+                        // We would have expected something else, like an arithmetic operator.
+                        return 0;
+                    }
+                    if (Character.isBmpCodePoint(c)) {
+                        c = Characters.toNormalScript((char) c);
+                        if (c >= '0' && c <= '9') {
+                            // Exponent on two digits. We do not expect so high power after unit symbol.
+                            return 0;
+                        }
+                    }
+                }
+                return p;
+            }
+        }
+        return 1;
+    }
+
+    /**
+     * Returns the SI prefix for the given scale factor, or 0 if none.
+     */
+    @SuppressWarnings("null")
+    static char prefix(final double scale) {
+        final int n = Numerics.toExp10(Math.getExponent(scale)) + 1;
+        if (Math.abs(MathFunctions.pow10(n) - scale) <= Math.ulp(scale)) {
+            int i = Math.abs(n);
+            switch (i) {
+                case 0:  return 0;
+                case 1:  // Fallthrough
+                case 2:  break;
+                default: {
+                    if (i > (MAX_POWER*3) || (i % 3) != 0) {
+                        return 0;
+                    }
+                    i = i/3 + 2;
+                    break;
+                }
+            }
+            return PREFIXES[n >= 0 ? (MAX_POWER+1) + i : (MAX_POWER+2) - i];
+        }
+        return 0;
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -20,11 +20,14 @@ import java.util.List;
 import java.util.Arrays;
 import java.util.Collections;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import javax.measure.UnitConverter;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.StringBuilders;
 import org.apache.sis.math.DecimalFunctions;
 import org.apache.sis.math.MathFunctions;
+import org.apache.sis.math.Fraction;
 import org.apache.sis.internal.util.Numerics;
 
 
@@ -74,50 +77,69 @@ final class LinearConverter extends Abst
     /**
      * The identity linear converter.
      */
-    static final LinearConverter IDENTITY = new LinearConverter(1, 0);
+    static final LinearConverter IDENTITY = new LinearConverter(1, 0, 1);
 
     /**
-     * The scale to apply for converting values.
+     * The scale to apply for converting values, before division by {@link #divisor}.
      */
     private final double scale;
 
     /**
-     * The offset to apply after the scale.
+     * The offset to apply after the scale, before division by {@link #divisor}.
      */
     private final double offset;
 
     /**
-     * The inverse of this unit converter. Computed when first needed and stored in
-     * order to avoid rounding error if the user asks for the inverse of the inverse.
+     * A divisor applied after the conversion.
+     * The complete formula used by Apache SIS is {@code y = (x*scale + offset) / divisor}.
+     * This division is mathematically unneeded since we could divide the offset and scale factor directly,
+     * but we keep it for accuracy reasons because most unit conversion factors are defined in base 10 and
+     * IEEE 754 can not represent fractional values in base 10 accurately.
      */
-    private transient LinearConverter inverse;
+    private final double divisor;
+
+    /**
+     * The scale and offset factors represented in base 10, computed when first needed.
+     * Those terms are pre-divided by the {@linkplain #divisor}.
+     */
+    private transient volatile BigDecimal scale10, offset10;
 
     /**
      * Creates a new linear converter for the given scale and offset.
+     * The complete formula applied is {@code y = (x*scale + offset) / divisor}.
      */
-    private LinearConverter(final double scale, final double offset) {
-        this.scale  = scale;
-        this.offset = offset;
+    private LinearConverter(final double scale, final double offset, final double divisor) {
+        this.scale   = scale;
+        this.offset  = offset;
+        this.divisor = divisor;
     }
 
     /**
      * Returns a linear converter for the given scale and offset.
      */
-    static LinearConverter create(final double scale, final double offset) {
+    private static LinearConverter create(final double scale, final double offset, final double divisor) {
         if (offset == 0) {
-            if (scale == 1) return IDENTITY;
+            if (scale == divisor) return IDENTITY;
         }
-        return new LinearConverter(scale, offset);
+        return new LinearConverter(scale, offset, divisor);
     }
 
     /**
      * Returns a linear converter for the given ratio. The scale factor is specified as a ratio because
-     * the unit conversion factors are defined with a value which is exact in base 10.
-     *
-     * @todo modify the {@code LinearConverter} implementation for storing the ratio.
+     * the unit conversion factors are often defined with a value in base 10.  That value is considered
+     * exact by definition, but IEEE 754 has no exact representation of decimal fraction digits.
      */
     static LinearConverter scale(final double numerator, final double denominator) {
-        return new LinearConverter(numerator / denominator, 0);
+        return new LinearConverter(numerator, 0, denominator);
+    }
+
+    /**
+     * Returns a converter for the given shift. The translation is specified as a fraction because the
+     * unit conversion terms are often defined with a value in base 10. That value is considered exact
+     * by definition, but IEEE 754 has no exact representation of decimal fraction digits.
+     */
+    static LinearConverter offset(final double numerator, final double denominator) {
+        return new LinearConverter(denominator, numerator, denominator);
     }
 
     /**
@@ -150,7 +172,7 @@ final class LinearConverter extends Abst
 
     /**
      * Raises the given converter to the given power. This method assumes that the given converter
-     * {@linkplain #isLinear() is linear} (this is not verified) and take only the scale factor;
+     * {@linkplain #isLinear() is linear} (this is not verified) and takes only the scale factor;
      * the offset (if any) is ignored.
      *
      * @param  converter  the converter to raise to the given power.
@@ -159,19 +181,35 @@ final class LinearConverter extends Abst
      * @return the converter raised to the given power.
      */
     static LinearConverter pow(final UnitConverter converter, final int n, final boolean root) {
-        double scale = converter.convert(1.0) - converter.convert(0.0);
+        double numerator, denominator;
+        if (converter instanceof LinearConverter) {
+            final LinearConverter lc = (LinearConverter) converter;
+            numerator   = lc.scale;
+            denominator = lc.divisor;
+        } else {
+            // Subtraction by convert(0) is a paranoiac safety.
+            numerator   = converter.convert(1.0) - converter.convert(0.0);
+            denominator = 1;
+        }
         if (root) {
             switch (n) {
-                case 2:  scale = Math.sqrt(scale); break;
-                case 3:  scale = Math.cbrt(scale); break;
-                default: scale = Math.pow(scale, 1.0 / n); break;
+                case 1:  break;
+                case 2:  numerator   = Math.sqrt(numerator);
+                         denominator = Math.sqrt(denominator);
+                         break;
+                case 3:  numerator   = Math.cbrt(numerator);
+                         denominator = Math.cbrt(denominator);
+                         break;
+                default: final double r = 1.0 / n;
+                         numerator   = Math.pow(numerator,   r);
+                         denominator = Math.pow(denominator, r);
+                         break;
             }
-        } else if (scale == 10) {
-            scale = MathFunctions.pow10(n);
         } else {
-            scale = Math.pow(scale, n);
+            numerator   = (numerator   == 10) ? MathFunctions.pow10(n) : Math.pow(numerator,   n);
+            denominator = (denominator == 10) ? MathFunctions.pow10(n) : Math.pow(denominator, n);
         }
-        return create(scale, 0);
+        return scale(numerator, denominator);
     }
 
     /**
@@ -192,23 +230,30 @@ final class LinearConverter extends Abst
     }
 
     /**
-     * Returns {@code true} if the scale is 1 and the offset is zero.
+     * Returns {@code true} if the effective scale factor is 1 and the offset is zero.
      */
     @Override
     public boolean isIdentity() {
-        return scale == 1 && offset == 0;
+        return scale == divisor && offset == 0;
     }
 
     /**
      * Returns the inverse of this unit converter.
+     * Given that the formula applied by this converter is:
+     *
+     * {@preformat math
+     *    y = (x⋅scale + offset) ∕ divisor
+     * }
+     *
+     * the inverse formula is:
+     *
+     * {@preformat math
+     *    x = (y⋅divisor - offset) ∕ scale
+     * }
      */
     @Override
     public synchronized UnitConverter inverse() {
-        if (inverse == null) {
-            inverse = new LinearConverter(1/scale, -offset/scale);
-            inverse.inverse = this;
-        }
-        return inverse;
+        return isIdentity() ? this : new LinearConverter(divisor, -offset, scale);
     }
 
     /**
@@ -217,50 +262,75 @@ final class LinearConverter extends Abst
     @Override
     @SuppressWarnings("fallthrough")
     Number[] coefficients() {
-        final Number[] c = new Number[(scale != 1) ? 2 : (offset != 0) ? 1 : 0];
+        final Number[] c = new Number[(scale != divisor) ? 2 : (offset != 0) ? 1 : 0];
         switch (c.length) {
-            case 2: c[1] = scale;
-            case 1: c[0] = offset;
+            case 2: c[1] = ratio(scale,  divisor);
+            case 1: c[0] = ratio(offset, divisor);
             case 0: break;
         }
         return c;
     }
 
     /**
+     * Returns the given ratio as a {@link Fraction} if possible, or as a {@link Double} otherwise.
+     * The use of {@link Fraction} allows the {@link org.apache.sis.referencing.operation.matrix}
+     * package to perform more accurate calculations.
+     */
+    private static Number ratio(final double value, final double divisor) {
+        final int numerator = (int) value;
+        if (numerator == value) {
+            final int denominator = (int) divisor;
+            if (denominator == divisor) {
+                return (denominator == 1) ? numerator : new Fraction(numerator, denominator);
+            }
+        }
+        return value / divisor;
+    }
+
+    /**
      * Applies the linear conversion on the given IEEE 754 floating-point value.
      */
     @Override
     public double convert(final double value) {
-        return value * scale + offset;
+        // TODO: use JDK9' Math.fma(…) and verify if it solve the accuracy issue in LinearConverterTest.inverse().
+        return (value * scale + offset) / divisor;
     }
 
     /**
      * Applies the linear conversion on the given value. This method uses {@link BigDecimal} arithmetic if
      * the given value is an instance of {@code BigDecimal}, or IEEE 754 floating-point arithmetic otherwise.
      *
-     * <p>This method is inefficient. Apache SIS rarely uses {@link BigDecimal} arithmetic, so providing an
-     * efficient implementation of this method is currently not a goal (this decision may be revisited in a
-     * future SIS version if the need for {@code BigDecimal} arithmetic increase).</p>
+     * <p>Apache SIS rarely uses {@link BigDecimal} arithmetic, so providing an efficient implementation of
+     * this method is not a goal.</p>
      */
     @Override
     public Number convert(Number value) {
         ArgumentChecks.ensureNonNull("value", value);
-        if (value instanceof BigDecimal) {
-            if (scale != 1) {
-                value = ((BigDecimal) value).multiply(BigDecimal.valueOf(scale));
-            }
-            if (offset != 0) {
-                value = ((BigDecimal) value).add(BigDecimal.valueOf(offset));
+        if (!isIdentity()) {
+            if (value instanceof BigInteger) {
+                value = new BigDecimal((BigInteger) value);
             }
-        } else if (!isIdentity()) {
-            final double x;
-            if (value instanceof Float) {
-                // Because unit conversion factors are usually defined in base 10.
-                x = DecimalFunctions.floatToDouble((Float) value);
+            if (value instanceof BigDecimal) {
+                BigDecimal scale10  = this.scale10;
+                BigDecimal offset10 = this.offset10;
+                if (scale10 == null || offset10 == null) {
+                    final BigDecimal divisor = BigDecimal.valueOf(this.divisor);
+                    scale10  = BigDecimal.valueOf(scale) .divide(divisor);
+                    offset10 = BigDecimal.valueOf(offset).divide(divisor);
+                    this.scale10  = scale10;            // Volatile fields
+                    this.offset10 = offset10;
+                }
+                value = ((BigDecimal) value).multiply(scale10).add(offset10);
             } else {
-                x = value.doubleValue();
+                final double x;
+                if (value instanceof Float) {
+                    // Because unit conversion factors are usually defined in base 10.
+                    x = DecimalFunctions.floatToDouble((Float) value);
+                } else {
+                    x = value.doubleValue();
+                }
+                value = convert(x);
             }
-            value = convert(x);
         }
         return value;
     }
@@ -271,12 +341,24 @@ final class LinearConverter extends Abst
      */
     @Override
     public double derivative(double value) {
-        return scale;
+        return scale / divisor;
     }
 
     /**
      * Concatenates this converter with another converter. The resulting converter is equivalent to first converting
-     * by the specified converter (right converter), and then converting by this converter (left converter).
+     * by the specified converter (right converter), and then converting by this converter (left converter).  In the
+     * following equations, the 1 subscript is for the specified converter and the 2 subscript is for this converter:
+     *
+     * {@preformat math
+     *    t = (x⋅scale₁ + offset₁) ∕ divisor₁
+     *    y = (t⋅scale₂ + offset₂) ∕ divisor₂
+     * }
+     *
+     * We rewrite as:
+     *
+     * {@preformat math
+     *    y = (x⋅scale₁⋅scale₂ + offset₁⋅scale₂ + divisor₁⋅offset₂) ∕ (divisor₁⋅divisor₂)
+     * }
      */
     @Override
     public UnitConverter concatenate(final UnitConverter converter) {
@@ -287,22 +369,43 @@ final class LinearConverter extends Abst
         if (isIdentity()) {
             return converter;
         }
-        final double otherScale, otherOffset;
+        double otherScale, otherOffset, otherDivisor;
         if (converter instanceof LinearConverter) {
-            otherScale  = ((LinearConverter) converter).scale;
-            otherOffset = ((LinearConverter) converter).offset;
+            final LinearConverter lc = (LinearConverter) converter;
+            otherScale   = lc.scale;
+            otherOffset  = lc.offset;
+            otherDivisor = lc.divisor;
         } else if (converter.isLinear()) {
             /*
              * Fallback for foreigner implementations. Note that 'otherOffset' should be restricted to zero
              * according JSR-363 definition of 'isLinear()', but let be safe; maybe we are not the only one
              * to have a different interpretation about the meaning of "linear".
              */
-            otherOffset = converter.convert(0.0);
-            otherScale  = converter.convert(1.0) - otherOffset;
+            otherOffset  = converter.convert(0.0);
+            otherScale   = converter.convert(1.0) - otherOffset;
+            otherDivisor = 1;
         } else {
             return new ConcatenatedConverter(converter, this);
         }
-        return create(otherScale * scale, otherOffset * scale + offset);
+        otherScale   *= scale;
+        otherOffset   = otherOffset * scale + otherDivisor * offset;
+        otherDivisor *= divisor;
+        /*
+         * Following loop is a little bit similar to simplifying a fraction, but checking only for the
+         * powers of 10 since unit conversions are often such values. Algorithm is not very efficient,
+         * but the loop should not be executed often.
+         */
+        if (otherScale != 0 || otherOffset != 0 || otherDivisor != 0) {
+            double cf, f = 1;
+            do {
+                cf = f;
+                f *= 10;
+            } while (otherScale % f == 0 && otherOffset % f == 0 && otherDivisor % f == 0);
+            otherScale   /= cf;
+            otherOffset  /= cf;
+            otherDivisor /= cf;
+        }
+        return create(otherScale, otherOffset, otherDivisor);
     }
 
     /**
@@ -318,7 +421,9 @@ final class LinearConverter extends Abst
      */
     @Override
     public int hashCode() {
-        return Numerics.hashCode((Double.doubleToLongBits(scale) + 31*Double.doubleToLongBits(offset)) ^ serialVersionUID);
+        return Numerics.hashCode(Double.doubleToLongBits(scale)
+                         + 31 * (Double.doubleToLongBits(offset)
+                         + 37 *  Double.doubleToLongBits(divisor)));
     }
 
     /**
@@ -328,12 +433,24 @@ final class LinearConverter extends Abst
     public boolean equals(final Object other) {
         if (other instanceof LinearConverter) {
             final LinearConverter o = (LinearConverter) other;
-            return Numerics.equals(scale, o.scale) && Numerics.equals(offset, o.offset);
+            return Numerics.equals(scale,   o.scale)  &&
+                   Numerics.equals(offset,  o.offset) &&
+                   Numerics.equals(divisor, o.divisor);
         }
         return false;
     }
 
     /**
+     * Returns {@code true} if the given converter perform the same conversion than this converter,
+     * except for rounding errors.
+     */
+    boolean equivalent(final LinearConverter other) {
+        double r;
+        return Math.abs((r = scale  * other.divisor) - other.scale  * divisor) <= Math.ulp(r) &&
+               Math.abs((r = offset * other.divisor) - other.offset * divisor) <= Math.ulp(r);
+    }
+
+    /**
      * Returns a string representation of this converter for debugging purpose.
      * This string representation may change in any future SIS release.
      * Current format is of the form "y = scale⋅x + offset".
@@ -342,12 +459,20 @@ final class LinearConverter extends Abst
     @Override
     public String toString() {
         final StringBuilder buffer = new StringBuilder().append("y = ");
+        if (offset != 0) {
+            buffer.append('(');
+        }
         if (scale != 1) {
-            buffer.append(scale).append('⋅');
+            StringBuilders.trimFractionalPart(buffer.append(scale));
+            buffer.append('⋅');
         }
         buffer.append('x');
         if (offset != 0) {
-            buffer.append(" + ").append(offset);
+            StringBuilders.trimFractionalPart(buffer.append(" + ").append(offset));
+            buffer.append(')');
+        }
+        if (divisor != 1) {
+            StringBuilders.trimFractionalPart(buffer.append('∕').append(divisor));
         }
         return buffer.toString();
     }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -69,7 +69,7 @@ final class SystemUnit<Q extends Quantit
      * @param  dimension  the unit dimension.
      * @param  symbol     the unit symbol, or {@code null} if this unit has no specific symbol.
      * @param  scope      {@link UnitRegistry#SI}, {@link UnitRegistry#ACCEPTED}, other constants or 0 if unknown.
-     * @param  epsg       the EPSG code,   or 0 if this unit has no EPSG code.
+     * @param  epsg       the EPSG code, or 0 if this unit has no EPSG code.
      */
     SystemUnit(final Class<Q> quantity, final UnitDimension dimension, final String symbol, final byte scope, final short epsg) {
         super(symbol, scope, epsg);
@@ -335,7 +335,15 @@ final class SystemUnit<Q extends Quantit
     @Override
     @SuppressWarnings("unchecked")
     public Unit<Q> alternate(final String symbol) {
-        ArgumentChecks.ensureNonNull("symbol", symbol);
+        ArgumentChecks.ensureNonEmpty("symbol", symbol);
+        for (int i=0; i < symbol.length();) {
+            final int c = symbol.codePointAt(i);
+            if (!isSymbolChar(c)) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalCharacter_2,
+                        "symbol", String.valueOf(Character.toChars(c))));
+            }
+            i += Character.charCount(c);
+        }
         if (symbol.equals(getSymbol())) {
             return this;
         }
@@ -346,13 +354,13 @@ final class SystemUnit<Q extends Quantit
              * in read-only mode when 'quantity' is null because we would be unable to guarantee that
              * the parameterized type <Q> is correct.
              */
-            final Unit<?> existing = (Unit<?>) UnitRegistry.putIfAbsent(symbol, alt);
+            final Object existing = UnitRegistry.putIfAbsent(symbol, alt);
             if (existing != null) {
-                if (existing instanceof SystemUnit<?>
-                        && ((SystemUnit<?>) existing).quantity == quantity
-                        && dimension.equals(existing.getDimension()))
-                {
-                    return (Unit<Q>) existing;
+                if (existing instanceof SystemUnit<?>) {
+                    final SystemUnit<?> unit = (SystemUnit<?>) existing;
+                    if (quantity.equals(unit.quantity) && dimension.equals(unit.dimension)) {
+                        return (SystemUnit<Q>) unit;
+                    }
                 }
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, symbol));
             }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -63,7 +63,10 @@ import org.apache.sis.util.collection.We
  * opposite sign. It is caller responsibility to handle the direction of axes associated to NetCDF units.
  *
  * <div class="section">Multi-threading</div>
- * {@code UnitFormat} is not thread-safe. Synchronization, if desired, is caller's responsibility.
+ * {@code UnitFormat} is generally not thread-safe.
+ * However if there is no call to any setter method or to {@link #label(Unit, String)} after construction,
+ * then the {@link #parse(CharSequence)} and {@link #format(Unit)} methods can be invoked concurrently in
+ * different threads.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.8
@@ -79,6 +82,13 @@ public class UnitFormat extends Format i
     private static final long serialVersionUID = -3064428584419360693L;
 
     /**
+     * The SI "“deca” prefix. This is the only SI prefix encoded on two letters instead than one.
+     * It can be represented by the CJK compatibility character “㍲”, but use of those characters
+     * is generally not recommended outside of Chinese, Japanese or Korean texts.
+     */
+    static final String DECA = "da";
+
+    /**
      * The default instance used by {@link Units#valueOf(String)} for parsing units of measurement.
      * While {@code UnitFormat} is generally not thread-safe, this particular instance is safe if
      * we never invoke any setter method.
@@ -284,6 +294,8 @@ public class UnitFormat extends Format i
      * instructs this formatter to use the “meter” spelling instead of “metre”.
      *
      * @param  locale  the new locale for this {@code UnitFormat}.
+     *
+     * @see UnitServices#getUnitFormat(String)
      */
     public void setLocale(final Locale locale) {
         ArgumentChecks.ensureNonNull("locale", locale);
@@ -328,7 +340,10 @@ public class UnitFormat extends Format i
      * If the specified label is already associated to another unit, then the previous association is discarded.
      *
      * <p>The given label must be non-empty and can not ends with a digit, since such digit would be confused
-     * with unit power.</p>
+     * with unit power. Current implementation does not put additional restrictions. However if the label will
+     * be used as a {@linkplain AbstractUnit#getSymbol() unit symbol} (as opposed to {@link AbstractUnit#getName()
+     * unit name}), then we recommend to restrict the characters to {@linkplain Character#isLetter(int) letters}
+     * and {@linkplain Characters#isSubScript(int) subscripts}.</p>
      *
      * @param  unit   the unit being labeled.
      * @param  label  the new label for the given unit.
@@ -336,7 +351,7 @@ public class UnitFormat extends Format i
      */
     @Override
     public void label(final Unit<?> unit, String label) {
-        ArgumentChecks.ensureNonNull("unit",  unit);
+        ArgumentChecks.ensureNonNull ("unit", unit);
         label = CharSequences.trimWhitespaces(label);
         ArgumentChecks.ensureNonEmpty("label", label);
         int c = Character.codePointBefore(label, label.length());
@@ -383,8 +398,7 @@ public class UnitFormat extends Format i
      * Returns the mapping from long localized and unlocalized names to unit instances.
      * This mapping is somewhat the converse of {@link #symbolToName()}, but includes
      * international and American spelling of unit names in addition of localized names.
-     * The intend is to recognize "meter" as well as "metre" (together with, for example,
-     * "mètre" if and only if the locale language is French).
+     * The intend is to recognize "meter" as well as "metre".
      *
      * <p>While we said that {@code UnitFormat} is not thread safe, we make an exception for this method
      * for allowing the singleton {@link #INSTANCE} to parse symbols in a multi-threads environment.</p>
@@ -438,7 +452,7 @@ public class UnitFormat extends Format i
      */
     private static void copy(final Locale locale, final ResourceBundle symbolToName, final Map<String,Unit<?>> nameToUnit) {
         for (final String symbol : symbolToName.keySet()) {
-            nameToUnit.put(symbolToName.getString(symbol).toLowerCase(locale).intern(), Units.get(symbol));
+            nameToUnit.put(CharSequences.toASCII(symbolToName.getString(symbol).toLowerCase(locale)).toString().intern(), Units.get(symbol));
         }
     }
 
@@ -713,6 +727,7 @@ public class UnitFormat extends Format i
      * @see Units#valueOf(String)
      */
     @Override
+    @SuppressWarnings("null")
     public Unit<?> parse(final CharSequence symbols) throws ParserException {
         String uom = CharSequences.trimWhitespaces(symbols).toString();
         /*
@@ -740,12 +755,60 @@ public class UnitFormat extends Format i
             }
         }
         /*
+         * Split the unit around the multiplication and division operators and parse each term individually.
+         */
+        int offset    = 0;                  // Index of the first character of the next unit term to parse.
+        int operation = 0;                  // 1 = multiplication,  2 = division.
+        Unit<?> unit  = null;
+        final int length = uom.length();
+        for (int i=0; i<length; i++) {
+            final char c = uom.charAt(i);   // No need to use code points because we search characters in BMP.
+            final int next;
+            switch (c) {
+                case '.':
+                case '⋅': next = 1; break;
+                case '/':
+                case '∕': next = 2; break;
+                default:  continue;
+            }
+            final Unit<?> term = parseSymbol(CharSequences.trimWhitespaces(uom, offset, i).toString(), symbols, offset);
+            switch (operation) {
+                case 0:  unit = term; break;
+                case 1:  unit = unit.multiply(term); break;
+                case 2:  unit = unit.divide(term); break;
+                default: throw new AssertionError(operation);
+            }
+            operation = next;
+            offset = i+1;
+        }
+        final Unit<?> term = parseSymbol(CharSequences.trimWhitespaces(uom, offset, length).toString(), symbols, offset);
+        switch (operation) {
+            case 0:  unit = term; break;
+            case 1:  unit = unit.multiply(term); break;
+            case 2:  unit = unit.divide(term); break;
+            default: throw new AssertionError(operation);
+        }
+        return unit;
+    }
+
+    /**
+     * Parses a single unit symbol with its exponent.
+     * The given symbol shall not contain multiplication or division operator.
+     *
+     * @param  uom      the single unit symbol to parse.
+     * @param  symbols  the complete string specified by the user, used for error reporting.
+     * @param  offset   index of {@code uom} in the {@code symbols} string, used for error reporting.
+     * @return the parsed unit symbol (never {@code null}).
+     * @throws ParserException if a problem occurred while parsing the given symbols.
+     */
+    private Unit<?> parseSymbol(final String uom, final CharSequence symbols, final int offset) throws ParserException {
+        /*
          * Check for labels explicitly given by users. Those labels have precedence over the Apache SIS hard-coded
          * symbols. If no explicit label was found, check for symbols and names known to this UnitFormat instance.
          */
         Unit<?> unit = labelToUnit.get(uom);
         if (unit == null) {
-            unit = withPrefix(uom);
+            unit = getPrefixed(uom);
             if (unit == null) {
                 final int length = uom.length();
                 if (length == 0) {
@@ -777,7 +840,7 @@ public class UnitFormat extends Format i
                                 } catch (NumberFormatException e) {
                                     // Should never happen unless the number is larger than 'int' capacity.
                                     throw (ParserException) new ParserException(Errors.format(
-                                            Errors.Keys.UnknownUnit_1, uom), symbols, i).initCause(e);
+                                            Errors.Keys.UnknownUnit_1, uom), symbols, offset+i).initCause(e);
                                 }
                                 canApply = true;
                                 break;
@@ -785,8 +848,7 @@ public class UnitFormat extends Format i
                         } while (i != 0);
                     }
                     if (canApply) {
-                        uom = CharSequences.trimWhitespaces(uom.substring(0, i));
-                        unit = withPrefix(uom);
+                        unit = getPrefixed(CharSequences.trimWhitespaces(uom, 0, i).toString());
                         if (unit != null) {
                             return unit.pow(power);
                         }
@@ -817,13 +879,13 @@ public class UnitFormat extends Format i
                  * appear in numerous places.
                  */
                 String lc = uom.replace('_', ' ').toLowerCase(locale);
-                lc = CharSequences.replace(CharSequences.replace(CharSequences.replace(lc,
+                lc = CharSequences.replace(CharSequences.replace(CharSequences.replace(CharSequences.toASCII(lc),
                         "meters",  "meter"),
                         "metres",  "metre"),
                         "degrees", "degree").toString();
                 unit = nameToUnit().get(lc);
                 if (unit == null) {
-                    throw new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, 0);
+                    throw new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, offset);
                 }
             }
         }
@@ -835,7 +897,7 @@ public class UnitFormat extends Format i
      * This method does not perform any arithmetic operation on {@code Unit}.
      * Returns {@code null} if no unit is found.
      */
-    private static Unit<?> withPrefix(final String uom) {
+    private static Unit<?> getPrefixed(final String uom) {
         Unit<?> unit = Units.get(uom);
         if (unit == null && uom.length() >= 2) {
             int s = 1;
@@ -850,7 +912,7 @@ public class UnitFormat extends Format i
                 if (c != null) {
                     String symbol = unit.getSymbol();
                     if (prefix == '㍲') {
-                        symbol = "da" + symbol;
+                        symbol = DECA + symbol;
                     } else {
                         symbol = prefix + symbol;
                     }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java?rev=1766833&r1=1766832&r2=1766833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitRegistry.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -55,21 +55,18 @@ final class UnitRegistry implements Syst
 
     /**
      * Identifies units defined outside the SI system but accepted for use with SI.
-     * The {@link #SI} value can be used as a bitmask for identifying the SI or accepted units.
      */
-    static final byte ACCEPTED = 3;
-
-    // All following constants shall have an even value (unless accepted for use with SI).
+    static final byte ACCEPTED = 2;
 
     /**
      * Identifies units defined for use in British imperial system.
      */
-    static final byte IMPERIAL = 2;
+    static final byte IMPERIAL = 4;
 
     /**
      * Identifies units defined in another system than the above.
      */
-    static final byte OTHER = 4;
+    static final byte OTHER = 8;
 
     /**
      * All {@link UnitDimension}, {@link SystemUnit} or {@link ConventionalUnit} that are hard-coded in Apache SIS.
@@ -180,6 +177,17 @@ final class UnitRegistry implements Syst
     }
 
     /**
+     * Name of this system of units.
+     */
+    final String name;
+
+    /**
+     * The bitmask for units to include. Can be any combination of {@link #SI}, {@link #ACCEPTED},
+     * {@link #IMPERIAL} or {@link #OTHER} bits.
+     */
+    private final int includes;
+
+    /**
      * The value returned by {@link #getUnits()}, created when first needed.
      */
     private transient Set<Unit<?>> units;
@@ -187,16 +195,17 @@ final class UnitRegistry implements Syst
     /**
      * Creates a new unit system.
      */
-    UnitRegistry() {
+    UnitRegistry(final String name, final int includes) {
+        this.name     = name;
+        this.includes = includes;
     }
 
     /**
-     * Returns the well-known acronym that stands for "Système International"
-     * together with the name of other systems used.
+     * Returns the name of this system of units.
      */
     @Override
     public String getName() {
-        return "SI and others";
+        return name;
     }
 
     /**
@@ -220,8 +229,11 @@ final class UnitRegistry implements Syst
                 if (units == null) {
                     units = new HashSet<>();
                     for (final Object value : HARD_CODED.values()) {
-                        if (value instanceof Unit<?>) {
-                            units.add((Unit<?>) value);
+                        if (value instanceof AbstractUnit<?>) {
+                            final AbstractUnit<?> unit = (AbstractUnit<?>) value;
+                            if ((unit.scope & includes) != 0) {
+                                units.add(unit);
+                            }
                         }
                     }
                     units = Collections.unmodifiableSet(units);

Copied: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java (from r1766829, sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java?p2=sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java&p1=sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java&r1=1766829&r2=1766833&rev=1766833&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/UnitServices.java [UTF-8] Thu Oct 27 14:15:18 2016
@@ -116,7 +116,7 @@ public class UnitServices extends Servic
      */
     @Override
     public Collection<SystemOfUnits> getAvailableSystemsOfUnits() {
-        return UnmodifiableArrayList.wrap(systems);
+        return UnmodifiableArrayList.<SystemOfUnits>wrap(systems);
     }
 
     /**




Mime
View raw message