Author: desruisseaux
Date: Fri Mar 7 22:48:35 2014
New Revision: 1575442
URL: http://svn.apache.org/r1575442
Log:
Improve implementation of parameter groups.
Added:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
(with props)
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -19,7 +19,6 @@ package org.apache.sis.parameter;
import java.util.Map;
import java.util.Set;
import java.util.List;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Collections;
import org.opengis.parameter.ParameterValueGroup;
@@ -68,13 +67,7 @@ public class DefaultParameterDescriptorG
/**
* The {@linkplain #descriptors() parameter descriptors} for this group.
*/
- private final GeneralParameterDescriptor[] parameters;
-
- /**
- * A view of {@link #parameters} as an immutable list.
- * Will be constructed only when first needed.
- */
- private transient List<GeneralParameterDescriptor> asList;
+ private final List<GeneralParameterDescriptor> descriptors;
/**
* Constructs a parameter group from a set of properties. The properties
map is given unchanged to the
@@ -139,7 +132,7 @@ public class DefaultParameterDescriptorG
}
}
}
- this.parameters = parameters;
+ descriptors = asList(parameters);
}
/**
@@ -156,7 +149,53 @@ public class DefaultParameterDescriptorG
minimumOccurs = descriptor.getMinimumOccurs();
maximumOccurs = descriptor.getMaximumOccurs();
final List<GeneralParameterDescriptor> c = descriptor.descriptors();
- parameters = c.toArray(new GeneralParameterDescriptor[c.size()]);
+ if (descriptor instanceof DefaultParameterDescriptorGroup &&
+ ((DefaultParameterDescriptorGroup) descriptor).descriptors ==
c)
+ {
+ descriptors = c; // Share the immutable instance (no need to
clone).
+ } else {
+ descriptors = asList(c.toArray(new
GeneralParameterDescriptor[c.size()]));
+ }
+ }
+
+ /**
+ * Returns the given array of parameters as an unmodifiable list.
+ */
+ private static List<GeneralParameterDescriptor> asList(final
GeneralParameterDescriptor[] parameters) {
+ switch (parameters.length) {
+ case 0: return Collections.emptyList();
+ case 1: return Collections.singletonList(parameters[0]);
+ case 2: // fall through
+ case 3: return UnmodifiableArrayList.wrap(parameters);
+ default: return new AsList(parameters);
+ }
+ }
+
+ /**
+ * The {@link DefaultParameterDescriptorGroup#descriptors} as an
unmodifiable list.
+ * This class overrides {@link #contains(Object)} with a faster
implementation based on {@link HashSet}.
+ * This optimizations is helpful for map projection implementations, which
test often for a parameter validity.
+ */
+ private static final class AsList extends
UnmodifiableArrayList<GeneralParameterDescriptor> {
+ /** For compatibility with different versions. */
+ private static final long serialVersionUID = -2116304004367396735L;
+
+ /** The element as a set, created when first needed. */
+ private transient volatile Set<GeneralParameterDescriptor> asSet;
+
+ /** Constructs a list for the specified array. */
+ public AsList(final GeneralParameterDescriptor[] array) {
+ super(array);
+ }
+
+ /** Tests for the inclusion of the specified descriptor. */
+ @Override public boolean contains(final Object object) {
+ Set<GeneralParameterDescriptor> s = asSet;
+ if (s == null) {
+ asSet = s = new HashSet<>(this); // No synchronization: not a
big problem if created twice.
+ }
+ return s.contains(object);
+ }
}
/**
@@ -209,46 +248,13 @@ public class DefaultParameterDescriptorG
}
/**
- * A view of {@link #parameters} as an unmodifiable list. This class
overrides {@link #contains(Object)}
- * with a faster implementation based on {@link HashSet}. This
optimizations is helpful for map projection
- * implementations, which test often for a parameter validity.
- */
- private static final class AsList extends
UnmodifiableArrayList<GeneralParameterDescriptor> {
- /** For compatibility with different versions. */
- private static final long serialVersionUID = -2116304004367396735L;
-
- /** The element as a set. */
- private final Set<GeneralParameterDescriptor> asSet;
-
- /** Constructs a list for the specified array. */
- public AsList(final GeneralParameterDescriptor[] array) {
- super(array);
- asSet = new HashSet<>(this);
- }
-
- /** Tests for the inclusion of the specified descriptor. */
- @Override public boolean contains(final Object object) {
- return asSet.contains(object);
- }
- }
-
- /**
* Returns all parameters in this group.
*
* @return The parameter descriptors in this group.
*/
@Override
public List<GeneralParameterDescriptor> descriptors() {
- if (asList == null) {
- switch (parameters.length) {
- case 0: asList = Collections.emptyList();
break;
- case 1: asList = Collections.singletonList(parameters[0]);
break;
- case 2: // fall through
- case 3: asList = UnmodifiableArrayList.wrap(parameters);
break;
- default: asList = new AsList(parameters);
break;
- }
- }
- return asList;
+ return descriptors;
}
/**
@@ -264,7 +270,7 @@ public class DefaultParameterDescriptorG
public GeneralParameterDescriptor descriptor(final String name) throws
ParameterNotFoundException {
ArgumentChecks.ensureNonNull("name", name);
GeneralParameterDescriptor fallback = null, ambiguity = null;
- for (final GeneralParameterDescriptor param : parameters) {
+ for (final GeneralParameterDescriptor param : descriptors) {
if (IdentifiedObjects.isHeuristicMatchForName(param, name)) {
if (name.equals(param.getName().getCode())) {
return param;
@@ -296,7 +302,7 @@ public class DefaultParameterDescriptorG
final DefaultParameterDescriptorGroup that =
(DefaultParameterDescriptorGroup) object;
return minimumOccurs == that.minimumOccurs &&
maximumOccurs == that.maximumOccurs &&
- Arrays.equals(parameters, that.parameters);
+ descriptors.equals(that.descriptors);
}
default: {
final ParameterDescriptorGroup that =
(ParameterDescriptorGroup) object;
@@ -316,6 +322,6 @@ public class DefaultParameterDescriptorG
*/
@Override
protected long computeHashCode() {
- return Arrays.hashCode(parameters) + super.computeHashCode();
+ return super.computeHashCode() + descriptors.hashCode();
}
}
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -69,7 +69,7 @@ public class DefaultParameterValueGroup
*
* <p>Consider this field as final. It is not for the purpose of {@link
#clone()}.</p>
*/
- private ParameterValueList content;
+ private ParameterValueList values;
/**
* Constructs a parameter group from the specified descriptor.
@@ -78,14 +78,13 @@ public class DefaultParameterValueGroup
*/
public DefaultParameterValueGroup(final ParameterDescriptorGroup
descriptor) {
ArgumentChecks.ensureNonNull("descriptor", descriptor);
- final List<GeneralParameterDescriptor> parameters =
descriptor.descriptors();
- final List<GeneralParameterValue> values = new
ArrayList<>(parameters.size());
- for (final GeneralParameterDescriptor element : parameters) {
- for (int count=element.getMinimumOccurs(); --count>=0;) {
- values.add(element.createValue());
+ final List<GeneralParameterDescriptor> elements =
descriptor.descriptors();
+ values = new ParameterValueList(descriptor, elements.size());
+ for (final GeneralParameterDescriptor child : elements) {
+ for (int count=child.getMinimumOccurs(); --count>=0;) {
+ values.addUnchecked(new UninitializedParameter(child));
}
}
- content = new ParameterValueList(descriptor, values);
}
/**
@@ -95,16 +94,28 @@ public class DefaultParameterValueGroup
*/
@Override
public ParameterDescriptorGroup getDescriptor() {
- return content.descriptor;
+ return values.descriptor;
}
/**
- * Returns the values in this group. Changes in this list are reflected on
this {@code ParameterValueGroup}.
- * The returned list supports the {@code add(…)} and {@code remove(…)}
operations.
+ * Returns the values in this group. The returned list is
<cite>live</cite>:
+ * changes in this list are reflected on this {@code ParameterValueGroup},
and conversely.
+ *
+ * {@section Restrictions}
+ * All write operations must comply to the following conditions:
+ *
+ * <ul>
+ * <li>Parameters added to the list shall have one of the descriptors
listed by {@link #getDescriptor()}.</li>
+ * <li>Adding or removing parameters shall not violate the parameter
cardinality constraints.</li>
+ * </ul>
+ *
+ * The list will verify those conditions and throws {@link
org.opengis.parameter.InvalidParameterNameException},
+ * {@link org.opengis.parameter.InvalidParameterCardinalityException} or
other runtime exceptions if a condition
+ * is not meet.
*/
@Override
public List<GeneralParameterValue> values() {
- return content;
+ return values;
}
/**
@@ -113,19 +124,23 @@ public class DefaultParameterValueGroup
*
* <ul>
* <li>If this group contains a parameter value of the given name, then
that parameter is returned.</li>
- * <li>Otherwise if the {@linkplain #getDescriptor() descriptor}
contains a definition for a parameter
- * of the given name, then a new {@code ParameterValue} instance is
- * {@linkplain DefaultParameterDescriptor#createValue() created},
added to this group then returned.</li>
+ * <li>Otherwise if a {@linkplain
DefaultParameterDescriptorGroup#descriptor(String) descriptor} of the
+ * given name exists, then a new {@code ParameterValue} instance is
+ * {@linkplain DefaultParameterDescriptor#createValue() created},
added to this group and returned.</li>
* <li>Otherwise a {@code ParameterNotFoundException} is thrown.</li>
* </ul>
*
- * This convenience method provides a way to get and set parameter values
by name. For example
- * the following idiom fetches a floating point value for the {@code
"false_easting"} parameter:
+ * This convenience method provides a way to get and set parameter values
by name.
+ * For example the following idiom fetches a floating point value for the
<cite>False easting</cite>
+ * and <cite>False northing</cite> parameters and set a new value for the
<cite>False easting</cite> one:
*
* {@preformat java
- * double value = parameter("false_easting").doubleValue();
+ * double easting = parameter("False easting" ).doubleValue();
+ * double northing = parameter("False northing").doubleValue();
+ * parameter("False easting").setValue(500000.0);
* }
*
+ * {@section Parameters subgroups}
* This method does not search recursively in subgroups. This is because
more than one subgroup
* may exist for the same {@linkplain ParameterDescriptorGroup
descriptor}. The user have to
* {@linkplain #groups(String) query all subgroups} and select explicitly
the appropriate one.
@@ -139,42 +154,42 @@ public class DefaultParameterValueGroup
@Override
public ParameterValue<?> parameter(final String name) throws
ParameterNotFoundException {
ArgumentChecks.ensureNonNull("name", name);
- final List<GeneralParameterValue> values = content.values;
- ParameterValue<?> fallback = null, ambiguity = null;
- for (final GeneralParameterValue value : values) {
- if (value instanceof ParameterValue<?>) {
- final GeneralParameterDescriptor descriptor =
value.getDescriptor();
+ final ParameterValueList values = this.values; // Protect against
accidental changes.
+ int fallback = -1, ambiguity = -1;
+ final int size = values.size();
+ for (int i=0; i<size; i++) {
+ final GeneralParameterDescriptor descriptor = values.descriptor(i);
+ if (descriptor instanceof ParameterDescriptor<?>) {
if (isHeuristicMatchForName(descriptor, name)) {
if (name.equals(descriptor.getName().toString())) {
- return (ParameterValue<?>) value;
- } else if (fallback == null) {
- fallback = (ParameterValue<?>) value;
+ return (ParameterValue<?>) values.get(i);
+ } else if (fallback < 0) {
+ fallback = i;
} else {
- ambiguity = (ParameterValue<?>) value;
+ ambiguity = i;
}
}
}
}
- if (fallback != null) {
- if (ambiguity == null) {
- return fallback;
+ if (fallback >= 0) {
+ if (ambiguity < 0) {
+ return (ParameterValue<?>) values.get(fallback);
}
throw new
ParameterNotFoundException(Errors.format(Errors.Keys.AmbiguousName_3,
- fallback.getDescriptor().getName(),
ambiguity.getDescriptor().getName(), name), name);
+ values.descriptor(fallback).getName(),
values.descriptor(ambiguity).getName(), name), name);
}
/*
- * No existing parameter found. Check if an optional parameter exists.
- * If such a descriptor is found, create it, add it to the list of
values
- * and returns it.
+ * No existing parameter found. The parameter may be optional. Check
if a descriptor exists.
+ * If such a descriptor is found, create the parameter, add it to the
values list and returns it.
*/
- final GeneralParameterDescriptor descriptor =
content.descriptor.descriptor(name);
- if (descriptor instanceof ParameterDescriptor<?>) {
+ final GeneralParameterDescriptor descriptor =
values.descriptor.descriptor(name);
+ if (descriptor instanceof ParameterDescriptor<?> &&
descriptor.getMaximumOccurs() != 0) {
final ParameterValue<?> value = ((ParameterDescriptor<?>)
descriptor).createValue();
- values.add(value);
+ values.addUnchecked(value);
return value;
}
throw new
ParameterNotFoundException(Errors.format(Errors.Keys.ParameterNotFound_2,
- content.descriptor.getName(), name), name);
+ values.descriptor.getName(), name), name);
}
/**
@@ -191,11 +206,14 @@ public class DefaultParameterValueGroup
@Override
public List<ParameterValueGroup> groups(final String name) throws
ParameterNotFoundException {
ArgumentChecks.ensureNonNull("name", name);
+ final ParameterValueList values = this.values; // Protect against
accidental changes.
final List<ParameterValueGroup> groups = new ArrayList<>(4);
- for (final GeneralParameterValue value : content.values) {
- if (value instanceof ParameterValueGroup) {
- if (isHeuristicMatchForName(value.getDescriptor(), name)) {
- groups.add((ParameterValueGroup) value);
+ final int size = values.size();
+ for (int i=0; i<size; i++) {
+ final GeneralParameterDescriptor descriptor = values.descriptor(i);
+ if (descriptor instanceof ParameterDescriptorGroup) {
+ if (isHeuristicMatchForName(descriptor, name)) {
+ groups.add((ParameterValueGroup) values.get(i));
}
}
}
@@ -205,7 +223,7 @@ public class DefaultParameterValueGroup
* it is simply an optional group not yet defined), then returns an
empty list.
*/
if (groups.isEmpty()) {
- final ParameterDescriptorGroup descriptor = content.descriptor;
+ final ParameterDescriptorGroup descriptor = values.descriptor;
if (!(descriptor.descriptor(name) instanceof
ParameterDescriptorGroup)) {
throw new ParameterNotFoundException(Errors.format(
Errors.Keys.ParameterNotFound_2, descriptor.getName(),
name), name);
@@ -235,19 +253,15 @@ public class DefaultParameterValueGroup
public ParameterValueGroup addGroup(final String name)
throws ParameterNotFoundException,
InvalidParameterCardinalityException
{
- final ParameterDescriptorGroup descriptor = content.descriptor;
+ final ParameterValueList values = this.values; // Protect against
accidental changes.
+ final ParameterDescriptorGroup descriptor = values.descriptor;
final GeneralParameterDescriptor child = descriptor.descriptor(name);
if (!(child instanceof ParameterDescriptorGroup)) {
throw new ParameterNotFoundException(Errors.format(
Errors.Keys.ParameterNotFound_2, descriptor.getName(),
name), name);
}
- final int count = content.count(child.getName());
- if (count >= child.getMaximumOccurs()) {
- throw new InvalidParameterCardinalityException(Errors.format(
- Errors.Keys.TooManyOccurrences_2, count, name), name);
- }
final ParameterValueGroup value = ((ParameterDescriptorGroup)
child).createValue();
- content.values.add(value);
+ values.add(value);
return value;
}
@@ -264,8 +278,8 @@ public class DefaultParameterValueGroup
}
if (object != null && getClass() == object.getClass()) {
final DefaultParameterValueGroup that =
(DefaultParameterValueGroup) object;
- return Objects.equals(content.descriptor, that.content.descriptor)
&&
- Objects.equals(content.values, that.content.values);
+ return Objects.equals(values.descriptor, that.values.descriptor) &&
+ Objects.equals(values, that.values);
}
return false;
}
@@ -278,7 +292,7 @@ public class DefaultParameterValueGroup
*/
@Override
public int hashCode() {
- return content.descriptor.hashCode() ^ content.values.hashCode();
+ return values.descriptor.hashCode() ^ values.hashCode();
}
/**
@@ -296,11 +310,7 @@ public class DefaultParameterValueGroup
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
- copy.content = new ParameterValueList(content.descriptor, new
ArrayList<>(content.values));
- final List<GeneralParameterValue> values = copy.content.values;
- for (int i=values.size(); --i>=0;) {
- values.set(i, values.get(i).clone());
- }
+ copy.values = new ParameterValueList(copy.values);
return copy;
}
}
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -28,7 +28,7 @@ import static org.apache.sis.util.Argume
/**
- * Provides convenience methods for easier {@code DefaultParameterDescriptor}
instantiations.
+ * Provides convenience methods for easier {@code ParameterDescriptorGroup}
instantiations.
* This builder can be helpful for map projection <em>providers</em>, or for
implementation of
* any process that use parameters. Map projection or process <em>users</em>
do not need this
* builder since they can invoke {@link ParameterDescriptor#createValue()} on
the descriptor
@@ -53,8 +53,9 @@ import static org.apache.sis.util.Argume
* Parameter descriptors are typically grouped in a {@link
ParameterDescriptorGroup}.
* All parameters usually have the same namespace, which can be declared only
once.
* The following example creates parameters for "<cite>Mercator (variant
A)</cite>" projection method (EPSG:9804)
- * with all parameter names in the "EPSG" namespace. The default values define
a projection centered on (0°,0°)
- * with no scale factor and no false easting/northing.
+ * with all parameter names in the "EPSG" namespace. The default values define
a projection centered on (0°,0°),
+ * with no scale factor and no false easting/northing. The projection is valid
from 80°S to 84°N and on all the
+ * longitude range (±180°).
*
* {@preformat java
* ParameterBuilder builder = new ParameterBuilder();
@@ -76,6 +77,7 @@ import static org.apache.sis.util.Argume
* builder.addName("Longitude of natural origin") // Primary name in
builder default namespace.
* .addName(Citations.OGC, "central_meridian") // First alias in
"OGC" namespace.
* .addName(Citations.GEOTIFF, "NatOriginLong") // Second alias in
"GeoTIFF" namespace.
+ * .addIdentifier("8802") // Primary key in
EPSG database.
* .createBounded(-80, +84, 0, NonSI.DEGREE_ANGLE);
* }
*
Modified:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -19,7 +19,10 @@ package org.apache.sis.parameter;
import java.util.List;
import java.util.AbstractList;
import java.util.RandomAccess;
+import java.util.Arrays;
import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.GeneralParameterValue;
@@ -28,13 +31,20 @@ import org.opengis.parameter.GeneralPara
import org.opengis.parameter.InvalidParameterNameException;
import org.opengis.parameter.InvalidParameterCardinalityException;
import org.opengis.referencing.ReferenceIdentifier;
+import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
/**
* The list to be returned by {@link DefaultParameterValueGroup#values()}.
* This class performs checks on the parameter values to be added or removed.
- * This implementation supports {@code add(…)} and {@code remove(…)}
operations.
+ * This implementation supports {@code set(…)}, {@code add(…)} and {@code
remove(…)} operations.
+ *
+ * <p><b>Implementation note:</b> This class reproduces some {@link
java.util.ArrayList} functionalities.
+ * However we do <strong>not</strong> extend {@code ArrayList} because we
really need the default method
+ * implementations provided by {@code AbstractList} — the optimizations
performed by {@code ArrayList}
+ * are not suitable here.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4 (derived from geotk-2.1)
@@ -50,63 +60,159 @@ final class ParameterValueList extends A
/**
* The descriptor for the list as a whole.
*
- * <p>This descriptor will not be used in {@link #equals(Object)} and
{@link #hashCode()}
+ * <p>This descriptor shall not be used in {@link #equals(Object)} and
{@link #hashCode()}
* implementations in order to stay consistent with the {@link List}
contract.</p>
*/
final ParameterDescriptorGroup descriptor;
/**
- * The unchecked list of parameter values for this list.
+ * The parameter values in the group. The length of this array is the list
capacity.
+ */
+ private GeneralParameterValue[] values;
+
+ /**
+ * Number of valid elements in the {@link #values} array.
*/
- final List<GeneralParameterValue> values;
+ private int size;
/**
- * Constructs a parameter list.
+ * Constructs an initially empty parameter list.
*
* @param descriptor The descriptor for this list.
- * @param values The parameter values for this list.
+ * @param capacity The initial capacity.
*/
- ParameterValueList(final ParameterDescriptorGroup descriptor, final
List<GeneralParameterValue> values) {
+ ParameterValueList(final ParameterDescriptorGroup descriptor, final int
capacity) {
this.descriptor = descriptor;
- this.values = values;
+ values = new GeneralParameterValue[capacity];
+ }
+
+ /**
+ * Constructs a parameter list initialized to a copy of the given one.
+ */
+ ParameterValueList(final ParameterValueList other) {
+ descriptor = other.descriptor;
+ values = new GeneralParameterValue[size = other.size];
+ for (int i=0; i<size; i++) {
+ values[i] = other.values[i].clone();
+ }
+ }
+
+ /**
+ * Returns the number of parameters in this list.
+ */
+ @Override
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Returns the descriptor at the given index. This method is preferable to
{@code get(i).getDescriptor()}
+ * when the caller does not need the replacement of {@link
UninitializedParameter} instances.
+ */
+ final GeneralParameterDescriptor descriptor(final int index) {
+ return values[index].getDescriptor();
+ }
+
+ /**
+ * Returns the parameter value at the given index. If the parameter at the
given index is a
+ * mandatory parameter pending creation of the actual value, the value
will be created now.
+ */
+ @Override
+ public GeneralParameterValue get(int index) {
+ ArgumentChecks.ensureValidIndex(size, index);
+ GeneralParameterValue value = values[index];
+ if (value instanceof UninitializedParameter) {
+ values[index] = value = value.getDescriptor().createValue();
+ }
+ return value;
}
- /*
- * CAUTION: Some methods are NOT forwarded to 'values', and this is on
purpose!
- * This include all modification methods (add, set, remove, etc.).
- * We must rely on the default AbstractList implementation for
them.
- */
- @Override public boolean isEmpty () {return
values.isEmpty ( );}
- @Override public int size () {return
values.size ( );}
- @Override public GeneralParameterValue get (int i) {return
values.get (i);}
- @Override public int indexOf (Object o) {return
values.indexOf (o);}
- @Override public int lastIndexOf(Object o) {return
values.lastIndexOf(o);}
- @Override public boolean equals (Object o) {return
values.equals (o);}
- @Override public int hashCode () {return
values.hashCode ( );}
- @Override public String toString () {return
values.toString ( );}
+ /**
+ * Sets the parameter at the given index. The descriptor of the given
parameter must be one of those
+ * in the {@link DefaultParameterDescriptorGroup#descriptors()} list, and
storing that parameter must
+ * be allowed by the cardinality constraints.
+ */
+ @Override
+ public GeneralParameterValue set(final int index, final
GeneralParameterValue parameter) {
+ ArgumentChecks.ensureValidIndex(size, index);
+ final GeneralParameterValue value = values[index];
+ ArgumentChecks.ensureNonNull("parameter", parameter);
+ final GeneralParameterDescriptor desc = parameter.getDescriptor();
+ if (!value.getDescriptor().equals(desc)) {
+ ensureDescriptorExists(desc);
+ ensureCanRemove(desc);
+ ensureCanAdd(desc);
+ }
+ values[index] = parameter;
+ return value;
+ }
/**
* Adds a {@link ParameterValue} or an other {@link ParameterValueGroup}
to this list.
* If an existing parameter is already included for the same name and
adding the new
* parameter would increase the number past what is allowable by {@code
maximumOccurs},
- * then an {@link IllegalStateException} will be thrown.
+ * then an {@link InvalidParameterCardinalityException} will be thrown.
*
* @param parameter New parameter to be added to this group.
- * @return {@code true} if this object changed as a result of this call.
+ * @return Always {@code true} since this object changes as a result of
this call.
* @throws IllegalArgumentException if the specified parameter is not
allowable by the groups descriptor.
* @throws InvalidParameterCardinalityException if adding this parameter
would result in more parameters
* than allowed by {@code maximumOccurs}.
*/
@Override
public boolean add(final GeneralParameterValue parameter) {
- final GeneralParameterDescriptor type = parameter.getDescriptor();
- final ReferenceIdentifier name = type.getName();
+ ArgumentChecks.ensureNonNull("parameter", parameter);
+ final GeneralParameterDescriptor desc = parameter.getDescriptor();
+ ensureDescriptorExists(desc);
+ /*
+ * If we had an uninitialized parameter (a parameter created by the
DefaultParameterValueGroup constructor
+ * and never been queried or set by the user), then the given
parameter will replace the uninitialized.
+ * The intend is to allow users to set its own parameters by a call to
group.values().addAll(myParam).
+ * Otherwise the given parameter will be added, in which case we need
to check the cardinality.
+ */
+ final ReferenceIdentifier name = desc.getName();
+ int count = 0;
+ for (int i=0; i<size; i++) {
+ final GeneralParameterValue value = values[i];
+ if (name.equals(value.getDescriptor().getName())) {
+ if (value instanceof UninitializedParameter) {
+ values[i] = parameter;
+ return true;
+ }
+ count++;
+ }
+ }
+ if (count > desc.getMaximumOccurs()) {
+ throw new InvalidParameterCardinalityException(Errors.format(
+ Errors.Keys.TooManyOccurrences_2, count, name),
name.getCode());
+ }
+ addUnchecked(parameter);
+ modCount++;
+ return true;
+ }
+
+ /**
+ * Unconditionally adds the given parameter to this list without any
validity check.
+ * The internal array will growth as needed.
+ */
+ final void addUnchecked(final GeneralParameterValue parameter) {
+ if (size == values.length) {
+ values = Arrays.copyOf(values, size*2);
+ }
+ values[size++] = parameter;
+ }
+
+ /**
+ * Verifies the given descriptor exists in the {@link
DefaultParameterDescriptorGroup#descriptors()} list.
+ */
+ final void ensureDescriptorExists(final GeneralParameterDescriptor desc) {
final List<GeneralParameterDescriptor> descriptors =
descriptor.descriptors();
- if (!descriptors.contains(type)) {
+ if (!descriptors.contains(desc)) {
/*
* For a more accurate error message, check if the operation
failed because the
* parameter name was not found, or the parameter descriptor does
not matches.
*/
+ final ReferenceIdentifier name = desc.getName();
for (final GeneralParameterDescriptor descriptor : descriptors) {
if (name.equals(descriptor.getName())) {
throw new IllegalArgumentException(Errors.format(
@@ -116,32 +222,47 @@ final class ParameterValueList extends A
throw new InvalidParameterNameException(Errors.format(
Errors.Keys.ParameterNotFound_2, descriptor.getName(),
name), name.getCode());
}
- /*
- * Before to add the parameter, check the cardinality.
- */
- final int count = count(name);
- if (count >= type.getMaximumOccurs()) {
+ }
+
+ /**
+ * Verifies if adding a parameter with the given descriptor is allowed by
the cardinality constraints. If adding
+ * the parameter would result in more occurrences than {@link
DefaultParameterDescriptor#getMaximumOccurs()},
+ * then this method throws an {@link InvalidParameterCardinalityException}.
+ */
+ private void ensureCanAdd(final GeneralParameterDescriptor desc) {
+ final ReferenceIdentifier name = desc.getName();
+ int count = 0;
+ for (int i=0; i<size; i++) {
+ if (name.equals(values[i].getDescriptor().getName())) {
+ count++;
+ }
+ }
+ if (count >= desc.getMaximumOccurs()) {
throw new InvalidParameterCardinalityException(Errors.format(
Errors.Keys.TooManyOccurrences_2, count, name),
name.getCode());
}
- modCount++;
- return values.add(parameter);
}
/**
- * Count the number of parameter having the given name.
- *
- * @param name The name to search.
- * @return Number of parameter having the given name.
+ * Verifies if removing the given value is allowed by the cardinality
constraints. If removing the parameter
+ * would result in less occurrences than {@link
DefaultParameterDescriptor#getMinimumOccurs()},
+ * then this method throws an {@link InvalidParameterCardinalityException}.
*/
- final int count(final ReferenceIdentifier name) {
- int count = 0;
- for (final GeneralParameterValue value : values) {
- if (name.equals(value.getDescriptor().getName())) {
- count++;
+ private void ensureCanRemove(final GeneralParameterDescriptor desc) {
+ final int min = desc.getMinimumOccurs();
+ if (min != 0) { // Optimization for a common case.
+ final ReferenceIdentifier name = desc.getName();
+ int count = 0;
+ for (int i=0; i<size; i++) {
+ if (name.equals(values[i].getDescriptor().getName())) {
+ if (++count > min) {
+ return;
+ }
+ }
}
+ throw new InvalidParameterCardinalityException(Errors.format(
+ Errors.Keys.TooFewOccurrences_2, min, name),
name.getCode());
}
- return count;
}
/**
@@ -153,22 +274,36 @@ final class ParameterValueList extends A
*/
@Override
public GeneralParameterValue remove(final int index) {
- final GeneralParameterDescriptor type =
values.get(index).getDescriptor();
- final int min = type.getMinimumOccurs();
- if (min != 0) {
- int count = 0;
- final ReferenceIdentifier name = type.getName();
- for (final GeneralParameterValue value : values) {
- if (name.equals(value.getDescriptor().getName())) {
- if (++count > min) break;
- }
- }
- if (count <= min) {
- throw new InvalidParameterCardinalityException(Errors.format(
- Errors.Keys.TooFewOccurrences_2, min, name),
name.getCode());
- }
- }
+ ArgumentChecks.ensureValidIndex(size, index);
+ final GeneralParameterValue value = values[index];
+ ensureCanRemove(value.getDescriptor());
+ System.arraycopy(values, index + 1, values, index, --size - index);
+ values[size] = null;
modCount++;
- return values.remove(index);
+ return value;
+ }
+
+ /**
+ * Returns a string representation of this list.
+ */
+ @Override
+ public String toString() {
+ if (size == 0) {
+ return "[]";
+ }
+ final String lineSeparator = System.lineSeparator();
+ final StringBuilder buffer = new StringBuilder();
+ for (int i=0; i<size; i++) {
+ buffer.append(values[i]).append(lineSeparator);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Trims the array to its capacity before to serialize.
+ */
+ private void writeObject(final ObjectOutputStream out) throws IOException {
+ values = ArraysExt.resize(values, size);
+ out.defaultWriteObject();
}
}
Added:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java?rev=1575442&view=auto
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
(added)
+++
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.parameter;
+
+import java.io.Serializable;
+import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.GeneralParameterValue;
+import org.apache.sis.referencing.IdentifiedObjects;
+
+
+/**
+ * Placeholder for a mandatory parameter value which has not yet been
initialized.
+ * {@code UninitializedParameter} are immutable and contains only the
descriptor of
+ * the parameter to initialize. {@code UninitializedParameter} are replaced by
the
+ * actual parameter when first needed.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.4
+ * @version 0.4
+ * @module
+ */
+final class UninitializedParameter implements GeneralParameterValue,
Serializable {
+ /**
+ * For cross-version serialization compatibility.
+ */
+ private static final long serialVersionUID = 4664809449434987422L;
+
+ /**
+ * The descriptor of the parameter to initialize.
+ */
+ private final GeneralParameterDescriptor descriptor;
+
+ /**
+ * Creates a new {@code UninitializedParameter} for the given descriptor.
+ */
+ UninitializedParameter(final GeneralParameterDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ /**
+ * Returns the descriptor of the parameter to initialize.
+ */
+ @Override
+ public GeneralParameterDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ /**
+ * Returns {@code this} since there is no need to clone this object.
+ */
+ @Override
+ public GeneralParameterValue clone() {
+ return this;
+ }
+
+ /**
+ * Returns a string representation of this parameter.
+ */
+ @Override
+ public String toString() {
+ return "Parameter[\"" +
IdentifiedObjects.toString(descriptor.getName()) + "\"]";
+ }
+}
Propchange:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -17,18 +17,8 @@
package org.apache.sis.parameter;
import java.util.Map;
-import java.util.HashMap;
-import java.util.Locale;
+import java.util.List;
import org.opengis.parameter.GeneralParameterDescriptor;
-import javax.measure.unit.SI;
-import javax.measure.unit.Unit;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.parameter.ParameterValueGroup;
-import org.apache.sis.measure.Range;
-import org.apache.sis.measure.NumberRange;
-import org.apache.sis.measure.MeasurementRange;
-import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -56,14 +46,14 @@ public final strictfp class DefaultParam
* The very last parameter has a maximum number of occurrence of 2, which
is illegal
* according ISO 19111 but nevertheless supported by Apache SIS.
*/
- static final DefaultParameterDescriptorGroup createGroupOfIntegers() {
- final Integer DEFAULT = 10;
+ static final DefaultParameterDescriptorGroup createGroup_2M_2O() {
+ final Integer DEFAULT_VALUE = 10;
final Class<Integer> type = Integer.class;
return new DefaultParameterDescriptorGroup(name("The group"), 0, 1,
- new DefaultParameterDescriptor<>(name("Mandatory 1"), type, null,
null, DEFAULT, true),
- new DefaultParameterDescriptor<>(name("Mandatory 2"), type, null,
null, DEFAULT, true),
- new DefaultParameterDescriptor<>(name( "Optional 3"), type, null,
null, DEFAULT, false),
- new MultiOccurrenceDescriptor <>(name( "Optional 4"), type, null,
null, DEFAULT, false)
+ new DefaultParameterDescriptor<>(name("Mandatory 1"), type, null,
null, DEFAULT_VALUE, true),
+ new DefaultParameterDescriptor<>(name("Mandatory 2"), type, null,
null, DEFAULT_VALUE, true),
+ new DefaultParameterDescriptor<>(name( "Optional 3"), type, null,
null, DEFAULT_VALUE, false),
+ new MultiOccurrenceDescriptor <>(name( "Optional 4"), type, null,
null, DEFAULT_VALUE, false)
);
}
@@ -75,11 +65,11 @@ public final strictfp class DefaultParam
}
/**
- * Tests descriptor validation.
+ * Validates the test parameter descriptors created by {@link
#createGroup_2M_2O()}.
*/
@Test
- public void testValidate() {
- for (final GeneralParameterDescriptor descriptor :
createGroupOfIntegers().descriptors()) {
+ public void validateTestObjects() {
+ for (final GeneralParameterDescriptor descriptor :
createGroup_2M_2O().descriptors()) {
AssertionError error = null;
try {
validate(descriptor);
@@ -93,4 +83,32 @@ public final strictfp class DefaultParam
}
}
}
+
+ /**
+ * Tests {@link DefaultParameterDescriptorGroup#descriptor(String)}.
+ */
+ @Test
+ public void testDescriptor() {
+ final DefaultParameterDescriptorGroup group = createGroup_2M_2O();
+ final List<GeneralParameterDescriptor> descriptors =
group.descriptors();
+ assertEquals("name", "The group", group.getName().getCode());
+ assertEquals("size", 4, descriptors.size());
+ assertSame("descriptor(“Mandatory 1”)", descriptors.get(0),
group.descriptor("Mandatory 1"));
+ assertSame("descriptor(“Optional 3”)", descriptors.get(2),
group.descriptor("Optional 3"));
+ assertSame("descriptor(“Optional 4”)", descriptors.get(3),
group.descriptor("Optional 4"));
+ assertSame("descriptor(“Mandatory 2”)", descriptors.get(1),
group.descriptor("Mandatory 2"));
+ }
+
+ /**
+ * Tests {@code
DefaultParameterDescriptorGroup.descriptors().contains(Object)}.
+ * The list returned by {@code descriptors()} provides a fast
implementation based on {@code HashSet},
+ * because this operation is requested everytime a new parameter is added
or modified.
+ */
+ @Test
+ public void testContains() {
+ final List<GeneralParameterDescriptor> descriptors =
createGroup_2M_2O().descriptors();
+ for (final GeneralParameterDescriptor p : descriptors) {
+ assertTrue(descriptors.contains(p));
+ }
+ }
}
Modified:
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java?rev=1575442&r1=1575441&r2=1575442&view=diff
==============================================================================
---
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
[UTF-8] Fri Mar 7 22:48:35 2014
@@ -16,20 +16,13 @@
*/
package org.apache.sis.parameter;
-import java.util.Map;
-import java.util.HashMap;
import java.util.List;
-import java.util.Locale;
+import java.util.Arrays;
import org.opengis.parameter.GeneralParameterDescriptor;
-import javax.measure.unit.SI;
-import javax.measure.unit.Unit;
+import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
-import org.apache.sis.measure.Range;
-import org.apache.sis.measure.NumberRange;
-import org.apache.sis.measure.MeasurementRange;
-import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -68,13 +61,12 @@ public final strictfp class DefaultParam
}
/**
- * Tests parameter validation.
+ * Validates the test parameter values created by {@link
#createValues(List, int)}.
*/
@Test
- public void testValidate() {
- for (final DefaultParameterValue<?> param : createValues(
-
DefaultParameterDescriptorGroupTest.createGroupOfIntegers().descriptors(), 10))
- {
+ public void validateTestObjects() {
+ final DefaultParameterDescriptorGroup group =
DefaultParameterDescriptorGroupTest.createGroup_2M_2O();
+ for (final DefaultParameterValue<?> param :
createValues(group.descriptors(), 10)) {
AssertionError error = null;
try {
validate(param);
@@ -90,6 +82,24 @@ public final strictfp class DefaultParam
}
/**
+ * Tests {@code DefaultParameterValueGroup.values().addAll(…)}.
+ */
+ @Test
+ public void testAddAll() {
+ final DefaultParameterDescriptorGroup descriptor =
DefaultParameterDescriptorGroupTest.createGroup_2M_2O();
+ final DefaultParameterValueGroup group = new
DefaultParameterValueGroup(descriptor);
+ final List<GeneralParameterValue> values = group.values();
+ assertEquals("Initial size", 2, values.size());
+
+ final DefaultParameterValue<?>[] external =
createValues(descriptor.descriptors(), 10);
+ assertTrue(values.addAll(Arrays.asList(external)));
+ assertEquals("Final size", external.length, values.size());
+ for (int i=0; i<external.length; i++) {
+ assertSame(external[i], values.get(i));
+ }
+ }
+
+ /**
* Tests the {@link DefaultParameterValueGroup#addGroup(String)} method.
* Ensures the descriptor is found and the new value correctly inserted.
*/