You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/06/18 19:38:17 UTC
svn commit: r1686282 [1/4] - in /sis/trunk: ./
core/sis-feature/src/main/java/org/apache/sis/feature/
core/sis-feature/src/test/java/org/apache/sis/feature/
core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/
core/sis-metadata/src/main/ja...
Author: desruisseaux
Date: Thu Jun 18 17:38:16 2015
New Revision: 1686282
URL: http://svn.apache.org/r1686282
Log:
Merge from the JDK6 branch Feature bug fixes and partial WKT 2 work.
Added:
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
- copied unchanged from r1686280, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
- copied unchanged from r1686280, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
- copied unchanged from r1686280, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Warnings.java
- copied unchanged from r1686280, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Warnings.java
Removed:
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTParser.java
Modified:
sis/trunk/ (props changed)
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/mock/VerticalCRSMock.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractReferenceSystemTest.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultGeodeticDatumTest.java
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/Characters.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Jun 18 17:38:16 2015
@@ -1,4 +1,4 @@
/sis/branches/Android:1430670-1480699
-/sis/branches/JDK6:1394364-1684689
-/sis/branches/JDK7:1394913-1684688
-/sis/branches/JDK8:1584960-1684685
+/sis/branches/JDK6:1394364-1686280
+/sis/branches/JDK7:1394913-1686269
+/sis/branches/JDK8:1584960-1686266
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -41,7 +41,7 @@ import org.apache.sis.util.resources.Err
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*
* @see DefaultAssociationRole#newInstance()
@@ -134,7 +134,7 @@ public abstract class AbstractAssociatio
* @see AbstractFeature#getPropertyValue(String)
*/
@Override
- public abstract AbstractFeature getValue();
+ public abstract AbstractFeature getValue() throws IllegalStateException;
/**
* Returns all features, or an empty collection if none.
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -64,7 +64,7 @@ import org.apache.sis.internal.jdk7.JDK7
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*
* @see DefaultAttributeType#newInstance()
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -124,7 +124,7 @@ public abstract class AbstractFeature im
*
* @param name The property name.
* @return The property of the given name (never {@code null}).
- * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+ * @throws IllegalArgumentException if the given argument is not a property name of this feature.
*
* @see #getPropertyValue(String)
* @see DefaultFeatureType#getProperty(String)
@@ -155,8 +155,9 @@ public abstract class AbstractFeature im
* to {@code org.opengis.feature.Property}. This change is pending GeoAPI revision.</div>
*
* @param property The property to set.
- * @throws IllegalArgumentException if the type of the given property is not one of the types
- * known to this feature, or if the property can not be set of an other reason.
+ * @throws IllegalArgumentException if the name of the given property is not a property name of this feature.
+ * @throws IllegalArgumentException if the value of the given property is not valid.
+ * @throws IllegalArgumentException if the property can not be set for another reason.
*
* @see #setPropertyValue(String, Object)
*/
@@ -188,10 +189,9 @@ public abstract class AbstractFeature im
*
* @param name The name of the property to create.
* @return A {@code Property} of the given name.
- * @throws IllegalArgumentException If the given argument is not the name of an attribute or
+ * @throws IllegalArgumentException if the given argument is not the name of an attribute or
* feature association of this feature.
*/
- @SuppressWarnings({"unchecked","rawtypes"})
final Property createProperty(final String name) throws IllegalArgumentException {
final AbstractIdentifiedType pt = type.getProperty(name);
if (pt instanceof DefaultAttributeType<?>) {
@@ -257,7 +257,7 @@ public abstract class AbstractFeature im
*
* @param name The name of the property for which to get the default value.
* @return The default value for the {@code Property} of the given name.
- * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+ * @throws IllegalArgumentException if the given argument is not an attribute or association name of this feature.
*/
final Object getDefaultValue(final String name) throws IllegalArgumentException {
final AbstractIdentifiedType pt = type.getProperty(name);
@@ -303,7 +303,7 @@ public abstract class AbstractFeature im
*
* @param name The property name.
* @return The value for the given property, or {@code null} if none.
- * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+ * @throws IllegalArgumentException if the given argument is not an attribute or association name of this feature.
*
* @see AbstractAttribute#getValue()
*/
@@ -320,8 +320,9 @@ public abstract class AbstractFeature im
*
* @param name The attribute name.
* @param value The new value for the given attribute (may be {@code null}).
- * @throws ClassCastException If the value is not assignable to the expected value class.
- * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+ * @throws IllegalArgumentException if the given name is not an attribute or association name of this feature.
+ * @throws ClassCastException if the value is not assignable to the expected value class.
+ * @throws IllegalArgumentException if the given value is not valid for a reason other than its type.
*
* @see AbstractAttribute#setValue(Object)
*/
@@ -449,9 +450,11 @@ public abstract class AbstractFeature im
throw illegalPropertyType(base.getName(), property.getClass());
}
if (pt != base) {
- throw new IllegalArgumentException(base == null
- ? Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name)
- : Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+ if (base == null) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+ } else {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+ }
}
}
@@ -560,9 +563,9 @@ public abstract class AbstractFeature im
}
/**
- * Returns the exception for a property type which neither an attribute or an association.
+ * Returns the exception for a property type which is neither an attribute or an association.
* This method is invoked after a {@link PropertyType} has been found for the user-supplied name,
- * but that property can not be stored in a {@link Property} instance.
+ * but that property can not be stored in or extracted from a {@link Property} instance.
*/
static IllegalArgumentException unsupportedPropertyType(final GenericName name) {
return new IllegalArgumentException(Errors.format(Errors.Keys.CanNotInstantiate_1, name));
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -42,7 +42,7 @@ import org.apache.sis.internal.jdk7.Obje
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public class AbstractIdentifiedType implements Serializable {
@@ -169,9 +169,7 @@ public class AbstractIdentifiedType impl
* @param identification The name and other information to be given to this identified type.
* @throws IllegalArgumentException if a property has an invalid value.
*/
- protected AbstractIdentifiedType(final Map<String,?> identification)
- throws IllegalArgumentException
- {
+ protected AbstractIdentifiedType(final Map<String,?> identification) throws IllegalArgumentException {
ensureNonNull("identification", identification);
Object value = identification.get(NAME_KEY);
if (value == null) {
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -31,7 +31,7 @@ import org.apache.sis.internal.util.Abst
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
final class CharacteristicMap extends AbstractMap<String,AbstractAttribute<?>> implements Cloneable {
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -79,7 +79,7 @@ final class DenseFeature extends Abstrac
* @param name The property name.
* @return The index for the property of the given name,
* or a negative value if the property is a parameterless operation.
- * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+ * @throws IllegalArgumentException if the given argument is not a property name of this feature.
*/
private int getIndex(final String name) throws IllegalArgumentException {
final Integer index = indices.get(name);
@@ -127,7 +127,7 @@ final class DenseFeature extends Abstrac
*
* @param property The property to set.
* @throws IllegalArgumentException if the type of the given property is not one of the types
- * known to this feature.
+ * known to this feature, or if the property can not be set or another reason.
*/
@Override
public void setProperty(final Object property) throws IllegalArgumentException {
@@ -202,7 +202,7 @@ final class DenseFeature extends Abstrac
* @param name The attribute name.
* @param value The new value for the given attribute (may be {@code null}).
* @throws ClassCastException If the value is not assignable to the expected value class.
- * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+ * @throws IllegalArgumentException If the given value can not be assigned for another reason.
*/
@Override
public void setPropertyValue(final String name, Object value) throws IllegalArgumentException {
@@ -285,12 +285,36 @@ final class DenseFeature extends Abstrac
/**
* Returns a hash code value for this feature.
+ * This implementation computes the hash code using only the property values, not the {@code Property} instances,
+ * in order to keep the hash code value stable before and after the {@code properties} array is promoted from the
+ * {@code Object[]} type to the {@code Property[]} type.
*
* @return A hash code value.
*/
@Override
public int hashCode() {
- return type.hashCode() + 37 * Arrays.hashCode(properties);
+ int code = 1;
+ if (properties != null) {
+ if (properties instanceof Property[]) {
+ for (final Property p : (Property[]) properties) {
+ code = 31 * code;
+ final Object value;
+ if (p instanceof AbstractAttribute<?>) {
+ value = getAttributeValue((AbstractAttribute<?>) p);
+ } else if (p instanceof AbstractAssociation) {
+ value = getAssociationValue((AbstractAssociation) p);
+ } else {
+ continue;
+ }
+ if (value != null) {
+ code += value.hashCode();
+ }
+ }
+ } else {
+ code = Arrays.hashCode(properties);
+ }
+ }
+ return type.hashCode() + code;
}
/**
@@ -305,7 +329,17 @@ final class DenseFeature extends Abstrac
}
if (obj instanceof DenseFeature) {
final DenseFeature that = (DenseFeature) obj;
- return type.equals(that.type) && Arrays.equals(properties, that.properties);
+ if (type.equals(that.type)) {
+ final boolean asProperties = (properties instanceof Property[]);
+ if (asProperties != (that.properties instanceof Property[])) {
+ if (asProperties) {
+ that.wrapValuesInProperties();
+ } else {
+ wrapValuesInProperties();
+ }
+ }
+ return Arrays.equals(properties, that.properties);
+ }
}
return false;
}
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -16,6 +16,9 @@
*/
package org.apache.sis.feature;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.Locale;
import java.util.TimeZone;
import java.io.IOException;
@@ -60,7 +63,7 @@ import org.apache.sis.referencing.Identi
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public class FeatureFormat extends TabularFormat<Object> {
@@ -267,19 +270,28 @@ header: for (int i=0; ; i++) {
* Column 3 - Value or default value.
*/
if (value != null) {
- final Format format = getFormat(valueClass);
- if (format != null) {
- value = format.format(value, buffer, dummyFP);
- } else if (value instanceof AbstractFeature && propertyType instanceof DefaultAssociationRole) {
- final String p = DefaultAssociationRole.getTitleProperty((DefaultAssociationRole) propertyType);
- if (p != null) {
- value = ((AbstractFeature) value).getPropertyValue(p);
+ final boolean isInstance = valueClass != null && valueClass.isInstance(value);
+ final Format format = isInstance ? getFormat(valueClass) : null;
+ final Iterator<?> it = (!isInstance && (value instanceof Collection<?>)
+ ? (Collection<?>) value : Collections.singleton(value)).iterator();
+ String separator = "";
+ while (it.hasNext()) {
+ value = it.next();
+ if (value != null) {
+ if (format != null) {
+ value = format.format(value, buffer, dummyFP);
+ } else if (value instanceof AbstractFeature && propertyType instanceof DefaultAssociationRole) {
+ final String p = DefaultAssociationRole.getTitleProperty((DefaultAssociationRole) propertyType);
+ if (p != null) {
+ value = ((AbstractFeature) value).getPropertyValue(p);
+ if (value == null) continue;
+ }
+ }
+ table.append(separator).append(formatValue(value));
+ buffer.setLength(0);
+ separator = ", ";
}
}
- if (value != null) {
- table.append(formatValue(value));
- }
- buffer.setLength(0);
}
/*
* Column 4 - Characteristics.
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -28,7 +28,7 @@ import org.apache.sis.util.resources.Err
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
abstract class Field<V> extends Property {
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -39,7 +39,7 @@ import org.apache.sis.util.resources.Err
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*
* @see DefaultAssociationRole
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -42,7 +42,7 @@ import org.apache.sis.util.resources.Err
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*
* @see DefaultAttributeType
@@ -86,10 +86,13 @@ final class MultiValuedAttribute<V> exte
final Class<V> valueClass = type.getValueClass();
if (values == null) {
this.values = new CheckedArrayList<V>(valueClass);
- } else if (((CheckedArrayList<?>) values).getElementType() == valueClass) {
- this.values = (CheckedArrayList<V>) values;
} else {
- throw new ClassCastException();
+ final Class<?> actual = ((CheckedArrayList<?>) values).getElementType();
+ if (actual == valueClass) {
+ this.values = (CheckedArrayList<V>) values;
+ } else {
+ throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_3, "values", valueClass, actual));
+ }
}
}
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -27,7 +27,7 @@ import org.opengis.util.GenericName;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
final class NamedFeatureType implements FeatureType, Serializable {
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -34,7 +34,7 @@ import org.apache.sis.internal.jdk7.Obje
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*
* @see DefaultAssociationRole
@@ -92,7 +92,7 @@ final class SingletonAssociation extends
* @throws IllegalArgumentException If the given feature is not valid for this association.
*/
@Override
- public void setValue(final AbstractFeature value) {
+ public void setValue(final AbstractFeature value) throws IllegalArgumentException {
if (value != null) {
ensureValid(role.getValueType(), value.getType());
}
Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -26,6 +26,9 @@ import org.apache.sis.util.ArgumentCheck
import org.apache.sis.util.CorruptedObjectException;
import org.apache.sis.util.resources.Errors;
+// Branch-dependent imports
+import org.apache.sis.internal.jdk7.Objects;
+
/**
* A feature in which only a small fraction of properties are expected to be provided. This implementation uses
@@ -197,7 +200,7 @@ final class SparseFeature extends Abstra
*
* @param property The property to set.
* @throws IllegalArgumentException if the type of the given property is not one of the types
- * known to this feature.
+ * known to this feature, or if the property can not be set for another reason.
*/
@Override
public void setProperty(final Object property) throws IllegalArgumentException {
@@ -252,7 +255,7 @@ final class SparseFeature extends Abstra
* @param name The attribute name.
* @param value The new value for the given attribute (may be {@code null}).
* @throws ClassCastException If the value is not assignable to the expected value class.
- * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+ * @throws IllegalArgumentException If the given value can not be assigned for another reason.
*/
@Override
public void setPropertyValue(final String name, final Object value) throws IllegalArgumentException {
@@ -355,12 +358,32 @@ final class SparseFeature extends Abstra
/**
* Returns a hash code value for this feature.
+ * This implementation computes the hash code using only the property values, not the {@code Property} instances,
+ * in order to keep the hash code value stable before and after the {@code properties} map is (conceptually)
+ * promoted from the {@code Map<Integer,Object>} type to the {@code Map<Integer,Property>} type.
*
* @return A hash code value.
*/
@Override
public int hashCode() {
- return type.hashCode() + 37 * properties.hashCode();
+ int code = type.hashCode() * 37;
+ if (valuesKind == PROPERTIES) {
+ for (final Map.Entry<Integer,Object> entry : properties.entrySet()) {
+ final Object p = entry.getValue();
+ final Object value;
+ if (p instanceof AbstractAttribute<?>) {
+ value = getAttributeValue((AbstractAttribute<?>) p);
+ } else if (p instanceof AbstractAssociation) {
+ value = getAssociationValue((AbstractAssociation) p);
+ } else {
+ value = null;
+ }
+ code += Objects.hashCode(entry.getKey()) ^ Objects.hashCode(value);
+ }
+ } else {
+ code += properties.hashCode();
+ }
+ return code;
}
/**
@@ -375,7 +398,17 @@ final class SparseFeature extends Abstra
}
if (obj instanceof SparseFeature) {
final SparseFeature that = (SparseFeature) obj;
- return type.equals(that.type) && properties.equals(that.properties);
+ if (type.equals(that.type)) {
+ final boolean asProperties = (valuesKind == PROPERTIES);
+ if (asProperties != (that.valuesKind == PROPERTIES)) {
+ if (asProperties) {
+ that.requireMapOfProperties();
+ } else {
+ requireMapOfProperties();
+ }
+ }
+ return properties.equals(that.properties);
+ }
}
return false;
}
Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -16,6 +16,7 @@
*/
package org.apache.sis.feature;
+import java.util.Arrays;
import java.util.Locale;
import java.util.Random;
import org.apache.sis.test.DependsOn;
@@ -31,7 +32,7 @@ import static org.apache.sis.test.Assert
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
@DependsOn({
@@ -66,7 +67,47 @@ public final strictfp class FeatureForma
@Test
public void testFeature() {
final Random random = TestUtilities.createRandomNumberGenerator();
- final AbstractFeature feature = FeatureTestCase.twinTown(random.nextBoolean());
+ final boolean isSparse = random.nextBoolean();
+
+ final DefaultFeatureType type = DefaultFeatureTypeTest.worldMetropolis();
+ final AbstractFeature feature = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+ feature.setPropertyValue("city", "Tokyo");
+ feature.setPropertyValue("population", 13185502); // In 2011.
+ feature.setPropertyValue("universities", Arrays.asList("Waseda", "Keio"));
+
+ final FeatureFormat format = new FeatureFormat(Locale.US, null);
+ final String text = format.format(feature);
+ assertMultilinesEquals("World metropolis\n" +
+ "┌──────────────┬─────────────────────┬─────────────┬──────────────┬─────────────────┐\n" +
+ "│ Name │ Type │ Cardinality │ Value │ Characteristics │\n" +
+ "├──────────────┼─────────────────────┼─────────────┼──────────────┼─────────────────┤\n" +
+ "│ city │ String │ [1 … 1] │ Tokyo │ │\n" +
+ "│ population │ Integer │ [1 … 1] │ 13,185,502 │ │\n" +
+ "│ region │ InternationalString │ [1 … 1] │ │ │\n" +
+ "│ isGlobal │ Boolean │ [1 … 1] │ │ │\n" +
+ "│ universities │ String │ [0 … ∞] │ Waseda, Keio │ │\n" +
+ "│ temperature │ Float │ [1 … 1] │ │ accuracy, units │\n" +
+ "└──────────────┴─────────────────────┴─────────────┴──────────────┴─────────────────┘\n", text);
+ }
+
+ /**
+ * Tests the formatting of an {@link AbstractFeature} with an association to another feature of the same type.
+ */
+ @Test
+ public void testFeatureWithAssociation() {
+ final Random random = TestUtilities.createRandomNumberGenerator();
+ final boolean isSparse = random.nextBoolean();
+
+ final DefaultFeatureType type = DefaultAssociationRoleTest.twinTownCity(false);
+ final AbstractFeature twinTown = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+ twinTown.setPropertyValue("city", "Le Mans");
+ twinTown.setPropertyValue("population", 143240); // In 2011.
+
+ final AbstractFeature feature = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+ feature.setPropertyValue("city", "Paderborn");
+ feature.setPropertyValue("population", 143174); // December 31th, 2011
+ feature.setPropertyValue("twin town", twinTown);
+
final FeatureFormat format = new FeatureFormat(Locale.US, null);
final String text = format.format(feature);
assertMultilinesEquals("Twin town\n" +
Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -38,7 +38,7 @@ import static org.apache.sis.test.Assert
* @author Martin Desruisseaux (Geomatys)
* @author Marc le Bihan
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public abstract strictfp class FeatureTestCase extends TestCase {
@@ -60,23 +60,6 @@ public abstract strictfp class FeatureTe
}
/**
- * Creates a feature for twin towns.
- */
- static AbstractFeature twinTown(final boolean isSparse) {
- final DefaultFeatureType twinTown = DefaultAssociationRoleTest.twinTownCity(false);
-
- final AbstractFeature leMans = isSparse ? new SparseFeature(twinTown) : new DenseFeature(twinTown);
- leMans.setPropertyValue("city", "Le Mans");
- leMans.setPropertyValue("population", 143240); // In 2011.
-
- final AbstractFeature paderborn = isSparse ? new SparseFeature(twinTown) : new DenseFeature(twinTown);
- paderborn.setPropertyValue("city", "Paderborn");
- paderborn.setPropertyValue("population", 143174); // December 31th, 2011
- paderborn.setPropertyValue("twin town", leMans);
- return paderborn;
- }
-
- /**
* Creates a new feature for the given type.
*/
abstract AbstractFeature createFeature(final DefaultFeatureType type);
@@ -370,4 +353,31 @@ public abstract strictfp class FeatureTe
private void testSerialization() {
assertNotSame(feature, assertSerializedEquals(feature));
}
+
+ /**
+ * Tests {@code equals(Object)}.
+ *
+ * @throws CloneNotSupportedException Should never happen.
+ */
+ @Test
+ @DependsOnMethod("testSimpleProperties")
+ public void testEquals() throws CloneNotSupportedException {
+ feature = createFeature(DefaultFeatureTypeTest.city());
+ feature.setPropertyValue("city", "Tokyo");
+ final AbstractFeature clone = cloneFeature();
+ assertEquals(feature, clone);
+ /*
+ * Force the conversion of a property value into a full Property object on one and only one of
+ * the Features to be compared. The implementation shall be able to wrap or unwrap the values.
+ */
+ assertEquals("Tokyo", ((AbstractAttribute) clone.getProperty("city")).getValue());
+ assertEquals("hashCode", feature.hashCode(), clone.hashCode());
+ assertEquals("equals", feature, clone);
+ /*
+ * For the other Feature instance to contain full Property object and test again.
+ */
+ assertEquals("Tokyo", ((AbstractAttribute) feature.getProperty("city")).getValue());
+ assertEquals("hashCode", feature.hashCode(), clone.hashCode());
+ assertEquals("equals", feature, clone);
+ }
}
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -25,6 +25,7 @@ import org.opengis.referencing.Identifie
import org.opengis.referencing.ReferenceIdentifier;
import org.opengis.referencing.crs.SingleCRS;
import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.crs.VerticalCRS;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystem;
@@ -310,6 +311,17 @@ public class ReferencingServices extends
///////////////////////////////////////////////////////////////////////////////////////
/**
+ * Returns a coordinate reference system for heights above the mean seal level.
+ *
+ * @return The "Mean Seal Level (MSL) height" coordinate reference system, or {@code null}.
+ *
+ * @since 0.6
+ */
+ public VerticalCRS getMSLH() {
+ throw moduleNotFound();
+ }
+
+ /**
* Returns the Greenwich prime meridian.
*
* @return The Greenwich prime meridian.
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -60,7 +60,18 @@ public final class WKTKeywords extends S
Anchor = "Anchor",
Scope = "Scope",
Area = "Area",
- Remarks = "Remarks";
+ Remark = "Remark";
+
+ /**
+ * Related to unit of measurements.
+ */
+ public static final String
+ Unit = "Unit",
+ LengthUnit = "LengthUnit",
+ AngleUnit = "AngleUnit",
+ ScaleUnit = "ScaleUnit",
+ TimeUnit = "TimeUnit",
+ ParametricUnit = "ParametricUnit";
/**
* Related to {@link org.apache.sis.referencing.cs.AbstractCS}
@@ -86,6 +97,7 @@ public final class WKTKeywords extends S
Datum = "Datum",
GeodeticCRS = "GeodeticCRS",
BaseGeodCRS = "BaseGeodCRS",
+ GeodCRS = "GeodCRS",
GeogCS = "GeogCS",
GeocCS = "GeocCS";
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -38,15 +38,19 @@ import org.apache.sis.metadata.iso.citat
* according the OGC 01-009 (<cite>Coordinate transformation services</cite>) specification.</li>
* <li>An older specification — <cite>Simple Features</cite> — was unclear on this matter and has been
* interpreted by many softwares as fixing the unit to decimal degrees.</li>
+ * <li>Some softwares support only (<var>longitude</var>, <var>latitude</var>) axis order
+ * and ignore completely all {@code AXIS[…]} elements in the WKT.</li>
* </ul>
*
* Despite the first interpretation being specified by both OGC 01-009 and ISO 19162 standards, the second
* interpretation appears to be in wide use for WKT 1. Apache SIS uses the standard interpretation by default,
* but the {@link #WKT1_COMMON_UNITS} enumeration allows parsing and formatting using the older interpretation.
+ * The {@link #WKT1_IGNORE_AXES} enumeration mimics the most minimalist WKT 1 parsers,
+ * but should be avoided when not imposed by compatibility reasons.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.4
+ * @version 0.6
* @module
*
* @see WKTFormat#getConvention()
@@ -66,7 +70,7 @@ public enum Convention {
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
*/
- WKT2(false),
+ WKT2(false, false),
/**
* The ISO 19162 format with omission of some optional elements. This convention is identical
@@ -91,7 +95,7 @@ public enum Convention {
*
* <p>This is the default convention used by {@link FormattableObject#toString()}.</p>
*/
- WKT2_SIMPLIFIED(false),
+ WKT2_SIMPLIFIED(false, false),
/**
* The OGC 01-009 format, also known as “WKT 1”.
@@ -103,12 +107,14 @@ public enum Convention {
* names when available.</p>
*
* <div class="section">Differences compared to WKT 2</div>
- * WKT 1 and WKT 2 differ in their keywords and syntax, but also in more subtle ways regarding parameter
- * and code list values. For {@link GeocentricCRS}, WKT 1 uses a legacy set of Cartesian axes which were
- * defined in OGC 01-009. Those axes use the <var>Other</var>, <var>Easting</var> and <var>Northing</var>
- * {@linkplain org.opengis.referencing.cs.AxisDirection axis directions} instead than the geocentric ones,
- * as shown in the following table:
+ * WKT 1 and WKT 2 differ in their keywords and syntax, but also in more subtle ways regarding axis names,
+ * parameter and code list values. For example in {@link GeocentricCRS}, WKT 1 uses a legacy set of Cartesian axes
+ * which were defined in OGC 01-009. Those axes use the <var>Other</var>, <var>Easting</var> and <var>Northing</var>
+ * {@linkplain org.opengis.referencing.cs.AxisDirection axis directions} instead than the geocentric ones.
+ * For more uniform handling of CRS objects in client code, SIS parser replaces some WKT 1 conventions by
+ * the ISO ones when possible.
*
+ * <table class="compact" summary="Differences between current and legacy specifications"><tr><td>
* <table class="sis">
* <caption>Geocentric axis directions</caption>
* <tr><th>ISO 19111</th> <th>OGC 01-009</th> <th>Description</th></tr>
@@ -116,10 +122,20 @@ public enum Convention {
* <tr><td>Geocentric Y</td> <td>Easting</td> <td>Toward 90°E longitude</td></tr>
* <tr><td>Geocentric Z</td> <td>Northing</td> <td>Toward north pole</td></tr>
* </table>
+ * </td><td>
+ * <table class="sis">
+ * <caption>Coordinate system axis names</caption>
+ * <tr><th>CRS type</th> <th>WKT1 names</th> <th>ISO abbreviations</th></tr>
+ * <tr><td>Geographic</td> <td>Lon, Lat</td> <td>λ, φ</td></tr>
+ * <tr><td>Vertical</td> <td><var>H</var></td> <td><var>H</var> or <var>h</var></td></tr>
+ * <tr><td>Projected</td> <td><var>X</var>, <var>Y</var></td> <td><var>E</var>, <var>N</var></td></tr>
+ * <tr><td>Geocentric</td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td></tr>
+ * </table>
+ * </td></tr></table>
*
* @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
*/
- WKT1(true),
+ WKT1(true, false),
/**
* The <cite>Simple Feature</cite> format, also known as “WKT 1”.
@@ -136,7 +152,24 @@ public enum Convention {
* (e.g. <cite>"meter"</cite> instead than <cite>"metre"</cite>).</li>
* </ul>
*/
- WKT1_COMMON_UNITS(true),
+ WKT1_COMMON_UNITS(true, true),
+
+ /**
+ * The <cite>Simple Feature</cite> format without parsing of axis elements.
+ * This convention is identical to {@link #WKT1_COMMON_UNITS} except that all {@code AXIS[…]} elements are ignored.
+ * Since the WKT 1 specification said that the default axis order shall be (<var>x</var>,<var>y</var>) or
+ * (<var>longitude</var>, <var>latitude</var>), ignoring {@code AXIS[…]} elements is equivalent to forcing
+ * the coordinate systems to that default order.
+ *
+ * <p>Note that {@code AXIS[…]} elements still need to be well formed even when parsing a text with this convention.
+ * Malformed axis elements will continue to cause a {@link java.text.ParseException} despite their content being ignored.</p>
+ *
+ * <p>This convention may be useful for compatibility with some other softwares that do not handle axis order correctly.
+ * But except when imposed by such compatibility reasons, this convention should be avoided as much as possible.</p>
+ *
+ * @since 0.6
+ */
+ WKT1_IGNORE_AXES(true, true),
/**
* A special convention for formatting objects as stored internally by Apache SIS.
@@ -167,7 +200,7 @@ public enum Convention {
* @see org.apache.sis.referencing.operation.projection.NormalizedProjection#getParameterValues()
*/
@Debug
- INTERNAL(false);
+ INTERNAL(false, false);
/**
* The default conventions.
@@ -180,10 +213,24 @@ public enum Convention {
private final boolean isWKT1;
/**
+ * {@code true} for a frequently-used convention about units instead than the standard one.
+ * <ul>
+ * <li>If {@code true}, forces {@code PRIMEM} and {@code PARAMETER} angular units to degrees
+ * instead than inferring the unit from the context. The standard value is {@code false},
+ * which means that the angular units are inferred from the context as required by the
+ * WKT 1 specification.</li>
+ * <li>If {@code true}, uses US unit names instead of the international names.
+ * For example Americans said {@code "meter"} instead of {@code "metre"}.</li>
+ * </ul>
+ */
+ final boolean usesCommonUnits;
+
+ /**
* Creates a new enumeration value.
*/
- private Convention(final boolean isWKT1) {
+ private Convention(final boolean isWKT1, final boolean usesCommonUnits) {
this.isWKT1 = isWKT1;
+ this.usesCommonUnits = usesCommonUnits;
}
/**
@@ -217,21 +264,6 @@ public enum Convention {
}
/**
- * {@code true} for a frequently-used convention about units instead than the standard one.
- * <ul>
- * <li>If {@code true}, forces {@code PRIMEM} and {@code PARAMETER} angular units to degrees
- * instead than inferring the unit from the context. The standard value is {@code false},
- * which means that the angular units are inferred from the context as required by the
- * WKT 1 specification.</li>
- * <li>If {@code true}, uses US unit names instead of the international names.
- * For example Americans said {@code "meter"} instead of {@code "metre"}.</li>
- * </ul>
- */
- final boolean usesCommonUnits() {
- return this == WKT1_COMMON_UNITS;
- }
-
- /**
* Returns the default authority to look for when fetching identified object names and identifiers.
* The difference between various authorities are most easily seen in projection and parameter names.
* The value returned by this method can be overwritten by {@link WKTFormat#setNameAuthority(Citation)}.
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -80,6 +80,14 @@ final class Element {
final int offset;
/**
+ * Index of the keyword in the array given to the {@link #pullElement(String...)}
+ * or {@link #pullOptionalElement(String...)} method.
+ *
+ * @see #getKeywordIndex()
+ */
+ private byte keywordIndex;
+
+ /**
* Keyword of this entity. For example: {@code "PrimeMeridian"}.
*/
public final String keyword;
@@ -116,7 +124,7 @@ final class Element {
* @param position On input, the position where to start parsing from.
* On output, the first character after the separator.
*/
- Element(final Parser parser, final String text, final ParsePosition position) throws ParseException {
+ Element(final AbstractParser parser, final String text, final ParsePosition position) throws ParseException {
/*
* Find the first keyword in the specified string. If a keyword is found, then
* the position is set to the index of the first character after the keyword.
@@ -284,20 +292,6 @@ final class Element {
////////////////////////////////////////////////////////////////////////////////////////
/**
- * Returns a {@link ParseException} for a child keyword which is either missing or unknown.
- *
- * @param child The missing or unknown child keyword.
- * @return {@code true} if the given keyword is missing, or {@code false} if it is unknown.
- * @return The exception to be thrown.
- */
- final ParseException keywordNotFound(final String child, final boolean missing) {
- return new LocalizedParseException(locale,
- missing ? Errors.Keys.MissingComponentInElement_2
- : Errors.Keys.UnknownKeywordInElement_2,
- new String[] {keyword, child}, offset);
- }
-
- /**
* Returns a {@link ParseException} with the specified cause. A localized string
* <code>"Error in <{@link #keyword}>"</code> will be prepend to the message.
* The error index will be the starting index of this {@code Element}.
@@ -348,11 +342,11 @@ final class Element {
}
/**
- * Returns an exception saying that a component is missing.
+ * Returns an exception saying that a sub-element is missing.
*
- * @param key The name of the missing component.
+ * @param key The name of the missing sub-element.
*/
- private ParseException missingParameter(final String key) {
+ final ParseException missingComponent(final String key) {
int error = offset;
if (keyword != null) {
error += keyword.length();
@@ -361,6 +355,34 @@ final class Element {
new String[] {keyword, key}, error);
}
+ /**
+ * Returns a {@link ParseException} for a child keyword which is unknown.
+ *
+ * @param expected Keyword of a typical element. Used only if this element contains no child element.
+ * @return The exception to be thrown.
+ */
+ final ParseException missingOrUnknownComponent(final String expected) {
+ String name = null;
+ for (final Object child : list) {
+ if (child instanceof Element) {
+ name = ((Element) child).keyword;
+ if (name != null) {
+ break;
+ }
+ }
+ }
+ final short res;
+ final String[] args;
+ if (name != null) {
+ res = Errors.Keys.UnknownKeyword_1;
+ args = new String[] {name};
+ } else {
+ res = Errors.Keys.MissingComponentInElement_2;
+ args = new String[] {keyword, expected};
+ }
+ return new LocalizedParseException(locale, res, args, offset);
+ }
+
@@ -386,7 +408,7 @@ final class Element {
return (Date) object;
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
@@ -405,7 +427,7 @@ final class Element {
return ((Number) object).doubleValue();
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
@@ -429,7 +451,7 @@ final class Element {
return number.intValue();
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
@@ -448,7 +470,7 @@ final class Element {
return (Boolean) object;
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
@@ -467,7 +489,7 @@ final class Element {
return (String) object;
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
@@ -486,43 +508,51 @@ final class Element {
return object;
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
- * Removes the next {@link Element} from the list and returns it.
+ * Removes the next {@link Element} of the given name from the list and returns it.
+ * If the element was mandatory but is missing, then the first entry in the given {@code keys}
+ * array will be taken as the name of the missing element to report in the exception message.
*
- * @param key The element name (e.g. {@code "PrimeMeridian"}).
- * @return The next {@link Element} on the list.
- * @throws ParseException if no more element is available.
- */
- public Element pullElement(final String key) throws ParseException {
- final Element element = pullOptionalElement(key);
- if (element != null) {
- return element;
- }
- throw missingParameter(key);
- }
-
- /**
- * Removes the next {@link Element} from the list and returns it.
+ * <p>The given {@code mode} argument can be one of the following constants:</p>
+ * <ul>
+ * <li>{@link AbstractParser#MANDATORY} throw an exception if no matching element is found.</li>
+ * <li>{@link AbstractParser#OPTIONAL} return {@code null} if no matching element is found.</li>
+ * <li>{@link AbstractParser#FIRST} return {@code null} if the first element (ignoring all others)
+ * does not match.</li>
+ * </ul>
*
- * @param key The element name (e.g. {@code "PrimeMeridian"}).
- * @return The next {@link Element} on the list, or {@code null} if no more element is available.
+ * @param mode {@link AbstractParser#FIRST}, {@link AbstractParser#OPTIONAL} or {@link AbstractParser#MANDATORY}.
+ * @param keys The element names (e.g. {@code "PrimeMeridian"}).
+ * @return The next {@link Element} of the given names found on the list, or {@code null} if none.
+ * @throws ParseException if {@code mode} is {@code MANDATORY} and no element of the given names was found.
*/
- public Element pullOptionalElement(final String key) {
+ public Element pullElement(final int mode, final String... keys) throws ParseException {
final Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
final Object object = iterator.next();
if (object instanceof Element) {
final Element element = (Element) object;
- if (element.list != null && key.equalsIgnoreCase(element.keyword)) {
- iterator.remove();
- return element;
+ if (element.list != null) {
+ for (int i=0; i<keys.length; i++) {
+ if (element.keyword.equalsIgnoreCase(keys[i])) {
+ keywordIndex = (byte) i;
+ iterator.remove();
+ return element;
+ }
+ }
+ if (mode == AbstractParser.FIRST) {
+ return null;
+ }
}
}
}
- return null;
+ if (mode != AbstractParser.MANDATORY) {
+ return null;
+ }
+ throw missingComponent(keys[0]);
}
/**
@@ -545,17 +575,43 @@ final class Element {
}
}
}
- throw missingParameter(key);
+ throw missingComponent(key);
}
/**
- * Returns the next element, or {@code null} if there is no more element.
- * The element is <strong>not</strong> removed from the list.
+ * Removes the next object of the given type from the list and returns it, if presents.
*
- * @return The next element, or {@code null} if there is no more elements.
+ * @param type The object type.
+ * @return The next object on the list, or {@code null} if none.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T pullOptional(final Class<T> type) {
+ final Iterator<Object> iterator = list.iterator();
+ while (iterator.hasNext()) {
+ final Object object = iterator.next();
+ if (type.isInstance(object)) {
+ iterator.remove();
+ return (T) object;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if this element does not contains any remaining child.
+ *
+ * @return {@code true} if there is no child remaining.
+ */
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ /**
+ * Returns the index of the keyword in the array given to the {@link #pullElement(String...)}
+ * or {@link #pullOptionalElement(String...)} method.
*/
- public Object peek() {
- return list.isEmpty() ? null : list.getFirst();
+ final int getKeywordIndex() {
+ return keywordIndex;
}
/**
@@ -565,8 +621,9 @@ final class Element {
* If the given {@code ignored} map is non-null, then this method will add the keywords
* of ignored elements in that map as below:
* <ul>
- * <li>Keyword of ignored elements are the keys. Note that a key may be null.</li>
- * <li>Keywords of the elements that contained ignored elements are the values.</li>
+ * <li><b>Keys</b>: keyword of ignored elements. Note that a key may be null.</li>
+ * <li><b>Values</b>: keywords of all elements containing an element identified by the above-cited key.
+ * This list is used for helping the users to locate the ignored elements.</li>
* </ul>
*
* @param ignoredElements The collection where to declare ignored elements, or {@code null}.
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -20,6 +20,7 @@ import java.io.Console;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicReference;
import javax.xml.bind.annotation.XmlTransient;
+import org.opengis.util.InternationalString;
import org.apache.sis.util.Debug;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.internal.util.X364;
@@ -180,9 +181,9 @@ public abstract class FormattableObject
try {
formatter.append(this);
if (strict) {
- final String message = formatter.getErrorMessage();
+ final InternationalString message = formatter.getErrorMessage();
if (message != null) {
- throw new UnformattableObjectException(message, formatter.getErrorCause());
+ throw new UnformattableObjectException(message.toString(), formatter.getErrorCause());
}
}
wkt = formatter.toWKT();
Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1686282&r1=1686281&r2=1686282&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Thu Jun 18 17:38:16 2015
@@ -746,7 +746,7 @@ public class Formatter implements Locali
}
}
if (showRemarks) {
- appendOnNewLine(WKTKeywords.Remarks, object.getRemarks(), ElementKind.REMARKS);
+ appendOnNewLine(WKTKeywords.Remark, object.getRemarks(), ElementKind.REMARKS);
}
isComplement = false;
}
@@ -823,6 +823,10 @@ public class Formatter implements Locali
* <li>“{@code VerticalExtent[102, 108, LengthUnit["m", 1]]}” (Δz = 6)</li>
* <li>“{@code VerticalExtent[100.2, 100.8, LengthUnit["m", 1]]}” (Δz = 0.6)</li>
* </ul>
+ *
+ * Note that according ISO 19162, heights are positive toward up and relative to an unspecified mean sea level.
+ * It is caller's responsibility to ensure that the given range complies with that specification as much as
+ * possible.
*/
private void appendVerticalExtent(final MeasurementRange<Double> range) {
if (range != null) {
@@ -1118,23 +1122,27 @@ public class Formatter implements Locali
* Specialization is used in WKT 2 format except the <cite>simplified WKT 2</cite> one.
*
* <div class="note"><b>Example:</b>
- * {@code append(SI.KILOMETRE)} will append "{@code LENGTHUNIT["km", 1000]}" to the WKT.</div>
+ * {@code append(SI.KILOMETRE)} will append "{@code LengthUnit["km", 1000]}" to the WKT.</div>
*
* @param unit The unit to append to the WKT, or {@code null} if none.
+ *
+ * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#35">WKT 2 specification §7.4</a>
*/
public void append(final Unit<?> unit) {
if (unit != null) {
- String keyword = "Unit";
- if (!convention.isSimplified()) {
- if (Units.isLinear(unit)) {
- keyword = "LengthUnit";
- } else if (Units.isAngular(unit)) {
- keyword = "AngleUnit";
- } else if (Units.isScale(unit)) {
- keyword = "ScaleUnit";
- } else if (Units.isTemporal(unit)) {
- keyword = "TimeUnit";
- }
+ final boolean isSimplified = convention.isSimplified();
+ final Unit<?> base = unit.toSI();
+ final String keyword;
+ if (base.equals(SI.METRE)) {
+ keyword = isSimplified ? WKTKeywords.Unit : WKTKeywords.LengthUnit;
+ } else if (base.equals(SI.RADIAN)) {
+ keyword = isSimplified ? WKTKeywords.Unit : WKTKeywords.AngleUnit;
+ } else if (base.equals(Unit.ONE)) {
+ keyword = isSimplified ? WKTKeywords.Unit : WKTKeywords.ScaleUnit;
+ } else if (base.equals(SI.SECOND)) {
+ keyword = WKTKeywords.TimeUnit; // "Unit" alone is not allowed for time units according ISO 19162.
+ } else {
+ keyword = WKTKeywords.ParametricUnit;
}
openElement(false, keyword);
setColor(ElementKind.UNIT);
@@ -1144,7 +1152,7 @@ public class Formatter implements Locali
} else if (NonSI.DEGREE_ANGLE.equals(unit)) {
buffer.append("degree");
} else if (SI.METRE.equals(unit)) {
- buffer.append(convention.usesCommonUnits() ? "meter" : "metre");
+ buffer.append(convention.usesCommonUnits ? "meter" : "metre");
} else if (Units.PPM.equals(unit)) {
buffer.append("parts per million");
} else {
@@ -1153,11 +1161,15 @@ public class Formatter implements Locali
closeQuote(fromIndex);
resetColor();
final double conversion = Units.toStandardUnit(unit);
- if (!(conversion > 0)) { // ISO 19162 requires the conversion factor to be positive.
- setInvalidWKT(Unit.class, null);
- }
appendExact(conversion);
closeElement(false);
+ /*
+ * ISO 19162 requires the conversion factor to be positive.
+ * In addition, keywords other than "Unit" are not valid in WKt 1.
+ */
+ if (!(conversion > 0) || (keyword != WKTKeywords.Unit && convention.majorVersion() == 1)) {
+ setInvalidWKT(Unit.class, null);
+ }
}
}
@@ -1322,7 +1334,7 @@ public class Formatter implements Locali
*/
@SuppressWarnings("unchecked")
public <Q extends Quantity> Unit<Q> addContextualUnit(final Unit<Q> unit) {
- if (unit == null || convention.usesCommonUnits()) {
+ if (unit == null || convention.usesCommonUnits) {
return null;
}
hasContextualUnit |= 1;
@@ -1354,7 +1366,7 @@ public class Formatter implements Locali
* However this check does not work in Convention.WKT1_COMMON_UNITS mode, since the
* map is always empty in that mode.
*/
- if (!convention.usesCommonUnits()) {
+ if (!convention.usesCommonUnits) {
throw new IllegalStateException();
}
}
@@ -1425,7 +1437,7 @@ public class Formatter implements Locali
}
/**
- * Marks the current WKT representation of the given object as not strictly compliant to the WKT specification.
+ * Marks the current WKT representation of the given object as not strictly compliant with the WKT specification.
* This method can be invoked by implementations of {@link FormattableObject#formatTo(Formatter)} when the object
* to format is more complex than what the WKT specification allows.
* Applications can test {@link #isInvalidWKT()} later for checking WKT validity.
@@ -1450,7 +1462,7 @@ public class Formatter implements Locali
}
/**
- * Marks the current WKT representation of the given class as not strictly compliant to the WKT specification.
+ * Marks the current WKT representation of the given class as not strictly compliant with the WKT specification.
* This method can be used as an alternative to {@link #setInvalidWKT(IdentifiedObject, Exception)} when the
* problematic object is not an instance of {@code IdentifiedObject}.
*
@@ -1488,9 +1500,15 @@ public class Formatter implements Locali
/**
* Returns the error message {@link #isInvalidWKT()} is set, or {@code null} otherwise.
* If non-null, a cause may be available in the {@link #getErrorCause()} method.
+ *
+ * <div class="note"><b>Note:</b> the message is returned as an {@link InternationalString}
+ * in order to defer the actual message formatting until needed.</div>
*/
- final String getErrorMessage() {
- return isInvalidWKT() ? Errors.format(Errors.Keys.CanNotRepresentInFormat_2, "WKT", invalidElement) : null;
+ final InternationalString getErrorMessage() {
+ if (!isInvalidWKT()) {
+ return null;
+ }
+ return Errors.formatInternational(Errors.Keys.CanNotRepresentInFormat_2, "WKT", invalidElement);
}
/**