Author: desruisseaux
Date: Fri Apr 15 17:03:33 2016
New Revision: 1739336

URL: http://svn.apache.org/viewvc?rev=1739336&view=rev
Log:
Implement character escaping in StringJoinOperation.
Document that AbstractOperation.getDependencies() does not report transitive 
dependencies.
Implement hashCode() and equals(Object) in AbstractOperation subclasses.

Modified:
    
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
    
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
    
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
    
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Modified: 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
 [UTF-8] Fri Apr 15 17:03:33 2016
@@ -154,6 +154,9 @@ public abstract class AbstractOperation
 
     /**
      * Returns the names of feature properties that this operation needs for 
performing its task.
+     * This method does not resolve transitive dependencies, i.e. if a 
dependency is itself an operation having
+     * other dependencies, the returned set will contain the name of that 
operation but not the names of that
+     * operation dependencies (unless they are the same that the direct 
dependencies of {@code this}).
      *
      * <div class="note"><b>Rational:</b>
      * this information is needed for writing the {@code SELECT} SQL statement 
to send to a database server.
@@ -171,7 +174,7 @@ public abstract class AbstractOperation
 
     /**
      * Returns a hash code value for this operation.
-     * The default implementation computes a hash code from the {@linkplain 
#getParameters() parameters}
+     * The default implementation computes a hash code from the {@linkplain 
#getParameters() parameters descriptor}
      * and {@linkplain #getResult() result type}.
      *
      * @return {@inheritDoc}
@@ -183,7 +186,7 @@ public abstract class AbstractOperation
 
     /**
      * Compares this operation with the given object for equality.
-     * The default implementation compares the {@linkplain #getParameters() 
parameters}
+     * The default implementation compares the {@linkplain #getParameters() 
parameters descriptor}
      * and {@linkplain #getResult() result type}.
      *
      * @return {@inheritDoc}

Modified: 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
 [UTF-8] Fri Apr 15 17:03:33 2016
@@ -23,6 +23,7 @@ import org.opengis.referencing.crs.Coord
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.UnconvertibleObjectException;
+import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
@@ -52,22 +53,22 @@ import org.opengis.feature.PropertyType;
  *     <th>Returned by</th>
  *   </tr>
  *   <tr>
- *     <td>{@value org.apache.sis.feature.AbstractOperation#NAME_KEY}</td>
+ *     <td>{@value org.apache.sis.feature.AbstractIdentifiedType#NAME_KEY}</td>
  *     <td>{@link GenericName} or {@link String}</td>
  *     <td>{@link AbstractOperation#getName() Operation.getName()} 
(mandatory)</td>
  *   </tr>
  *   <tr>
- *     <td>{@value 
org.apache.sis.feature.AbstractOperation#DEFINITION_KEY}</td>
+ *     <td>{@value 
org.apache.sis.feature.AbstractIdentifiedType#DEFINITION_KEY}</td>
  *     <td>{@link InternationalString} or {@link String}</td>
  *     <td>{@link AbstractOperation#getDefinition() 
Operation.getDefinition()}</td>
  *   </tr>
  *   <tr>
- *     <td>{@value 
org.apache.sis.feature.AbstractOperation#DESIGNATION_KEY}</td>
+ *     <td>{@value 
org.apache.sis.feature.AbstractIdentifiedType#DESIGNATION_KEY}</td>
  *     <td>{@link InternationalString} or {@link String}</td>
  *     <td>{@link AbstractOperation#getDesignation() 
Operation.getDesignation()}</td>
  *   </tr>
  *   <tr>
- *     <td>{@value 
org.apache.sis.feature.AbstractOperation#DESCRIPTION_KEY}</td>
+ *     <td>{@value 
org.apache.sis.feature.AbstractIdentifiedType#DESCRIPTION_KEY}</td>
  *     <td>{@link InternationalString} or {@link String}</td>
  *     <td>{@link AbstractOperation#getDescription() 
Operation.getDescription()}</td>
  *   </tr>
@@ -110,6 +111,11 @@ import org.opengis.feature.PropertyType;
  */
 public final class FeatureOperations extends Static {
     /**
+     * The pool of operations or operation dependencies created so far, for 
sharing exiting instances.
+     */
+    static final WeakHashSet<PropertyType> POOL = new 
WeakHashSet<>(PropertyType.class);
+
+    /**
      * Do not allow instantiation of this class.
      */
     private FeatureOperations() {
@@ -150,7 +156,7 @@ public final class FeatureOperations ext
      */
     public static Operation link(final Map<String,?> identification, final 
PropertyType referent) {
         ArgumentChecks.ensureNonNull("referent", referent);
-        return new LinkOperation(identification, referent);
+        return POOL.unique(new LinkOperation(identification, referent));
     }
 
     /**
@@ -158,14 +164,21 @@ public final class FeatureOperations ext
      * This operation can be used for creating a <cite>compound key</cite> as 
a {@link String} that consists
      * of two or more attribute values that uniquely identify a feature 
instance.
      *
-     * <p>The {@code delimiter}, {@code prefix} and {@code suffix} arguments 
given to this method are used in
-     * the same way than {@link java.util.StringJoiner}. Null prefix, suffix 
and property values are handled
-     * as if they were empty strings.</p>
-     *
-     * <div class="section">Restrictions</div>
-     * The single properties can be either attributes or operations that 
produce attributes;
-     * feature associations are not allowed.
-     * Furthermore each attribute shall contain at most one value; 
multi-valued attributes are not allowed.
+     * <p>The {@code delimiter}, {@code prefix} and {@code suffix} arguments 
given to this method
+     * are used in the same way than {@link java.util.StringJoiner}, except 
for null values.
+     * Null prefix, suffix and property values are handled as if they were 
empty strings.</p>
+     *
+     * <p>If the same character sequences than the given delimiter appears in 
a property value,
+     * the {@code '\'} escape character will be inserted before that sequence.
+     * If the {@code '\'} character appears in a property value, it will be 
doubled.</p>
+     *
+     * <p><b>Restrictions:</b></p>
+     * <ul>
+     *   <li>The single properties can be either attributes or operations that 
produce attributes;
+     *       feature associations are not allowed.</li>
+     *   <li>Each attribute shall contain at most one value; multi-valued 
attributes are not allowed.</li>
+     *   <li>The delimiter can not contain the {@code '\'} escape 
character.</li>
+     * </ul>
      *
      * <div class="section">Read/write behavior</div>
      * This operation supports both reading and writing. When setting a value 
on the attribute created by this
@@ -191,6 +204,10 @@ public final class FeatureOperations ext
             throws UnconvertibleObjectException
     {
         ArgumentChecks.ensureNonEmpty("delimiter", delimiter);
+        if (delimiter.indexOf(StringJoinOperation.ESCAPE) >= 0) {
+            throw new 
IllegalArgumentException(Errors.getResources(identification).getString(
+                    Errors.Keys.IllegalCharacter_2, "delimiter", 
StringJoinOperation.ESCAPE));
+        }
         ArgumentChecks.ensureNonNull("singleAttributes", singleAttributes);
         switch (singleAttributes.length) {
             case 0: {
@@ -204,7 +221,7 @@ public final class FeatureOperations ext
                 break;
             }
         }
-        return new StringJoinOperation(identification, delimiter, prefix, 
suffix, singleAttributes);
+        return POOL.unique(new StringJoinOperation(identification, delimiter, 
prefix, suffix, singleAttributes));
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
 [UTF-8] Fri Apr 15 17:03:33 2016
@@ -119,9 +119,6 @@ final class LinkOperation extends Abstra
      */
     @Override
     public Set<String> getDependencies() {
-        if (result instanceof AbstractOperation) {
-            return ((AbstractOperation) result).getDependencies();
-        }
         return Collections.singleton(referentName);
     }
 
@@ -137,4 +134,21 @@ final class LinkOperation extends Abstra
         ArgumentChecks.ensureNonNull("feature", feature);
         return feature.getProperty(referentName);
     }
+
+    /**
+     * Computes a hash-code value for this operation.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + referentName.hashCode();
+    }
+
+    /**
+     * Compares this operation with the given object for equality.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        // 'this.result' is compared (indirectly) by the super class.
+        return super.equals(obj) && referentName.equals(((LinkOperation) 
obj).referentName);
+    }
 }

Modified: 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
 [UTF-8] Fri Apr 15 17:03:33 2016
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
 import org.opengis.parameter.ParameterDescriptorGroup;
@@ -27,9 +28,11 @@ import org.apache.sis.util.ObjectConvert
 import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.UnconvertibleObjectException;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Classes;
 
 // Branch-dependent imports
+import java.util.Objects;
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.Feature;
 import org.opengis.feature.IdentifiedType;
@@ -62,6 +65,11 @@ final class StringJoinOperation extends
     private static final long serialVersionUID = 2303047827010821381L;
 
     /**
+     * The character used for escaping occurrences of the delimiter inside a 
value.
+     */
+    static final char ESCAPE = '\\';
+
+    /**
      * The parameter descriptor for the "String join" operation, which does 
not take any parameter.
      */
     private static final ParameterDescriptorGroup EMPTY_PARAMS = 
LinkOperation.parameters("StringJoin", 1);
@@ -96,17 +104,17 @@ final class StringJoinOperation extends
     /**
      * The characters to use at the beginning of the concatenated string, or 
an empty string if none.
      */
-    private final String prefix;
+    final String prefix;
 
     /**
      * The characters to use at the end of the concatenated string, or an 
empty string if none.
      */
-    private final String suffix;
+    final String suffix;
 
     /**
      * The characters to use a delimiter between each single attribute value.
      */
-    private final String delimiter;
+    final String delimiter;
 
     /**
      * Creates a new operation for string concatenations using the given 
prefix, suffix and delimeter.
@@ -124,6 +132,12 @@ final class StringJoinOperation extends
         attributeNames = new String[singleAttributes.length];
         converters = new ObjectConverter[singleAttributes.length];
         for (int i=0; i < singleAttributes.length; i++) {
+            /*
+             * Verify the following conditions:
+             *   - property types are non-null.
+             *   - properties are either attributes, or operations producing 
attributes.
+             *   - attributes contain at most one value (no collections).
+             */
             IdentifiedType attributeType = singleAttributes[i];
             ArgumentChecks.ensureNonNullElement("singleAttributes", i, 
attributeType);
             final GenericName name = attributeType.getName();
@@ -139,10 +153,15 @@ final class StringJoinOperation extends
                 throw new 
IllegalArgumentException(Errors.getResources(identification)
                         .getString(Errors.Keys.NotASingleton_1, name));
             }
-            converters[i] = ObjectConverters.find(String.class, 
((AttributeType<?>) attributeType).getValueClass());
+            /*
+             * StringJoinOperation does not need to keep the AttributeType 
references.
+             * We need only their names and how to convert from String to 
their values.
+             */
             attributeNames[i] = name.toString();
+            converters[i] = ObjectConverters.find(String.class, 
((AttributeType<?>) attributeType).getValueClass());
         }
-        resultType = new 
DefaultAttributeType<>(resultIdentification(identification), String.class, 1, 
1, null);
+        resultType = FeatureOperations.POOL.unique(new DefaultAttributeType<>(
+                resultIdentification(identification), String.class, 1, 1, 
null));
         this.delimiter = delimiter;
         this.prefix = (prefix == null) ? "" : prefix;
         this.suffix = (suffix == null) ? "" : suffix;
@@ -188,44 +207,11 @@ final class StringJoinOperation extends
      * @param converter  the converter to use for formatting the given value.
      * @param value      the value to format, or {@code null}.
      */
-    private static <S> Object format(final ObjectConverter<S,?> converter, 
final Object value) {
+    static <S> Object format(final ObjectConverter<S,?> converter, final 
Object value) {
         return converter.apply(converter.getSourceClass().cast(value));
     }
 
     /**
-     * Creates a value as the concatenation of the attributes read from the 
given feature.
-     *
-     * @param  feature  the feature from which to read the attributes.
-     * @return the concatenated string.
-     * @throws UnconvertibleObjectException if one of the attribute value is 
not of the expected type.
-     */
-    final String join(final Feature feature) throws 
UnconvertibleObjectException {
-        final StringBuilder sb = new StringBuilder();
-        String sep = prefix;
-        String name  = null;
-        Object value = null;
-        try {
-            for (int i=0; i < attributeNames.length; i++) {
-                name  = attributeNames[i];
-                value = feature.getPropertyValue(name);                 // 
Used in 'catch' block in case of exception.
-                value = format(converters[i].inverse(), value);
-                sb.append(sep);
-                if (value != null) {
-                    sb.append(value);
-                }
-                sep = delimiter;
-            }
-        } catch (ClassCastException e) {
-            if (value == null) {
-                throw e;
-            }
-            throw new UnconvertibleObjectException(Errors.format(
-                    Errors.Keys.IllegalPropertyValueClass_2, name, 
value.getClass(), e));
-        }
-        return sb.append(suffix).toString();
-    }
-
-    /**
      * Returns the concatenation of property values of the given feature.
      *
      * @param  feature     the feature on which to execute the operation.
@@ -238,6 +224,9 @@ final class StringJoinOperation extends
         return new Result(feature);
     }
 
+
+
+
     /**
      * The attributes that contains the result of concatenating the string 
representation of other attributes.
      * Value is calculated each time it is accessed.
@@ -264,57 +253,167 @@ final class StringJoinOperation extends
         /**
          * Creates a string which is the concatenation of attribute values of 
all properties
          * specified to the {@link StringJoinOperation} constructor.
+         *
+         * @return the concatenated string.
+         * @throws UnconvertibleObjectException if one of the attribute values 
is not of the expected type.
          */
         @Override
-        public String getValue() {
-            return join(feature);
+        public String getValue() throws UnconvertibleObjectException {
+            final StringBuilder sb = new StringBuilder();
+            String sep = prefix;
+            String name  = null;
+            Object value = null;
+            try {
+                for (int i=0; i < attributeNames.length; i++) {
+                    name  = attributeNames[i];
+                    value = feature.getPropertyValue(name);                 // 
Used in 'catch' block in case of exception.
+                    value = format(converters[i].inverse(), value);
+                    sb.append(sep);
+                    sep = delimiter;
+                    if (value != null) {
+                        /*
+                         * First insert the value, then substitute in-place 
all occurrences of "\" by "\\"
+                         * then all occurence of the delimiter by "\" followed 
by the delimiter.
+                         */
+                        final int startAt = sb.length();
+                        int j = sb.append(value).length();
+                        while (--j >= startAt) {
+                            if (sb.charAt(j) == ESCAPE) {
+                                sb.insert(j, ESCAPE);
+                            }
+                        }
+                        j = startAt;
+                        while ((j = sb.indexOf(sep, j)) >= 0) {
+                            sb.insert(j, ESCAPE);
+                            j += sep.length() + 1;
+                        }
+                    }
+                }
+            } catch (ClassCastException e) {
+                if (value == null) {
+                    throw e;
+                }
+                throw new UnconvertibleObjectException(Errors.format(
+                        Errors.Keys.IllegalPropertyValueClass_2, name, 
value.getClass(), e));
+            }
+            return sb.append(suffix).toString();
         }
 
         /**
          * Given a concatenated string as produced by {@link #getValue()}, 
separates the components around
-         * the separator and forward the values to the original attributes.
+         * the separator and forward the values to the original attributes. If 
one of the values can not be
+         * parsed, then this method does not store any property value ("all or 
nothing" behavior).
+         *
+         * @param  value  the concatenated string.
+         * @throws UnconvertibleObjectException if one of the attribute values 
can not be parsed to the expected type.
          */
         @Override
-        public void setValue(String value) {
-            //check prefix
-            if (!value.startsWith(prefix)) {
-                throw new InvalidPropertyValueException("Unvalid string, does 
not start with "+prefix);
-            }
-            if (!value.endsWith(suffix)) {
-                throw new InvalidPropertyValueException("Unvalid string, does 
not end with "+suffix);
+        public void setValue(final String value) throws 
UnconvertibleObjectException {
+            final int endAt = value.length() - suffix.length();
+            final boolean prefixMatches = value.startsWith(prefix);
+            if (!prefixMatches || !value.endsWith(suffix)) {
+                throw new 
InvalidPropertyValueException(Errors.format(Errors.Keys.UnexpectedCharactersAtBound_4,
+                        getName(),
+                        prefixMatches ? 1 : 0,              // For 
"{1,choice,0#begin|1#end}" in message format.
+                        prefixMatches ? suffix : prefix,
+                        prefixMatches ? CharSequences.token(value, 0) : 
value.substring(Math.max(0, endAt))));
             }
-
-            //split values, we don't use the regex split to avoid possible 
reserverd regex characters
-            final String[] values = new String[attributeNames.length];
-            int i = 0;
-            int offset = 0;
-            //remove prefix and suffix
-            value = value.substring(prefix.length(), value.length() - 
suffix.length());
-            while (true) {
-                if (i >= values.length) {
-                    throw new InvalidPropertyValueException("Unvalid string, 
expected "+values.length+" values, but found more");
-                }
-                final int idx = value.indexOf(delimiter, offset);
-                if (idx < 0) {
-                    //last element
-                    values[i++] = value.substring(offset);
-                    break;
+            /*
+             * We do not use the regex split for avoiding possible reserved 
regex characters,
+             * and also for processing directly escaped delimiters. We convert 
the values as we
+             * read them (no need to store the substrings) but do not store 
them in the properties
+             * before we succeeded to parse all values, so we have a "all or 
nothing" behavior.
+             */
+            final Object[] values = new Object[attributeNames.length];
+            int lower = prefix.length();
+            int upper = lower;
+            int count = 0;
+            boolean done = false;
+            do {
+                upper = value.indexOf(delimiter, upper);
+                if (upper >= 0 && upper < endAt) {
+                    /*
+                     * If an odd number of escape characters exist before the 
delimiter, remove the last
+                     * escape character and continue the search for the next 
delimiter.
+                     */
+                    int escape = upper;
+                    while (escape != 0 && value.charAt(escape - 1) == ESCAPE) {
+                        escape--;
+                    }
+                    if (((upper - escape) & 1) != 0) {
+                        upper += delimiter.length() + 1;
+                        continue;
+                    }
                 } else {
-                    values[i++] = value.substring(offset, idx);
-                    offset = (idx + delimiter.length());
+                    upper = endAt;
+                    done = true;
+                }
+                /*
+                 * Get the value and remove all escape characters. Each escape 
character is either followed by another
+                 * escape character (that we need to keep) or the delimiter. 
The algorithm used here is inefficient
+                 * (we recreate a buffer for each character to remove), but we 
assume that it should be rarely needed.
+                 */
+                String element = value.substring(lower, upper);
+                for (int i=0; (i = element.indexOf(ESCAPE, i)) >= 0;) {
+                    element = new StringBuilder(element.length() - 1)
+                            .append(element, 0, i).append(element, i+1, 
element.length()).toString();
+                    if (i < element.length()) {
+                        if (element.indexOf(i) == ESCAPE) {
+                            i++;
+                        } else {
+                            assert element.regionMatches(i, delimiter, 0, 
delimiter.length()) : element;
+                            i += delimiter.length();
+                        }
+                    }
                 }
+                /*
+                 * Empty strings are considered as null values for consistency 
with StringJoinOperation.format(…).
+                 * If we have more values than expected, continue the parsing 
but without storing the values.
+                 * The intend is to get the correct count of values for error 
reporting.
+                 */
+                if (!element.isEmpty() && count < values.length) {
+                    values[count] = converters[count].apply(element);
+                }
+                count++;
+                upper += delimiter.length();
+                lower = upper;
+            } while (!done);
+            /*
+             * Store the values in the properties only after we successfully 
converted all of them,
+             * in order to have a "all or nothing" behavior.
+             */
+            if (values.length != count) {
+                throw new InvalidPropertyValueException(
+                        
Errors.format(Errors.Keys.UnexpectedNumberOfComponents_3, value, values.length, 
count));
             }
-
-            if (i != values.length) {
-                throw new InvalidPropertyValueException("Unvalid string, 
number of values do not match, found "+(i)+" but expected "+values.length);
+            for (int i=0; i < values.length; i++) {
+                feature.setPropertyValue(attributeNames[i], values[i]);
             }
+        }
+    }
 
-            //set values, convert them if necessary
-            for (int k=0; k < values.length; k++) {
-                final String propName = attributeNames[k];
-                final Object val = converters[k].apply(values[k]);
-                feature.setPropertyValue(propName, val);
-            }
+    /**
+     * Computes a hash-code value for this operation.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + Arrays.hashCode(attributeNames) + 37 * 
Objects.hash(delimiter, prefix, suffix);
+    }
+
+    /**
+     * Compares this operation with the given object for equality.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (super.equals(obj)) {
+            // 'this.result' is compared (indirectly) by the super class.
+            final StringJoinOperation that = (StringJoinOperation) obj;
+            return Arrays.equals(this.attributeNames, that.attributeNames) &&
+                   Arrays.equals(this.converters,     that.converters)     &&
+                  Objects.equals(this.delimiter,      that.delimiter)      &&
+                  Objects.equals(this.prefix,         that.prefix)         &&
+                  Objects.equals(this.suffix,         that.suffix);
         }
+        return false;
     }
 }

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
 [UTF-8] Fri Apr 15 17:03:33 2016
@@ -1001,6 +1001,11 @@ public final class Errors extends Indexe
         public static final short UnexpectedCharactersAfter_2 = 198;
 
         /**
+         * Text for ‘{0}’ was expected to {1,choice,0#begin|1#end} with “{2}”, 
but found “{3}”.
+         */
+        public static final short UnexpectedCharactersAtBound_4 = 225;
+
+        /**
          * Unexpected dimension for a coordinate system of type ‘{0}’.
          */
         public static final short UnexpectedDimensionForCS_1 = 212;
@@ -1021,6 +1026,11 @@ public final class Errors extends Indexe
         public static final short UnexpectedFileFormat_2 = 111;
 
         /**
+         * Expected {1} components in “{0}” but found {2}.
+         */
+        public static final short UnexpectedNumberOfComponents_3 = 226;
+
+        /**
          * Parameter “{0}” was not expected.
          */
         public static final short UnexpectedParameter_1 = 152;

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
 [ISO-8859-1] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
 [ISO-8859-1] Fri Apr 15 17:03:33 2016
@@ -211,10 +211,12 @@ UndefinedOrderingForElements_2    = Orde
 UnexpectedArrayLength_2           = Expected an array of length {0}, but got 
{1}.
 UnexpectedChange_1                = Unexpected change in \u2018{0}\u2019.
 UnexpectedCharactersAfter_2       = The \u201c{1}\u201d characters after 
\u201c{0}\u201d was unexpected.
+UnexpectedCharactersAtBound_4     = Text for \u2018{0}\u2019 was expected to 
{1,choice,0#begin|1#end} with \u201c{2}\u201d, but found \u201c{3}\u201d.
 UnexpectedDimensionForCS_1        = Unexpected dimension for a coordinate 
system of type \u2018{0}\u2019.
 UnexpectedEndOfFile_1             = Unexpected end of file while reading 
\u201c{0}\u201d.
 UnexpectedEndOfString_1           = More characters were expected at the end 
of \u201c{0}\u201d.
 UnexpectedFileFormat_2            = File \u201c{1}\u201d seems to be encoded 
in an other format than {0}.
+UnexpectedNumberOfComponents_3    = Expected {1} components in \u201c{0}\u201d 
but found {2}.
 UnexpectedParameter_1             = Parameter \u201c{0}\u201d was not expected.
 UnexpectedTypeForReference_3      = Expected \u201c{0}\u201d to reference an 
instance of \u2018{1}\u2019, but found an instance of \u2018{2}\u2019.
 UnexpectedValueInElement_2        = Unexpected value \u201c{1}\u201d in 
\u201c{0}\u201d element.

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1739336&r1=1739335&r2=1739336&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
 [ISO-8859-1] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
 [ISO-8859-1] Fri Apr 15 17:03:33 2016
@@ -207,9 +207,11 @@ UndefinedOrderingForElements_2    = L\u2
 UnexpectedArrayLength_2           = Un tableau de longueur {0} \u00e9tait 
attendu, mais le tableau re\u00e7u est de longueur {1}.
 UnexpectedChange_1                = Changement inattendu dans \u2018{0}\u2019.
 UnexpectedCharactersAfter_2       = Les caract\u00e8res 
\u00ab\u202f{1}\u202f\u00bb apr\u00e8s \u00ab\u202f{0}\u202f\u00bb sont 
inattendus.
+UnexpectedCharactersAtBound_4     = Le texte pour \u2018{0}\u2019 devait 
{1,choice,0#commencer|1#finir} par \u00ab\u202f{2}\u202f\u00bb, mais on a 
trouv\u00e9 \u00ab\u202f{3}\u202f\u00bb.
 UnexpectedDimensionForCS_1        = Dimension inattendue pour un syst\u00e8me 
de coordonn\u00e9es de type \u2018{0}\u2019.
 UnexpectedEndOfFile_1             = Fin de fichier inattendue lors de la 
lecture de \u00ab\u202f{0}\u202f\u00bb.
 UnexpectedEndOfString_1           = D\u2019autres caract\u00e8res \u00e9taient 
attendus \u00e0 la fin du texte \u00ab\u202f{0}\u202f\u00bb.
+UnexpectedNumberOfComponents_3    = Il y a {2} composantes dans 
\u00ab\u202f{0}\u202f\u00bb alors qu\u2019on en attendait {1}.
 UnexpectedFileFormat_2            = Le fichier \u00ab\u202f{1}\u202f\u00bb 
semble \u00eatre encod\u00e9 dans un autre format que {0}.
 UnexpectedParameter_1             = Le param\u00e8tre 
\u00ab\u202f{0}\u202f\u00bb est inattendu.
 UnexpectedTypeForReference_3      = L\u2019identifiant \u201c{0}\u201d 
r\u00e9f\u00e9rence une instance de \u2018{2}\u2019 alors qu\u2019on attendait 
une instance de \u2018{1}\u2019.


Reply via email to