Author: desruisseaux
Date: Mon Dec 3 15:11:48 2012
New Revision: 1416555
URL: http://svn.apache.org/viewvc?rev=1416555&view=rev
Log:
Keep trace of objects associated to UUID in the current JVM.
This is a first draft - will need more review and tests.
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
(with props)
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/UUIDs.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierMap.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapAdapterTest.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCasesTest.java
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
Mon Dec 3 15:11:48 2012
@@ -28,14 +28,15 @@ import java.io.Serializable;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.xml.IdentifierSpace;
import org.apache.sis.xml.IdentifierMap;
+import org.apache.sis.xml.IdentifierSpace;
+import org.apache.sis.xml.IdentifierAlreadyBoundException;
+
+import static org.apache.sis.util.collection.Collections.hashMapCapacity;
// Related to JDK7
import java.util.Objects;
-import static org.apache.sis.util.collection.Collections.hashMapCapacity;
-
/**
* A map of identifiers which can be used as a helper class for
@@ -106,16 +107,6 @@ public class IdentifierMapAdapter extend
private transient Set<Entry<Citation,String>> entries;
/**
- * Creates an identifier map for the given collection of identifiers.
- *
- * @param identifiers The identifiers to wrap in a map view.
- * @return The map of identifiers as a wrapper over the given collection.
- */
- public static IdentifierMap create(final Collection<Identifier>
identifiers) {
- return new IdentifierMapWithSpecialCases(identifiers);
- }
-
- /**
* Creates a new map which will be a view over the given identifiers.
*
* @param identifiers The identifiers to wrap in a map view.
@@ -200,6 +191,25 @@ public class IdentifierMapAdapter extend
}
/**
+ * Returns the code of the first identifier associated with the given
authority only if
+ * if is <strong>not</strong> a specialized identifier. Otherwise returns
{@code null}.
+ *
+ * <p>This is a helper method for {@link
IdentifierMapWithSpecialCases#put(Citation, String)},
+ * in order to be able to return the old value if that value was a {@link
String} rather than
+ * the specialized type. We do not return the string for the specialized
case in order to avoid
+ * the cost of invoking {@code toString()} on the specialized object (some
may be costly). Such
+ * call would be useless because {@code IdentifierMapWithSpecialCase}
discard the value of this
+ * method when it found a specialized type.</p>
+ */
+ final String getUnspecialized(final Citation authority) {
+ final Identifier identifier = getIdentifier(authority);
+ if (identifier != null && !(identifier instanceof
SpecializedIdentifier<?>)) {
+ return identifier.getCode();
+ }
+ return null;
+ }
+
+ /**
* Returns the code of the first identifier associated with the given
* {@linkplain Identifier#getAuthority() authority}, or {@code null}
* if no identifier was found.
@@ -219,8 +229,8 @@ public class IdentifierMapAdapter extend
}
/**
- * Removes all identifiers associated with the given
- * {@linkplain Identifier#getAuthority() authority}.
+ * Removes all identifiers associated with the given {@linkplain
Identifier#getAuthority() authority}.
+ * The default implementation delegates to {@link #put(Citation, String)}
with a {@code null} value.
*
* @param authority The authority to search, which should be an instance
of {@link Citation}.
* @return The code of the identifier for the given authority, or {@code
null} if none.
@@ -238,11 +248,15 @@ public class IdentifierMapAdapter extend
* first entry, so it can be find by the {@code get} method.
*
* @param authority The authority for which to set the code.
- * @param code The new code for the given authority.
+ * @param code The new code for the given authority, or {@code null} for
removing the entry.
* @return The previous code for the given authority, or {@code null} if
none.
+ * @throws IdentifierAlreadyBoundException If this map expects unique
identifiers for the
+ * given authority, and the given value is already associated to
another object.
*/
@Override
- public String put(final Citation authority, final String code) throws
UnsupportedOperationException {
+ public String put(final Citation authority, final String code)
+ throws IdentifierAlreadyBoundException,
UnsupportedOperationException
+ {
ArgumentChecks.ensureNonNull("authority", authority);
String old = null;
final Iterator<? extends Identifier> it = identifiers.iterator();
@@ -275,7 +289,9 @@ public class IdentifierMapAdapter extend
* Sets the identifier associated with the given authority, and returns
the previous value.
*/
@Override
- public <T> T putSpecialized(final IdentifierSpace<T> authority, final T
value) throws UnsupportedOperationException {
+ public <T> T putSpecialized(final IdentifierSpace<T> authority, final T
value)
+ throws IdentifierAlreadyBoundException,
UnsupportedOperationException
+ {
ArgumentChecks.ensureNonNull("authority", authority);
T old = null;
final Iterator<? extends Identifier> it = identifiers.iterator();
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java
Mon Dec 3 15:11:48 2012
@@ -18,10 +18,12 @@ package org.apache.sis.internal.jaxb;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.UUID;
import java.util.Collection;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.xml.IdentifierSpace;
+import org.apache.sis.xml.IdentifierAlreadyBoundException;
import org.apache.sis.xml.XLink;
// Related to JDK7
@@ -30,40 +32,53 @@ import java.util.Objects;
/**
* A map of identifiers which handles some identifiers in a special way.
- * The identifiers for the following authorities are handled in a special way.
- * See usages of {@link #specialCase(Object)} for spotting the code where
- * a special handling is applied.
+ * The identifiers for the following authorities are handled in a special way:
*
* <ul>
- * <li>{@link IdentifierSpace#HREF}, handled as a shortcut to {@link
XLink#getHRef()}.</li>
+ * <li>{@link IdentifierSpace#HREF}: handled as a shortcut to {@link
XLink#getHRef()}.</li>
+ * <li>{@link IdentifierSpace#UUID}: {@code put} operations register the
UUID in a shared map.</li>
* </ul>
*
+ * See usages of {@link #specialCase(Object)} for identifying the code
locations where a special
+ * handling is applied.
+ *
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.19)
* @version 0.3
* @module
*/
-final class IdentifierMapWithSpecialCases extends IdentifierMapAdapter {
+public final class IdentifierMapWithSpecialCases extends IdentifierMapAdapter {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 5139573827448780289L;
/**
+ * The object being referenced by the identifiers, or {@code null} if not
applicable.
+ */
+ private final Object referent;
+
+ /**
* Creates a new map which will be a view over the given identifiers.
*
* @param identifiers The identifiers to wrap in a map view.
+ * @param referent The object being referenced by the identifiers.
*/
- public IdentifierMapWithSpecialCases(final Collection<Identifier>
identifiers) {
+ public IdentifierMapWithSpecialCases(final Collection<Identifier>
identifiers, final Object referent) {
super(identifiers);
+ this.referent = referent;
}
/**
* If the given authority is a special case, returns its {@link
NonMarshalledAuthority}
* integer enum. Otherwise returns -1. See javadoc for more information
about special cases.
+ *
+ * @param authority A {@link Citation}Â constant. The type is relaxed to
{@code Object}
+ * Â because the signature of some {@code Map} methods are that way.
*/
private static int specialCase(final Object authority) {
if (authority == IdentifierSpace.HREF) return
NonMarshalledAuthority.HREF;
+ if (authority == IdentifierSpace.UUID) return
NonMarshalledAuthority.UUID;
// A future Apache SIS version may add more special cases here.
return -1;
}
@@ -91,19 +106,42 @@ final class IdentifierMapWithSpecialCase
* object.
*/
private URI setHRef(final URI href) {
- super.putSpecialized(IdentifierSpace.HREF, null);
+ URI old = super.putSpecialized(IdentifierSpace.HREF, null);
XLink link = super.getSpecialized(IdentifierSpace.XLINK);
if (link != null) {
- final URI old = link.getHRef();
+ if (old == null) {
+ old = link.getHRef();
+ }
link.setHRef(href);
- return old;
- }
- if (href != null) {
+ } else if (href != null) {
link = new XLink();
link.setHRef(href);
super.putSpecialized(IdentifierSpace.XLINK, link);
}
- return null;
+ return old;
+ }
+
+ /**
+ * Sets the {@code "gco:uuid"} value, which may be null. This method
stores the UUID-object
+ * association in a shared map, if no value existed previously.
+ *
+ * @param uuid The UUID to assign to the object.
+ * @return The previous value, or {@code null} if none.
+ * @throws IdentifierAlreadyBoundException If the given identifier is
already associated to another object.
+ */
+ private UUID setUUID(final UUID uuid) throws
IdentifierAlreadyBoundException {
+ if (referent == null) {
+ return super.putSpecialized(IdentifierSpace.UUID, uuid);
+ }
+ if (uuid != null) {
+ UUIDs.bind(uuid, referent); // May throws
IdentifierAlreadyBoundException
+ }
+ // Invoke 'put' only if UUIDs.bind(â¦) has been succesful.
+ final UUID old = super.putSpecialized(IdentifierSpace.UUID, uuid);
+ if (old != null && !old.equals(uuid)) {
+ UUIDs.unbind(old, referent);
+ }
+ return old;
}
/**
@@ -173,19 +211,40 @@ final class IdentifierMapWithSpecialCase
* {@inheritDoc}
*/
@Override
- public String put(final Citation authority, final String code) throws
UnsupportedOperationException {
+ public String put(final Citation authority, final String code)
+ throws IdentifierAlreadyBoundException,
UnsupportedOperationException
+ {
+ final Exception exception;
switch (specialCase(authority)) {
+ default: {
+ return super.put(authority, code);
+ }
case NonMarshalledAuthority.HREF: {
- try {
- final URI old = setHRef((code != null) ? new URI(code) :
null);
- return (old != null) ? old.toString() : null;
+ URI id = null;
+ if (code != null) try {
+ id = new URI(code);
} catch (URISyntaxException e) {
- // Do not log the exception, since it will be
- // reported by super.put(Citation, String).
+ exception = e;
+ break;
}
- break;
+ final String old = getUnspecialized(authority);
+ id = setHRef(id);
+ return (id != null) ? id.toString() : old;
+ }
+ case NonMarshalledAuthority.UUID: {
+ UUID id = null;
+ if (code != null) try {
+ id = UUID.fromString(code);
+ } catch (IllegalArgumentException e) {
+ exception = e;
+ break;
+ }
+ final String old = getUnspecialized(authority);
+ id = setUUID(id);
+ return (id != null) ? id.toString() : old;
}
}
+ SpecializedIdentifier.parseFailure(exception);
return super.put(authority, code);
}
@@ -194,12 +253,13 @@ final class IdentifierMapWithSpecialCase
*/
@Override
@SuppressWarnings("unchecked")
- public <T> T putSpecialized(final IdentifierSpace<T> authority, final T
value) throws UnsupportedOperationException {
+ public <T> T putSpecialized(final IdentifierSpace<T> authority, final T
value)
+ throws IdentifierAlreadyBoundException,
UnsupportedOperationException
+ {
switch (specialCase(authority)) {
- case NonMarshalledAuthority.HREF: {
- return (T) setHRef((URI) value);
- }
+ default: return super.putSpecialized(authority, value);
+ case NonMarshalledAuthority.HREF: return (T) setHRef((URI) value);
+ case NonMarshalledAuthority.UUID: return (T) setUUID((UUID) value);
}
- return super.putSpecialized(authority, value);
}
}
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
Mon Dec 3 15:11:48 2012
@@ -139,7 +139,7 @@ public final class SpecializedIdentifier
* This is considered a non-fatal error, because the parse method can
fallback
* on the generic {@link IdentifierMapEntry} in such cases.
*/
- private static void parseFailure(final Exception e) {
+ static void parseFailure(final Exception e) {
// IdentifierMap.put(Citation,String) is the public facade.
Logging.recoverableException(IdentifierMap.class, "put", e);
}
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/UUIDs.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/UUIDs.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/UUIDs.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/UUIDs.java
Mon Dec 3 15:11:48 2012
@@ -19,6 +19,7 @@ package org.apache.sis.internal.jaxb;
import java.util.UUID;
import org.apache.sis.util.Static;
import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.xml.IdentifierAlreadyBoundException;
/**
@@ -60,14 +61,33 @@ public final class UUIDs extends Static
/**
* Keep a weak references to the given object for the given UUID.
* If an object is already mapped to the given UUID, then the mapping is
<strong>not</strong>
- * modified and the currently mapped object is returned. The returned
object may or may not be
- * equals to the object given in argument to this method.
+ * modified. An exception is thrown instead.
*
* @param uuid The UUID to associate to the object.
* @param object The object to associate to the UUID.
- * @return If an object is already mapped to the given UUID, that object.
Otherwise {@code null}.
+ * @throws IdentifierAlreadyBoundException If the given identifier is
already associated to another object.
*/
- public static Object store(final UUID uuid, final Object object) {
- return OBJECTS.putIfAbsent(uuid, object);
+ static void bind(final UUID uuid, final Object object) throws
IdentifierAlreadyBoundException {
+ final Object old = OBJECTS.putIfAbsent(uuid, object);
+ if (old != null && old != object) {
+ throw new IdentifierAlreadyBoundException(null, uuid);
+ }
+ }
+
+ /**
+ * Removes the entry associated to the given UUID.
+ * If the given UUID is associated to another object than the given one,
+ * then this method does nothing.
+ *
+ * @param uuid The UUID of the entry to remove from the map.
+ * @param object The object to remove from the map.
+ */
+ static void unbind(final UUID uuid, final Object object) {
+ synchronized (OBJECTS) {
+ final Object old = OBJECTS.remove(uuid);
+ if (old != null && old != object) { // Same work than
ConcurrentMap.remove(Object, Object);
+ OBJECTS.put(uuid, old);
+ }
+ }
}
}
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
Mon Dec 3 15:11:48 2012
@@ -89,6 +89,11 @@ public final class Errors extends Indexe
public static final int ForbiddenAttribute_2 = 21;
/**
+ * Identifier â{0}â is already associated to another object.
+ */
+ public static final int IdentifierAlreadyBound_1 = 50;
+
+ /**
* Argument â{0}â can not be an instance of â{1}â.
*/
public static final int IllegalArgumentClass_2 = 17;
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
Mon Dec 3 15:11:48 2012
@@ -32,6 +32,7 @@ IllegalLanguageCode_1 = The \u
IllegalRange_2 = Range [{0} \u2026 {1}] is not valid.
InconsistentAttribute_2 = Value \u201c{1}\u201d of attribute
\u2018{0}\u2019 is inconsistent with other attributes.
InconsistentTableColumns = Inconsistent table columns.
+IdentifierAlreadyBound_1 = Identifier \u201c{0}\u201d is already
associated to another object.
IndexOutOfBounds_1 = Index {0} is out of bounds.
InfiniteArgumentValue_1 = Argument \u2018{0}\u2019 can not take an
infinite value.
KeyCollision_1 = A different value is already associated to
the \u201c{0}\u201d key.
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
Mon Dec 3 15:11:48 2012
@@ -32,6 +32,7 @@ IllegalLanguageCode_1 = Le cod
IllegalRange_2 = La plage [{0} \u2026 {1}] n\u2019est pas
valide.
InconsistentAttribute_2 = La valeur \u201c{1}\u201d de l\u2019attribut
\u2018{0}\u2019 n\u2019est pas coh\u00e9rente avec celles des autres attributs.
InconsistentTableColumns = Les colonnes des tables ne sont pas
coh\u00e9rentes.
+IdentifierAlreadyBound_1 = L\u2019identifiant \u201c{0}\u201d est
d\u00e9j\u00e0 associ\u00e9 \u00e0 un autre objet.
IndexOutOfBounds_1 = L\u2019index {0} est en dehors des limites
permises.
InfiniteArgumentValue_1 = L\u2019argument \u2018{0}\u2019 ne peut pas
prendre une valeur infinie.
KeyCollision_1 = Une valeur diff\u00e9rente est
d\u00e9j\u00e0 associ\u00e9e \u00e0 la cl\u00e9 \u201c{0}\u201d.
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java?rev=1416555&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
Mon Dec 3 15:11:48 2012
@@ -0,0 +1,90 @@
+/*
+ * 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.xml;
+
+import java.util.UUID;
+import java.util.Locale;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.LocalizedException;
+
+
+/**
+ * Throws when an object is given a {@code UUID} which is already assigned to
another object.
+ * While the same XML identifier can be used in different documents, {@link
UUID}s are expected
+ * to be truly unique.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+public class IdentifierAlreadyBoundException extends IllegalArgumentException
implements LocalizedException {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -7571733911210491933L;
+
+ /**
+ * The locale to use for formatting the {@linkplain #getLocalizedMessage()
localized error message}.
+ */
+ private final Locale locale;
+
+ /**
+ * The identifier which is already associated to another object.
+ * May be an instance of {@link UUID} or {@link XLink}.
+ *
+ * (Current constructor accepts only UUID, but we may
+ * expand the set of allowed types in a future version).
+ */
+ private final Object identifier;
+
+ /**
+ * Creates a new exception for the given identifier.
+ *
+ * @param locale The locale to use for the {@linkplain
#getLocalizedMessage() localized message}.
+ * @param identifier The identifier which is already associated to another
object.
+ */
+ public IdentifierAlreadyBoundException(final Locale locale, final UUID
identifier) {
+ super(Errors.format(Errors.Keys.IdentifierAlreadyBound_1, identifier));
+ this.locale = locale;
+ this.identifier = identifier;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getLocalizedMessage() {
+ return
Errors.getResources(locale).getString(Errors.Keys.IdentifierAlreadyBound_1,
identifier);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getLocalizedMessage(final Locale locale) {
+ return
Errors.getResources(locale).getString(Errors.Keys.IdentifierAlreadyBound_1,
identifier);
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierAlreadyBoundException.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierMap.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierMap.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierMap.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/IdentifierMap.java
Mon Dec 3 15:11:48 2012
@@ -64,7 +64,10 @@ public interface IdentifierMap extends M
* @param value The identifier to be associated with the given namespace.
* @return The previous identifier associated with {@code authority}, or
{@code null}
* if there was no mapping of the specialized type for {@code
authority}.
+ * @throws IdentifierAlreadyBoundException If this map expects unique
identifiers for the
+ * given authority, and the given value is already associated to
another object.
* @throws UnsupportedOperationException If the identifier map is
unmodifiable.
*/
- <T> T putSpecialized(IdentifierSpace<T> authority, T value) throws
UnsupportedOperationException;
+ <T> T putSpecialized(IdentifierSpace<T> authority, T value)
+ throws IdentifierAlreadyBoundException,
UnsupportedOperationException;
}
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/NilObjectHandler.java
Mon Dec 3 15:11:48 2012
@@ -31,6 +31,7 @@ import org.apache.sis.util.ComparisonMod
import org.apache.sis.util.LenientComparable;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.jaxb.IdentifierMapAdapter;
+import org.apache.sis.internal.jaxb.IdentifierMapWithSpecialCases;
// Related to JDK7
import java.util.Objects;
@@ -71,7 +72,7 @@ final class NilObjectHandler implements
asList.add(identifier);
}
}
- attribute = IdentifierMapAdapter.create(asList);
+ attribute = new IdentifierMapWithSpecialCases(asList, null);
}
/**
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapAdapterTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapAdapterTest.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapAdapterTest.java
(original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapAdapterTest.java
Mon Dec 3 15:11:48 2012
@@ -82,59 +82,71 @@ public strictfp class IdentifierMapAdapt
public void testGetAndPut() {
final List<Identifier> identifiers = new ArrayList<>();
final Map<Citation,String> map = create(identifiers);
- assertTrue(map.isEmpty());
- assertEquals(0, map.size());
-
+ assertTrue ("Newly created map shall be empty.", map.isEmpty());
+ assertEquals("Newly created map shall be empty.", 0, map.size());
+ /*
+ * Add two entries, then verify the map content.
+ */
identifiers.add(new IdentifierMapEntry(ID, "myID"));
identifiers.add(new IdentifierMapEntry(UUID, "myUUID"));
- assertFalse (map.isEmpty());
- assertEquals(2, map.size());
- assertEquals(2, identifiers.size());
- assertTrue (map.containsKey(ID));
- assertTrue (map.containsKey(UUID));
- assertFalse (map.containsKey(HREF));
- assertEquals("myID", map.get(ID));
- assertEquals("myUUID", map.get(UUID));
- assertNull ( map.get(HREF));
- assertTrue (map.containsValue("myID"));
- assertTrue (map.containsValue("myUUID"));
- assertFalse (map.containsValue("myHREF"));
+ assertFalse ("After add, map shall not be empty.", map.isEmpty());
+ assertEquals("After add, map shall not be empty.", 2, map.size());
+ assertEquals("After add, map shall not be empty.", 2,
identifiers.size());
+ assertTrue ("Shall contain the entry we added.",
map.containsKey(ID));
+ assertTrue ("Shall contain the entry we added.",
map.containsKey(UUID));
+ assertFalse ("Shall not contain entry we didn't added.",
map.containsKey(HREF));
+ assertTrue ("Shall contain the entry we added.",
map.containsValue("myID"));
+ assertTrue ("Shall contain the entry we added.",
map.containsValue("myUUID"));
+ assertFalse ("Shall not contain entry we didn't added.",
map.containsValue("myHREF"));
+ assertEquals("Shall contain the entry we added.", "myID",
map.get(ID));
+ assertEquals("Shall contain the entry we added.", "myUUID",
map.get(UUID));
+ assertNull ("Shall not contain entry we didn't added.",
map.get(HREF));
assertMapEquals("{gml:id=âmyIDâ, gco:uuid=âmyUUIDâ}", map);
-
- assertEquals("myUUID", map.put(UUID, "myNewUUID"));
- assertFalse (map.containsValue("myUUID"));
- assertTrue (map.containsValue("myNewUUID"));
+ /*
+ * Alter one entry (no new entry added).
+ */
+ assertEquals("Shall get the old value.", "myUUID", map.put(UUID,
"myNewUUID"));
+ assertFalse ("Shall not contain anymore the old value.",
map.containsValue("myUUID"));
+ assertTrue ("Shall contain the new value.",
map.containsValue("myNewUUID"));
assertMapEquals("{gml:id=âmyIDâ, gco:uuid=âmyNewUUIDâ}", map);
- assertEquals(2, map.size());
- assertEquals(2, identifiers.size());
-
- assertNull (map.put(HREF, "myHREF"));
- assertTrue (map.containsValue("myHREF"));
- assertTrue (map.containsKey(HREF));
+ assertEquals("Map size shall be unchanged.", 2, map.size());
+ assertEquals("Map size shall be unchanged.", 2, identifiers.size());
+ /*
+ * Add a third identifier.
+ */
+ assertNull ("Shall not contain entry we didn't added.", map.put(HREF,
"myHREF"));
+ assertTrue ("Shall contain the entry we added.",
map.containsValue("myHREF"));
+ assertTrue ("Shall contain the entry we added.",
map.containsKey(HREF));
assertMapEquals("{gml:id=âmyIDâ, gco:uuid=âmyNewUUIDâ,
xlink:href=âmyHREFâ}", map);
- assertEquals(3, map.size());
- assertEquals(3, identifiers.size());
-
- assertEquals("myNewUUID", map.remove(UUID));
- assertFalse (map.containsValue("myNewUUID"));
- assertFalse (map.containsKey(UUID));
+ assertEquals("Map size shall be updated.", 3, map.size());
+ assertEquals("Map size shall be updated.", 3, identifiers.size());
+ /*
+ * Remove an identifier using the Map.remove(â¦) API.
+ */
+ assertEquals("Shall get the old value.", "myNewUUID",
map.remove(UUID));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsValue("myNewUUID"));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsKey(UUID));
assertMapEquals("{gml:id=âmyIDâ, xlink:href=âmyHREFâ}", map);
- assertEquals(2, map.size());
- assertEquals(2, identifiers.size());
-
+ assertEquals("Map size shall be updated.", 2, map.size());
+ assertEquals("Map size shall be updated.", 2, identifiers.size());
+ /*
+ * Remove an identifier using the Set.remove(â¦) API on values.
+ */
assertTrue (map.values().remove(toHRefString("myHREF")));
- assertFalse (map.containsValue("myHREF"));
- assertFalse (map.containsKey(HREF));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsValue("myHREF"));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsKey(HREF));
assertMapEquals("{gml:id=âmyIDâ}", map);
- assertEquals(1, map.size());
- assertEquals(1, identifiers.size());
-
+ assertEquals("Map size shall be updated.", 1, map.size());
+ assertEquals("Map size shall be updated.", 1, identifiers.size());
+ /*
+ * Remove an identifier using the Set.remove(â¦) API on keys.
+ */
assertTrue (map.keySet().remove(ID));
- assertFalse (map.containsValue("myID"));
- assertFalse (map.containsKey(ID));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsValue("myID"));
+ assertFalse ("Shall not contain the entry we removed.",
map.containsKey(ID));
assertMapEquals("{}", map);
- assertEquals(0, map.size());
- assertEquals(0, identifiers.size());
+ assertEquals("Map size shall be updated.", 0, map.size());
+ assertEquals("Map size shall be updated.", 0, identifiers.size());
}
/**
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCasesTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCasesTest.java?rev=1416555&r1=1416554&r2=1416555&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCasesTest.java
(original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCasesTest.java
Mon Dec 3 15:11:48 2012
@@ -56,7 +56,7 @@ public final strictfp class IdentifierMa
*/
@Override
IdentifierMapAdapter create(final Collection<Identifier> identifiers) {
- return new IdentifierMapWithSpecialCases(identifiers);
+ return new IdentifierMapWithSpecialCases(identifiers, null);
}
/**