You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by tl...@apache.org on 2013/08/25 17:49:59 UTC
svn commit: r1517321 [10/16] - in /sis/branches/Shapefile: ./ application/
application/sis-console/ application/sis-console/src/main/artifact/
application/sis-console/src/main/java/org/apache/sis/console/
application/sis-console/src/main/resources/org/...
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -19,7 +19,12 @@ package org.apache.sis.internal.jaxb;
import java.util.Map;
import java.util.Locale;
import java.util.TimeZone;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
import org.apache.sis.util.Version;
+import org.apache.sis.util.Exceptions;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.logging.WarningListener;
import org.apache.sis.xml.MarshalContext;
import org.apache.sis.xml.ValueConverter;
import org.apache.sis.xml.ReferenceResolver;
@@ -38,7 +43,7 @@ import org.apache.sis.xml.ReferenceResol
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.07)
- * @version 0.3
+ * @version 0.4
* @module
*/
public final class Context extends MarshalContext {
@@ -63,6 +68,20 @@ public final class Context extends Marsh
public static final int SUBSTITUTE_COUNTRY = 4;
/**
+ * The bit flag for enabling substitution of filenames by character strings.
+ *
+ * @see org.apache.sis.xml.XML#STRING_SUBSTITUTES
+ */
+ public static final int SUBSTITUTE_FILENAME = 8;
+
+ /**
+ * The bit flag for enabling substitution of mime types by character strings.
+ *
+ * @see org.apache.sis.xml.XML#STRING_SUBSTITUTES
+ */
+ public static final int SUBSTITUTE_MIMETYPE = 16;
+
+ /**
* The thread-local context. Elements are created in the constructor, and removed in a
* {@code finally} block by the {@link #finish()} method. This {@code ThreadLocal} shall
* not contain any value when no (un)marshalling is in progress.
@@ -70,20 +89,20 @@ public final class Context extends Marsh
private static final ThreadLocal<Context> CURRENT = new ThreadLocal<Context>();
/**
- * The value converter currently in use, or {@code null} for {@link ValueConverter#DEFAULT}.
+ * Various boolean attributes determines by the above static constants.
*/
- private ValueConverter converter;
+ private int bitMasks;
/**
- * The reference resolver currently in use, or {@code null} for {@link ReferenceResolver#DEFAULT}.
+ * The locale to use for marshalling, or {@code null} if no locale were explicitly specified.
*/
- private ReferenceResolver resolver;
+ private Locale locale;
/**
- * The GML version to be marshalled or unmarshalled, or {@code null} if unspecified.
- * If null, than the latest version is assumed.
+ * The timezone, or {@code null} if unspecified.
+ * In the later case, an implementation-default (typically UTC) timezone is used.
*/
- private Version versionGML;
+ private TimeZone timezone;
/**
* The base URL of ISO 19139 (or other standards) schemas. The valid values
@@ -92,20 +111,25 @@ public final class Context extends Marsh
private Map<String,String> schemas;
/**
- * The locale to use for marshalling, or {@code null} if no locale were explicitly specified.
+ * The GML version to be marshalled or unmarshalled, or {@code null} if unspecified.
+ * If null, than the latest version is assumed.
*/
- private Locale locale;
+ private Version versionGML;
/**
- * The timezone, or {@code null} if unspecified.
- * In the later case, an implementation-default (typically UTC) timezone is used.
+ * The reference resolver currently in use, or {@code null} for {@link ReferenceResolver#DEFAULT}.
*/
- private TimeZone timezone;
+ private ReferenceResolver resolver;
/**
- * Various boolean attributes determines by the above static constants.
+ * The value converter currently in use, or {@code null} for {@link ValueConverter#DEFAULT}.
*/
- private int bitMasks;
+ private ValueConverter converter;
+
+ /**
+ * The object to inform about warnings, or {@code null} if none.
+ */
+ private WarningListener<?> warningListener;
/**
* The context which was previously used. This form a linked list allowing
@@ -127,26 +151,29 @@ public final class Context extends Marsh
* }
* }
*
- * @param converter The converter in use.
- * @param resolver The resolver in use.
- * @param versionGML The GML version, or {@code null}.
- * @param schemas The schemas root URL, or {@code null} if none.
- * @param locale The locale, or {@code null} if unspecified.
- * @param timezone The timezone, or {@code null} if unspecified.
- * @param bitMasks A combination of {@link #MARSHALLING}, {@link #SUBSTITUTE_LANGUAGE},
- * {@link #SUBSTITUTE_COUNTRY} or other bit masks.
- */
- public Context(final ValueConverter converter, final ReferenceResolver resolver,
- final Version versionGML, final Map<String,String> schemas,
- final Locale locale, final TimeZone timezone, final int bitMasks)
+ * @param bitMasks A combination of {@link #MARSHALLING}, {@code SUBSTITUTE_*} or other bit masks.
+ * @param locale The locale, or {@code null} if unspecified.
+ * @param timezone The timezone, or {@code null} if unspecified.
+ * @param schemas The schemas root URL, or {@code null} if none.
+ * @param versionGML The GML version, or {@code null}.
+ * @param resolver The resolver in use.
+ * @param converter The converter in use.
+ * @param warningListener The object to inform about warnings.
+ */
+ public Context(final int bitMasks,
+ final Locale locale, final TimeZone timezone,
+ final Map<String,String> schemas, final Version versionGML,
+ final ReferenceResolver resolver, final ValueConverter converter,
+ final WarningListener<?> warningListener)
{
- this.converter = converter;
- this.resolver = resolver;
- this.versionGML = versionGML;
- this.schemas = schemas; // No clone, because this class is internal.
- this.locale = locale;
- this.timezone = timezone;
- this.bitMasks = bitMasks;
+ this.bitMasks = bitMasks;
+ this.locale = locale;
+ this.timezone = timezone;
+ this.schemas = schemas; // No clone, because this class is internal.
+ this.versionGML = versionGML;
+ this.resolver = resolver;
+ this.converter = converter;
+ this.warningListener = warningListener;
previous = current();
CURRENT.set(this);
}
@@ -160,32 +187,20 @@ public final class Context extends Marsh
*/
private Context(final Context previous) {
if (previous != null) {
- converter = previous.converter;
- resolver = previous.resolver;
- versionGML = previous.versionGML;
- schemas = previous.schemas;
- locale = previous.locale;
- timezone = previous.timezone;
- bitMasks = previous.bitMasks;
+ bitMasks = previous.bitMasks;
+ locale = previous.locale;
+ timezone = previous.timezone;
+ schemas = previous.schemas;
+ versionGML = previous.versionGML;
+ resolver = previous.resolver;
+ converter = previous.converter;
+ warningListener = previous.warningListener;
}
this.previous = previous;
CURRENT.set(this);
}
/**
- * Returns the schema version of the XML document being (un)marshalled.
- * See the super-class javadoc for the list of prefix that we shall support.
- */
- @Override
- public final Version getVersion(final String prefix) {
- if (prefix.equals("gml")) {
- return versionGML;
- }
- // Future SIS versions may add more cases here.
- return null;
- }
-
- /**
* Returns the locale to use for marshalling, or {@code null} if no locale were explicitly
* specified.
*/
@@ -203,6 +218,19 @@ public final class Context extends Marsh
return timezone;
}
+ /**
+ * Returns the schema version of the XML document being (un)marshalled.
+ * See the super-class javadoc for the list of prefix that we shall support.
+ */
+ @Override
+ public final Version getVersion(final String prefix) {
+ if (prefix.equals("gml")) {
+ return versionGML;
+ }
+ // Future SIS versions may add more cases here.
+ return null;
+ }
+
/*
* ---- END OF PUBLIC API --------------------------------------------------------------
*
@@ -250,22 +278,58 @@ public final class Context extends Marsh
}
/**
- * Returns the value converter in use for the current marshalling or unmarshalling process.
- * If no converter were explicitely set, then this method returns {@link ValueConverter#DEFAULT}.
+ * Returns the base URL of ISO 19139 (or other standards) schemas.
+ * The valid values are documented in the {@link org.apache.sis.xml.XML#SCHEMAS} property.
+ * If the returned value is not empty, then this method guarantees it ends with {@code '/'}.
*
* {@note This method is static for the convenience of performing the check for null context.}
*
* @param context The current context, or {@code null} if none.
- * @return The current value converter (never null).
+ * @param key One of the value documented in the "<cite>Map key</cite>" column of
+ * {@link org.apache.sis.xml.XML#SCHEMAS}.
+ * @param defaultSchema The value to return if no schema is found for the given key.
+ * @return The base URL of the schema, or an empty buffer if none were specified.
*/
- public static ValueConverter converter(final Context context) {
+ public static StringBuilder schema(final Context context, final String key, String defaultSchema) {
+ final StringBuilder buffer = new StringBuilder(128);
if (context != null) {
- final ValueConverter converter = context.converter;
- if (converter != null) {
- return converter;
+ final Map<String,String> schemas = context.schemas;
+ if (schemas != null) {
+ final String schema = schemas.get(key);
+ if (schema != null) {
+ defaultSchema = schema;
+ }
}
}
- return ValueConverter.DEFAULT;
+ buffer.append(defaultSchema);
+ final int length = buffer.length();
+ if (length != 0 && buffer.charAt(length - 1) != '/') {
+ buffer.append('/');
+ }
+ return buffer;
+ }
+
+ /**
+ * Returns {@code true} if the GML version is equals or newer than the specified version.
+ * If no GML version were specified, then this method returns {@code true}, i.e. newest
+ * version is assumed.
+ *
+ * {@note This method is static for the convenience of performing the check for null context.}
+ *
+ * @param context The current context, or {@code null} if none.
+ * @param version The version to compare to.
+ * @return {@code true} if the GML version is equals or newer than the specified version.
+ *
+ * @see #getVersion(String)
+ */
+ public static boolean isGMLVersion(final Context context, final Version version) {
+ if (context != null) {
+ final Version versionGML = context.versionGML;
+ if (versionGML != null) {
+ return versionGML.compareTo(version) >= 0;
+ }
+ }
+ return true;
}
/**
@@ -288,51 +352,74 @@ public final class Context extends Marsh
}
/**
- * Returns the base URL of ISO 19139 (or other standards) schemas.
- * The valid values are documented in the {@link org.apache.sis.xml.XML#SCHEMAS} property.
+ * Returns the value converter in use for the current marshalling or unmarshalling process.
+ * If no converter were explicitely set, then this method returns {@link ValueConverter#DEFAULT}.
*
* {@note This method is static for the convenience of performing the check for null context.}
*
* @param context The current context, or {@code null} if none.
- * @param key One of the value documented in the "<cite>Map key</cite>" column of
- * {@link org.apache.sis.xml.XML#SCHEMAS}.
- * @param defaultSchema The value to return if no schema is found for the given key.
- * @return The base URL of the schema, or {@code null} if none were specified.
+ * @return The current value converter (never null).
*/
- public static String schema(final Context context, final String key, final String defaultSchema) {
+ public static ValueConverter converter(final Context context) {
if (context != null) {
- final Map<String,String> schemas = context.schemas;
- if (schemas != null) {
- final String schema = schemas.get(key);
- if (schema != null) {
- return schema;
- }
+ final ValueConverter converter = context.converter;
+ if (converter != null) {
+ return converter;
}
}
- return defaultSchema;
+ return ValueConverter.DEFAULT;
}
/**
- * Returns {@code true} if the GML version is equals or newer than the specified version.
- * If no GML version were specified, then this method returns {@code true}, i.e. newest
- * version is assumed.
- *
- * {@note This method is static for the convenience of performing the check for null context.}
- *
- * @param context The current context, or {@code null} if none.
- * @param version The version to compare to.
- * @return {@code true} if the GML version is equals or newer than the specified version.
- *
- * @see #getVersion(String)
- */
- public static boolean isGMLVersion(final Context context, final Version version) {
+ * Sends the given warning to the warning listener if there is one, or logs the warning otherwise.
+ * In the later case, this method logs to the logger specified by {@link LogRecord#getLoggerName()}
+ * if defined, or to the {@code "org.apache.sis.xml"} logger otherwise.
+ *
+ * @param context The current context, or {@code null} if none.
+ * @param source The object that emitted a warning. Can not be null.
+ * @param warning The warning.
+ */
+ @SuppressWarnings("unchecked")
+ public static void warningOccured(final Context context, final Object source, final LogRecord warning) {
+ String logger = warning.getLoggerName();
+ if (logger == null) {
+ warning.setLoggerName(logger = "org.apache.sis.xml");
+ }
if (context != null) {
- final Version versionGML = context.versionGML;
- if (versionGML != null) {
- return versionGML.compareTo(version) >= 0;
+ final WarningListener<?> warningListener = context.warningListener;
+ if (warningListener != null && warningListener.getSourceClass().isInstance(source)) {
+ ((WarningListener) warningListener).warningOccured(source, warning);
+ return;
}
}
- return true;
+ /*
+ * Log the warning without stack-trace, since this method shall be used only for non-fatal warnings
+ * and we want to avoid polluting the logs.
+ */
+ warning.setThrown(null);
+ Logging.getLogger(logger).log(warning);
+ }
+
+ /**
+ * Convenience method for sending a warning for the given exception.
+ * The logger will be {@code "org.apache.sis.xml"}.
+ *
+ * @param context The current context, or {@code null} if none.
+ * @param source The object that emitted a warning. Can not be null.
+ * @param classe The name of the class to declare as the warning source.
+ * @param method The name of the method to declare as the warning source.
+ * @param cause The exception which occurred.
+ * @param warning {@code true} for {@link Level#WARNING}, or {@code false} for {@link Level#FILE}.
+ */
+ public static void warningOccured(final Context context, final Object source, final Class<?> classe,
+ final String method, final Exception cause, final boolean warning)
+ {
+ final LogRecord record = new LogRecord(warning ? Level.WARNING : Level.FINE,
+ Exceptions.formatChainedMessages(context != null ? context.getLocale() : null, null, cause));
+ record.setSourceClassName(classe.getCanonicalName());
+ record.setSourceMethodName(method);
+ record.setThrown(cause);
+ warningOccured(context, source, record);
}
/**
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -273,7 +273,7 @@ public class IdentifierMapAdapter extend
}
}
if (code != null) {
- identifiers.add(SpecializedIdentifier.parse(authority, code));
+ identifiers.add(SpecializedIdentifier.parse(this, authority, code));
}
return old;
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapWithSpecialCases.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -22,6 +22,7 @@ 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.ValueConverter;
import org.apache.sis.xml.XLink;
// Related to JDK7
@@ -92,7 +93,9 @@ public final class IdentifierMapWithSpec
/**
* Sets the {@code xlink:href} value, which may be null. If an explicit {@code xlink:href}
* identifier exists, it is removed before to set the new {@code href} in the {@link XLink}
- * object.
+ * object. The intend is to give precedence to the {@link XLink#getHRef()} property in every
+ * cases where the {@code href} is parsable as a {@link URI}, and use the value associated
+ * to the {@code HREF} key only as a fallback when the string can not be parsed.
*/
private URI setHRef(final URI href) {
URI old = super.putSpecialized(IdentifierSpace.HREF, null);
@@ -175,35 +178,54 @@ public final class IdentifierMapWithSpec
/**
* {@inheritDoc}
+ *
+ * <p>If the given {@code authority} is {@code HREF} and if the given string is parsable as a {@link URI},
+ * then this method will actually store the value as the {@link XLink#getHRef()} property of the {@code XLink}
+ * associated to the {@code XLINK} key. Only if the given string can not be parsed, then the value is stored
+ * <cite>as-is</cite> under the {@code HREF} key.</p>
*/
@Override
public String put(final Citation authority, final String code)
throws UnsupportedOperationException
{
+ final Context context;
+ final Object removed;
+ final Class<?> type;
final Exception exception;
switch (specialCase(authority)) {
default: {
return super.put(authority, code);
}
case NonMarshalledAuthority.HREF: {
- URI id = null;
- if (code != null) try {
- id = new URI(code);
- } catch (URISyntaxException e) {
- exception = e;
- break;
+ URI uri = null;
+ if (code != null) {
+ context = Context.current();
+ final ValueConverter converter = Context.converter(context);
+ try {
+ uri = converter.toURI(context, code);
+ } catch (URISyntaxException e) {
+ exception = e;
+ removed = setHRef(null);
+ type = URI.class;
+ break;
+ }
}
final String old = getUnspecialized(authority);
- id = setHRef(id);
- return (id != null) ? id.toString() : old;
+ uri = setHRef(uri);
+ return (uri != null) ? uri.toString() : old;
}
}
- SpecializedIdentifier.parseFailure(exception);
- return super.put(authority, code);
+ SpecializedIdentifier.parseFailure(context, this, code, type, exception);
+ final String old = super.put(authority, code);
+ return (old == null && removed != null) ? removed.toString() : old;
}
/**
* {@inheritDoc}
+ *
+ * <p>If the given {@code authority} is {@code HREF}, then this method will actually store the value
+ * as the {@link XLink#getHRef()} property of the {@code XLink} associated to the {@code XLINK} key.
+ * The previous {@code HREF} value, if any, is discarded.</p>
*/
@Override
@SuppressWarnings("unchecked")
@@ -211,8 +233,12 @@ public final class IdentifierMapWithSpec
throws UnsupportedOperationException
{
switch (specialCase(authority)) {
- default: return super.putSpecialized(authority, value);
- case NonMarshalledAuthority.HREF: return (T) setHRef((URI) value);
+ default: {
+ return super.putSpecialized(authority, value);
+ }
+ case NonMarshalledAuthority.HREF: {
+ return (T) setHRef((URI) value);
+ }
}
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -283,6 +283,10 @@ public final class NonMarshalledAuthorit
warningLogged = true;
final LogRecord record = Errors.getResources(null).getLogRecord(Level.WARNING,
Errors.Keys.MissingRequiredModule_1, "sis-metadata");
+ /*
+ * Log directly the the logger rather than invoking the Context.warningOccured(…) method because
+ * this warning does not occur during XML (un)marshalling. It may occurs only during serialization.
+ */
record.setThrown(e);
Logging.log(NonMarshalledAuthority.class, "readResolve", record);
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -20,13 +20,16 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.UUID;
import java.io.Serializable;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.xml.XLink;
import org.apache.sis.xml.IdentifierMap;
import org.apache.sis.xml.IdentifierSpace;
+import org.apache.sis.xml.ValueConverter;
import org.apache.sis.util.Debug;
-import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Messages;
import org.apache.sis.internal.util.Citations;
// Related to JDK7
@@ -89,43 +92,43 @@ public final class SpecializedIdentifier
* authorities declared in the {@link IdentifierSpace} interface. Otherwise a
* plain {@link IdentifierMapEntry} is created.
*
+ * @param source The object to declare as the source in case of failure.
* @param authority The authority, typically as one of the {@link IdentifierSpace} constants.
- * @param code The identifier code to parse.
+ * @param code The identifier code to parse.
*
* @see IdentifierMapAdapter#put(Citation, String)
*/
- static Identifier parse(final Citation authority, final String code) {
+ static Identifier parse(final IdentifierMap source, final Citation authority, final String code) {
if (authority instanceof NonMarshalledAuthority) {
- switch (((NonMarshalledAuthority) authority).ordinal) {
+ final int ordinal = ((NonMarshalledAuthority) authority).ordinal;
+ switch (ordinal) {
case NonMarshalledAuthority.ID: {
return new SpecializedIdentifier<String>(IdentifierSpace.ID, code);
}
case NonMarshalledAuthority.UUID: {
+ final Context context = Context.current();
+ final ValueConverter converter = Context.converter(context);
try {
- return new SpecializedIdentifier<UUID>(IdentifierSpace.UUID, UUID.fromString(code));
+ return new SpecializedIdentifier<UUID>(IdentifierSpace.UUID, converter.toUUID(context, code));
} catch (IllegalArgumentException e) {
- parseFailure(e);
+ parseFailure(context, source, code, UUID.class, e);
break;
}
}
- case NonMarshalledAuthority.HREF: {
- final URI href;
- try {
- href = new URI(code);
- } catch (URISyntaxException e) {
- parseFailure(e);
- break;
- }
- return new SpecializedIdentifier<URI>(IdentifierSpace.HREF, href);
- }
+ case NonMarshalledAuthority.HREF:
case NonMarshalledAuthority.XLINK: {
+ final Context context = Context.current();
+ final ValueConverter converter = Context.converter(context);
final URI href;
try {
- href = new URI(code);
+ href = converter.toURI(context, code);
} catch (URISyntaxException e) {
- parseFailure(e);
+ parseFailure(context, source, code, URI.class, e);
break;
}
+ if (ordinal == NonMarshalledAuthority.HREF) {
+ return new SpecializedIdentifier<URI>(IdentifierSpace.HREF, href);
+ }
final XLink xlink = new XLink();
xlink.setHRef(href);
return new SpecializedIdentifier<XLink>(IdentifierSpace.XLINK, xlink);
@@ -139,14 +142,31 @@ public final class SpecializedIdentifier
* Invoked by {@link #parse(Citation,String)} when a string can not be parsed.
* This is considered a non-fatal error, because the parse method can fallback
* on the generic {@link IdentifierMapEntry} in such cases.
- */
- static void parseFailure(final Exception e) {
- // IdentifierMap.put(Citation,String) is the public facade.
- Logging.recoverableException(IdentifierMap.class, "put", e);
+ *
+ * <p>This method assumes that {@link IdentifierMap#put(Citation, String)} is
+ * the public API by which this method has been invoked.</p>
+ *
+ * @param context The marshalling context, or {@code null} if none.
+ * @param source The object to declare as the source of the warning.
+ * @param value The value that we failed to parse.
+ * @param type The target type of the parsing process.
+ * @param cause The exception that occurred during the parsing process.
+ */
+ static void parseFailure(final Context context, final IdentifierMap source,
+ final String value, final Class<?> type, final Exception cause)
+ {
+ final Messages resources = Messages.getResources(context != null ? context.getLocale() : null);
+ final LogRecord record = resources.getLogRecord(Level.WARNING, Messages.Keys.UnparsableValueStoredAsText_2, type, value);
+ record.setSourceClassName(IdentifierMap.class.getCanonicalName());
+ record.setSourceMethodName("put");
+ record.setThrown(cause);
+ Context.warningOccured(context, source, record);
}
/**
* Returns the authority specified at construction time.
+ *
+ * @return The identifier authority.
*/
@Override
public Citation getAuthority() {
@@ -166,6 +186,8 @@ public final class SpecializedIdentifier
/**
* Returns a string representation of the {@linkplain #getValue() identifier value},
* or {@code null} if none.
+ *
+ * @return The identifier value.
*/
@Override
public String getCode() {
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -47,9 +47,9 @@ import org.apache.sis.internal.system.Sy
*/
public abstract class TypeRegistration {
/**
- * The JAXB context, or {@code null} if not yet created.
+ * The JAXB context, or {@code null} if not yet created or if the classpath changed.
*/
- private static Reference<JAXBContext> context;
+ private static volatile Reference<JAXBContext> context;
static {
SystemListener.add(new SystemListener(Modules.UTILITIES) {
@Override protected void classpathChanged() {
@@ -105,9 +105,9 @@ public abstract class TypeRegistration {
* @throws JAXBException If an error occurred while creating the JAXB context.
*/
public static synchronized JAXBContext getSharedContext() throws JAXBException {
- final Reference<JAXBContext> ref = context; // Protect from changes by the listener.
- if (ref != null) {
- final JAXBContext instance = ref.get();
+ final Reference<JAXBContext> c = context;
+ if (c != null) {
+ final JAXBContext instance = c.get();
if (instance != null) {
return instance;
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -41,7 +41,7 @@ import org.apache.sis.internal.jaxb.gmd.
* @author Guilhem Legal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
* @module
*
* @see StringAdapter
@@ -71,7 +71,7 @@ public final class CharSequenceAdapter e
* in a XML file or stream. JAXB calls automatically this method at marshalling time.
*
* @param value The string value.
- * @return The wrapper for the given character sequence.
+ * @return The wrapper for the given character sequence, or {@code null}.
*/
@Override
public GO_CharacterString marshal(final CharSequence value) {
@@ -83,11 +83,11 @@ public final class CharSequenceAdapter e
* in a XML file or stream.
*
* @param value The character representation of the object being marshalled.
- * @return The wrapper for the given character sequence.
+ * @return The wrapper for the given character sequence, or {@code null}.
*/
public static GO_CharacterString wrap(CharSequence value) {
if (value instanceof String) {
- return wrap(value, (String) value); // Slightly more efficient variant of this method.
+ return wrap(Context.current(), value, (String) value); // Slightly more efficient variant of this method.
}
/*
* <gmd:someElement xsi:type="gmd:PT_FreeText_PropertyType">
@@ -147,25 +147,38 @@ public final class CharSequenceAdapter e
* This method is a copy of {@link #wrap(CharSequence)} simplified for the case when we know
* that the character sequence being marshalled is a string.
*
- * @param object The object being marshalled (e.g. {@code URI} or {@code Locale}).
- * @param string The string representation of the object being marshalled.
- * @return The wrapper for the given character sequence.
+ * @param context The current (un)marshalling context, or {@code null} if none.
+ * @param object The object being marshalled (e.g. {@code URI} or {@code Locale}).
+ * @param string The string representation of the object being marshalled.
+ * @return The wrapper for the given character sequence, or {@code null}.
*/
- public static GO_CharacterString wrap(final Object object, String string) {
+ public static GO_CharacterString wrap(final Context context, final Object object, final String string) {
+ final CharSequence text = value(context, object, string);
+ return (text != null) ? new GO_CharacterString(text) : null;
+ }
+
+ /**
+ * Same as {@link #wrap(Object, String)}, but returns directly the {@link GO_CharacterString#text}
+ * value without wrapping in a {@code GO_CharacterString} instance.
+ *
+ * @param context The current (un)marshalling context, or {@code null} if none.
+ * @param object The object being marshalled (e.g. {@code URI} or {@code Locale}).
+ * @param string The string representation of the object being marshalled.
+ * @return The text value for the given character sequence, or {@code null}.
+ */
+ public static CharSequence value(final Context context, final Object object, String string) {
string = CharSequences.trimWhitespaces(string);
if (string == null || string.isEmpty()) {
return null;
}
- CharSequence value = string;
- final Context context = Context.current();
final XLink linkage = Context.resolver(context).anchor(context, object, string);
if (linkage != null) {
if (linkage instanceof Anchor) {
- value = (Anchor) linkage;
+ return (Anchor) linkage;
} else {
- value = new Anchor(linkage, string);
+ return new Anchor(linkage, string);
}
}
- return new GO_CharacterString(value);
+ return string;
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Boolean.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Boolean.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Boolean.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Boolean.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -17,40 +17,21 @@
package org.apache.sis.internal.jaxb.gco;
import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Surrounds boolean value by {@code <gco:Boolean>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * The ISO-19139 standard requires most types to be surrounded by an element representing the value type.
+ * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper element.
+ * The role of this class is to add the {@code <gco:…>} wrapper element required by ISO 19139.
*
* @author Cédric Briançon (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.4
* @module
*/
-public final class GO_Boolean extends XmlAdapter<GO_Boolean, Boolean> {
- /**
- * Wraps the {@link Boolean#TRUE} value.
- */
- private static final GO_Boolean TRUE = new GO_Boolean(Boolean.TRUE);
-
- /**
- * Wraps the {@link Boolean#FALSE} value.
- */
- private static final GO_Boolean FALSE = new GO_Boolean(Boolean.FALSE);
-
- /**
- * The boolean value to handle.
- */
- @XmlElement(name = "Boolean")
- public Boolean value;
-
+public final class GO_Boolean extends PropertyType<GO_Boolean, Boolean> {
/**
* Empty constructor used only by JAXB.
*/
@@ -58,23 +39,20 @@ public final class GO_Boolean extends Xm
}
/**
- * Constructs an adapter for the given value.
+ * Constructs a wrapper for the given value.
*
* @param value The value.
*/
private GO_Boolean(final Boolean value) {
- this.value = value;
+ super(value, value.booleanValue() == false && value != Boolean.FALSE);
}
/**
- * Allows JAXB to generate a Boolean object using the value found in the adapter.
- *
- * @param value The value wrapped in an adapter.
- * @return The boolean value extracted from the adapter.
+ * Returns the Java type which is bound by this adapter.
*/
@Override
- public Boolean unmarshal(final GO_Boolean value) {
- return (value != null) ? value.value : null;
+ protected Class<Boolean> getBoundType() {
+ return Boolean.class;
}
/**
@@ -86,12 +64,26 @@ public final class GO_Boolean extends Xm
* by {@code <gco:Boolean>} element.
*/
@Override
- public GO_Boolean marshal(final Boolean value) {
- if (value == null) {
- return null;
- }
- final GO_Boolean c = value ? TRUE : FALSE;
- assert value.equals(c.value) : value;
- return c;
+ protected GO_Boolean wrap(final Boolean value) {
+ return new GO_Boolean(value);
+ }
+
+ /**
+ * Invoked by JAXB at marshalling time for getting the actual value to write.
+ *
+ * @return The value to be marshalled.
+ */
+ @XmlElement(name = "Boolean")
+ public Boolean getElement() {
+ return skip() ? null : metadata;
+ }
+
+ /**
+ * Invoked by JAXB at unmarshalling time for storing the result temporarily.
+ *
+ * @param metadata The unmarshalled value.
+ */
+ public void setElement(final Boolean metadata) {
+ this.metadata = metadata;
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -16,32 +16,77 @@
*/
package org.apache.sis.internal.jaxb.gco;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
-
import org.apache.sis.xml.Namespaces;
-import org.apache.sis.internal.jaxb.gmd.PT_FreeText;
-import org.apache.sis.internal.jaxb.gmd.LanguageCode;
-import org.apache.sis.internal.jaxb.gmd.Country;
+import org.apache.sis.internal.jaxb.Context;
import org.apache.sis.internal.jaxb.gmx.Anchor;
+import org.apache.sis.internal.jaxb.gmx.FileName;
+import org.apache.sis.internal.jaxb.gmx.MimeFileType;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Messages;
/**
- * JAXB wrapper for string value in a {@code <gco:CharacterString>} or {@code <gmx:Anchor>} element,
- * for ISO-19139 compliance.
+ * JAXB wrapper for string value in a {@code <gco:CharacterString>}, {@code <gmx:Anchor>},
+ * {@code <gmx:FileName>} or {@code <gmx:MimeFileType>} element, for ISO-19139 compliance.
+ *
+ * <p>{@code FileName} and {@code MimeFileType} are possible substitutions for {@code CharacterString}.
+ * They make sense only in {@link org.apache.sis.metadata.iso.identification.DefaultBrowseGraphic} or
+ * other classes using URI, but the XML schema does not prevent their usage in place of other strings.
+ * Consequently we unconditionally accept {@code FileName} and {@code MimeFileType} at unmarshalling time.
+ * However marshalling will use the appropriate element for the kind of property to marshal.</p>
*
* @author Cédric Briançon (Geomatys)
* @since 0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.4
* @module
*
* @see org.apache.sis.internal.jaxb.gmd.PT_FreeText
*/
@XmlType(name = "CharacterString_PropertyType")
-@XmlSeeAlso({PT_FreeText.class, LanguageCode.class, Country.class})
+@XmlSeeAlso({
+ org.apache.sis.internal.jaxb.gmd.PT_FreeText.class,
+ org.apache.sis.internal.jaxb.gmd.LanguageCode.class,
+ org.apache.sis.internal.jaxb.gmd.Country.class
+})
public class GO_CharacterString {
+ /*
+ * Numerical values below are ordered: if two or more values are defined (thoerically not legal,
+ * but we try to be robust), the value associated to the highest constant has precedence.
+ */
+ /**
+ * Value assigned to {@link #type} if the character string
+ * shall be marshalled as a {@code <gmx:MimeFileType>} element.
+ */
+ public static final byte MIME_TYPE = 1;
+
+ /**
+ * Value assigned to {@link #type} if the character string
+ * shall be marshalled as a {@code <gmx:FileName>} element.
+ */
+ public static final byte FILENAME = 2;
+
+ /**
+ * Value assigned to {@link #type} if the current {@link #text}
+ * has been found in a {@code <gco:CharacterString>} element.
+ */
+ private static final byte ANCHOR = 3;
+
+ /**
+ * The XML element names for each possible {@link #type} values.
+ */
+ private static final String[] NAMES = new String[4];
+ static {
+ NAMES[0] = "CharacterString";
+ NAMES[MIME_TYPE] = "MimeFileType";
+ NAMES[FILENAME] = "FileName";
+ NAMES[ANCHOR] = "Anchor";
+ }
+
/**
* The text or anchor value, or {@code null} if none. May be an instance
* of {@link Anchor}, which needs to be handled in a special way.
@@ -49,13 +94,22 @@ public class GO_CharacterString {
private CharSequence text;
/**
+ * 0 if the text shall be marshalled as a {@code <gco:CharacterString>} or an anchor,
+ * or one of the static constants in this class otherwise.
+ *
+ * @see #FILENAME
+ * @see #MIME_TYPE
+ */
+ public byte type;
+
+ /**
* Empty constructor for JAXB and subclasses.
*/
- protected GO_CharacterString() {
+ public GO_CharacterString() {
}
/**
- * Builds an wrapper for the given text.
+ * Builds a wrapper for the given text.
*
* @param text The string to marshal, or {@code null} if none.
*/
@@ -64,38 +118,118 @@ public class GO_CharacterString {
}
/**
- * Builds an wrapper as a copy of the given one.
+ * Sets the {@link #text} field to the given value.
+ * If the given value overwrites a previous one, a warning is emitted.
*
- * @param text The wrapper to copy, or {@code null} if none.
+ * @param value The value to set.
+ * @param property 0 or one of the {@link #MIME_TYPE}, {@link #FILENAME} or {@link #ANCHOR} constants.
*/
- protected GO_CharacterString(final GO_CharacterString text) {
- if (text != null) {
- this.text = text.text;
+ private void setText(final CharSequence value, byte property) {
+ if (text != null && !value.equals(text)) {
+ /*
+ * The given value overwrite a previous one. Determine which value will be discarded
+ * using the 'type' value as a criterion, then emit a warning.
+ */
+ byte discarded = type;
+ boolean noset = false;
+ if (discarded > property) {
+ discarded = property;
+ property = type;
+ noset = true;
+ }
+ final Context context = Context.current();
+ final LogRecord record = Messages.getResources(context != null ? context.getLocale() : null)
+ .getLogRecord(Level.WARNING, Messages.Keys.DiscardedExclusiveProperty_2,
+ NAMES[discarded], NAMES[property]);
+ record.setSourceClassName(getClass().getCanonicalName());
+ record.setSourceMethodName("setText");
+ Context.warningOccured(context, value, record);
+ if (noset) {
+ return;
+ }
}
+ text = value;
+ type = property;
}
/**
- * Returns the text. This method is called by JAXB at marshalling time.
+ * Returns the text in a {@code <gco:CharacterString>} element, or {@code null} if none.
*
* @return The text, or {@code null}.
*/
@XmlElement(name = "CharacterString")
public final String getCharacterString() {
- final CharSequence text = this.text;
- return (text == null || text instanceof Anchor) ? null : text.toString();
+ if (type == 0) {
+ final CharSequence text = this.text;
+ if (text != null && !(text instanceof Anchor)) {
+ return text.toString();
+ }
+ }
+ return null;
}
/**
* Sets the value to the given string. This method is called by JAXB at unmarshalling time.
*
- * @param text The new text.
+ * @param value The new text.
*/
- public final void setCharacterString(String text) {
- text = CharSequences.trimWhitespaces(text);
- if (text != null && text.isEmpty()) {
- text = null;
+ public final void setCharacterString(String value) {
+ value = CharSequences.trimWhitespaces(value);
+ if (value != null && !value.isEmpty()) {
+ setText(value, (byte) 0);
+ }
+ }
+
+ /**
+ * Returns the text in a {@code <gmx:FileName>} element, or {@code null} if none.
+ */
+ @XmlElement(name = "FileName", namespace = Namespaces.GMX)
+ final FileName getFileName() {
+ if (type == FILENAME) {
+ final CharSequence text = this.text;
+ if (text != null && !(text instanceof Anchor)) {
+ return new FileName(text.toString());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Invoked by JAXB for setting the filename.
+ */
+ final void setFileName(final FileName file) {
+ if (file != null) {
+ final String value = CharSequences.trimWhitespaces(file.toString());
+ if (value != null && !value.isEmpty()) {
+ setText(value, FILENAME);
+ }
+ }
+ }
+
+ /**
+ * Returns the text in a {@code <gmx:MimeFileType>} element, or {@code null} if none.
+ */
+ @XmlElement(name = "MimeFileType", namespace = Namespaces.GMX)
+ final MimeFileType getMimeFileType() {
+ if (type == MIME_TYPE) {
+ final CharSequence text = this.text;
+ if (text != null && !(text instanceof Anchor)) {
+ return new MimeFileType(text.toString());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Invoked by JAXB for setting the MIME type.
+ */
+ final void setMimeFileType(final MimeFileType type) {
+ if (type != null) {
+ final String value = CharSequences.trimWhitespaces(type.toString());
+ if (value != null && !value.isEmpty()) {
+ setText(value, MIME_TYPE);
+ }
}
- this.text = text;
}
/**
@@ -117,7 +251,7 @@ public class GO_CharacterString {
* @param anchor The new anchor.
*/
public final void setAnchor(final Anchor anchor) {
- this.text = anchor;
+ setText(anchor, ANCHOR);
}
/**
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -17,16 +17,19 @@
package org.apache.sis.internal.jaxb.gco;
import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Surrounds double values by {@code <gco:Decimal>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * The ISO-19139 standard requires most types to be surrounded by an element representing the value type.
+ * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper element.
+ * The role of this class is to add the {@code <gco:…>} wrapper element required by ISO 19139.
+ *
+ * {@section Relationship with <code>GO_Real</code>}
+ * This adapter is identical to {@link GO_Real} except for the element name, which is {@code "Decimal"} instead
+ * than {@code "Real"}. This adapter is used for the {@code westBoundLongitude}, {@code eastBoundLongitude},
+ * {@code southBoundLatitude} and {@code northBoundLatitude} properties of {@code EX_DefaultGeographicBoundingBox}.
+ * The {@code GO_Real} adapter is used for about everything else.
*
* @author Cédric Briançon (Geomatys)
* @author Martin Desruisseaux (Geomatys)
@@ -35,31 +38,9 @@ import javax.xml.bind.annotation.adapter
* @module
*
* @see GO_Real
- * @see AsFloat
+ * @see GO_Decimal32
*/
-public final class GO_Decimal extends XmlAdapter<GO_Decimal, Double> {
- /**
- * Frequently used constants.
- */
- private static final GO_Decimal
- P0 = new GO_Decimal( 0.0),
- P1 = new GO_Decimal( 1.0),
- N1 = new GO_Decimal( -1.0),
- P45 = new GO_Decimal( 45.0),
- N45 = new GO_Decimal( -45.0),
- P90 = new GO_Decimal( 90.0),
- N90 = new GO_Decimal( -90.0),
- P180 = new GO_Decimal( 180.0),
- N180 = new GO_Decimal(-180.0),
- P360 = new GO_Decimal( 360.0),
- N360 = new GO_Decimal(-360.0);
-
- /**
- * The double value to handle.
- */
- @XmlElement(name = "Decimal")
- public Double value;
-
+public final class GO_Decimal extends PropertyType<GO_Decimal, Double> {
/**
* Empty constructor used only by JAXB.
*/
@@ -67,23 +48,20 @@ public final class GO_Decimal extends Xm
}
/**
- * Constructs an adapter for the given value.
+ * Constructs a wrapper for the given value.
*
* @param value The value.
*/
private GO_Decimal(final Double value) {
- this.value = value;
+ super(value, value.isNaN());
}
/**
- * Allows JAXB to generate a Double object using the value found in the adapter.
- *
- * @param value The value wrapped in an adapter.
- * @return The double value extracted from the adapter.
+ * Returns the Java type which is bound by this adapter.
*/
@Override
- public Double unmarshal(final GO_Decimal value) {
- return (value != null) ? value.value : null;
+ protected Class<Double> getBoundType() {
+ return Double.class;
}
/**
@@ -95,94 +73,26 @@ public final class GO_Decimal extends Xm
* by {@code <gco:Decimal>} element.
*/
@Override
- public GO_Decimal marshal(final Double value) {
- if (value == null) {
- return null;
- }
- final GO_Decimal c;
- final int index = value.intValue();
- if (index == value.doubleValue()) {
- switch (index) {
- case 0: c = P0; break;
- case 1: c = P1; break;
- case -1: c = N1; break;
- case 45: c = P45; break;
- case -45: c = N45; break;
- case 90: c = P90; break;
- case -90: c = N90; break;
- case 180: c = P180; break;
- case -180: c = N180; break;
- case 360: c = P360; break;
- case -360: c = N360; break;
- default: c = new GO_Decimal(value);
- }
- } else {
- c = new GO_Decimal(value);
- }
- assert value.equals(c.value) : value;
- return c;
+ public GO_Decimal wrap(final Double value) {
+ return new GO_Decimal(value);
}
-
-
+ /**
+ * Invoked by JAXB at marshalling time for getting the actual value to write.
+ *
+ * @return The value to be marshalled.
+ */
+ @XmlElement(name = "Decimal")
+ public Double getElement() {
+ return skip() ? null : metadata;
+ }
/**
- * Surrounds float values by {@code <gco:Decimal>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * Invoked by JAXB at unmarshalling time for storing the result temporarily.
*
- * @author Cédric Briançon (Geomatys)
- * @since 0.3 (derived from geotk-2.5)
- * @version 0.3
- * @module
- */
- public static final class AsFloat extends XmlAdapter<AsFloat, Float> {
- /**
- * The float value to handle.
- */
- @XmlElement(name = "Decimal")
- public Float value;
-
- /**
- * Empty constructor used only by JAXB.
- */
- public AsFloat() {
- }
-
- /**
- * Constructs an adapter for the given value.
- *
- * @param value The value.
- */
- private AsFloat(final Float value) {
- this.value = value;
- }
-
- /**
- * Allows JAXB to generate a Float object using the value found in the adapter.
- *
- * @param value The value wrapped in an adapter.
- * @return The float value extracted from the adapter.
- */
- @Override
- public Float unmarshal(final AsFloat value) {
- return (value != null) ? value.value : null;
- }
-
- /**
- * Allows JAXB to change the result of the marshalling process, according to the
- * ISO-19139 standard and its requirements about primitive types.
- *
- * @param value The float value we want to surround by an element representing its type.
- * @return An adaptation of the float value, that is to say a float value surrounded
- * by {@code <gco:Decimal>} element.
- */
- @Override
- public AsFloat marshal(final Float value) {
- return (value != null) ? new AsFloat(value) : null;
- }
+ * @param metadata The unmarshalled value.
+ */
+ public void setElement(final Double metadata) {
+ this.metadata = metadata;
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_GenericName.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_GenericName.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_GenericName.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_GenericName.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -16,19 +16,8 @@
*/
package org.apache.sis.internal.jaxb.gco;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-
-import org.opengis.util.TypeName;
-import org.opengis.util.LocalName;
-import org.opengis.util.MemberName;
import org.opengis.util.GenericName;
-
import org.apache.sis.util.iso.AbstractName;
-import org.apache.sis.util.iso.DefaultTypeName;
-import org.apache.sis.util.iso.DefaultMemberName;
-import org.apache.sis.util.iso.DefaultScopedName;
-import org.apache.sis.util.resources.Errors;
/**
@@ -50,12 +39,7 @@ import org.apache.sis.util.resources.Err
* @version 0.3
* @module
*/
-public final class GO_GenericName extends XmlAdapter<GO_GenericName, GenericName> {
- /**
- * The generic name to be marshalled.
- */
- private AbstractName name;
-
+public final class GO_GenericName extends NameAdapter<GO_GenericName, GenericName> {
/**
* Empty constructor for JAXB only.
*/
@@ -65,128 +49,8 @@ public final class GO_GenericName extend
/**
* Wraps a name at marshalling-time.
*/
- private GO_GenericName(final AbstractName name) {
- this.name = name;
- }
-
- /**
- * Ensures that the {@linkplain #name} is not already defined.
- *
- * @throws IllegalStateException If a name is already defined.
- */
- private void ensureUndefined() throws IllegalStateException {
- if (name != null) {
- throw new IllegalStateException(Errors.format(Errors.Keys.ValueAlreadyDefined_1, "name"));
- }
- }
-
- /**
- * Returns the {@code LocalName} generated from the metadata value.
- * The local name is returned only if it is not a {@link TypeName} or a {@link MemberName}
- * (otherwise, the corresponding {@code getXXX()} method needs to be invoked instead.
- *
- * @return The current local name, or {@code null} if none.
- *
- * @see #getTypeName()
- * @see #getMemberName()
- */
- @XmlElement(name = "LocalName")
- public String getLocalName() {
- final Object name = this.name;
- return (name instanceof LocalName) && !(name instanceof TypeName)
- && !(name instanceof MemberName) ? name.toString() : null;
- }
-
- /**
- * Sets the value for the {@code LocalName}.
- * This method is called at unmarshalling-time by JAXB.
- *
- * @param name The new name.
- * @throws IllegalStateException If a name is already defined.
- */
- public void setLocalName(final String name) throws IllegalStateException {
- ensureUndefined();
- if (name == null) {
- this.name = null;
- } else {
- /*
- * Following cast should be safe because the getNameFactory() method asked specifically
- * for a DefaultNameFactory instance, which is known to create AbstractName instances.
- */
- this.name = (AbstractName) LocalNameAdapter.getNameFactory().createLocalName(null, name);
- }
- }
-
- /**
- * Returns the {@code ScopedName} generated from the metadata value.
- * This method is called at marshalling-time by JAXB.
- *
- * @return The current name, or {@code null} if none.
- */
- @XmlElement(name = "ScopedName")
- public DefaultScopedName getScopedName() {
- final Object name = this.name;
- return (name instanceof DefaultScopedName) ? (DefaultScopedName) name : null;
- }
-
- /**
- * Sets the value for the {@code ScopedName}.
- * This method is called at unmarshalling-time by JAXB.
- *
- * @param name The new name.
- * @throws IllegalStateException If a name is already defined.
- */
- public void setScopedName(final DefaultScopedName name) throws IllegalStateException {
- ensureUndefined();
- this.name = name;
- }
-
- /**
- * Returns the {@code TypeName} generated from the metadata value.
- * This method is called at marshalling-time by JAXB.
- *
- * @return The current name, or {@code null} if none.
- */
- @XmlElement(name = "TypeName")
- public DefaultTypeName getTypeName() {
- final Object name = this.name;
- return (name instanceof DefaultTypeName) ? (DefaultTypeName) name : null;
- }
-
- /**
- * Sets the value for the {@code TypeName}.
- * This method is called at unmarshalling-time by JAXB.
- *
- * @param name The new name.
- * @throws IllegalStateException If a name is already defined.
- */
- public void setTypeName(final DefaultTypeName name) throws IllegalStateException {
- ensureUndefined();
- this.name = name;
- }
-
- /**
- * Returns the {@code MemberName} generated from the metadata value.
- * This method is called at marshalling-time by JAXB.
- *
- * @return The current name, or {@code null} if none.
- */
- @XmlElement(name = "MemberName")
- public DefaultMemberName getMemberName() {
- final Object name = this.name;
- return (name instanceof MemberName) ? (DefaultMemberName) name : null;
- }
-
- /**
- * Sets the value for the {@code MemberName}.
- * This method is called at unmarshalling-time by JAXB.
- *
- * @param name The new name.
- * @throws IllegalStateException If a name is already defined.
- */
- public void setMemberName(final DefaultMemberName name) throws IllegalStateException {
- ensureUndefined();
- this.name = name;
+ private GO_GenericName(final AbstractName value) {
+ name = value;
}
/**
@@ -198,20 +62,7 @@ public final class GO_GenericName extend
*/
@Override
public GO_GenericName marshal(final GenericName value) {
- if (value == null) {
- return null;
- }
- final AbstractName name;
- if (value instanceof AbstractName) {
- name = (AbstractName) value;
- } else {
- /*
- * Following cast should be safe because the getNameFactory() method asked specifically
- * for a DefaultNameFactory instance, which is known to create AbstractName instances.
- */
- name = (AbstractName) ScopedNameAdapter.wrap(value, LocalNameAdapter.getNameFactory());
- }
- return new GO_GenericName(name);
+ return (value != null) ? new GO_GenericName(AbstractName.castOrCopy(value)) : null;
}
/**
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -17,42 +17,23 @@
package org.apache.sis.internal.jaxb.gco;
import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Surrounds integer values by {@code <gco:Integer>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * The ISO-19139 standard requires most types to be surrounded by an element representing the value type.
+ * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper element.
+ * The role of this class is to add the {@code <gco:…>} wrapper element required by ISO 19139.
*
* @author Cédric Briançon (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.4
* @module
*
- * @see AsLong
+ * @see GO_Integer64
*/
-public final class GO_Integer extends XmlAdapter<GO_Integer, Integer> {
- /**
- * Frequently used constants.
- */
- private static final GO_Integer[] CONSTANTS = new GO_Integer[5];
- static {
- for (int i=0; i<CONSTANTS.length; i++) {
- CONSTANTS[i] = new GO_Integer(i);
- }
- }
-
- /**
- * The integer value to handle.
- */
- @XmlElement(name = "Integer")
- public Integer value;
-
+public final class GO_Integer extends PropertyType<GO_Integer, Integer> {
/**
* Empty constructor used only by JAXB.
*/
@@ -60,23 +41,20 @@ public final class GO_Integer extends Xm
}
/**
- * Constructs an adapter for the given value.
+ * Constructs a wrapper for the given value.
*
* @param value The value.
*/
private GO_Integer(final Integer value) {
- this.value = value;
+ super(value, value.intValue() == 0);
}
/**
- * Allows JAXB to generate an Integer object using the value found in the adapter.
- *
- * @param value The value wrapped in an adapter.
- * @return The integer value extracted from the adapter.
+ * Returns the Java type which is bound by this adapter.
*/
@Override
- public Integer unmarshal(final GO_Integer value) {
- return (value != null) ? value.value : null;
+ protected Class<Integer> getBoundType() {
+ return Integer.class;
}
/**
@@ -88,76 +66,26 @@ public final class GO_Integer extends Xm
* by {@code <gco:Integer>} element.
*/
@Override
- public GO_Integer marshal(final Integer value) {
- if (value == null) {
- return null;
- }
- final int i = value;
- final GO_Integer c = (i >= 0 && i < CONSTANTS.length) ? CONSTANTS[i] : new GO_Integer(value);
- assert value.equals(c.value) : value;
- return c;
+ public GO_Integer wrap(final Integer value) {
+ return new GO_Integer(value);
}
-
-
+ /**
+ * Invoked by JAXB at marshalling time for getting the actual value to write.
+ *
+ * @return The value to be marshalled.
+ */
+ @XmlElement(name = "Integer")
+ public Integer getElement() {
+ return skip() ? null : metadata;
+ }
/**
- * Surrounds long values by {@code <gco:Integer>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * Invoked by JAXB at unmarshalling time for storing the result temporarily.
*
- * @author Cédric Briançon (Geomatys)
- * @since 0.3 (derived from geotk-2.5)
- * @version 0.3
- * @module
- */
- public static final class AsLong extends XmlAdapter<AsLong, Long> {
- /**
- * The long value to handle.
- */
- @XmlElement(name = "Integer")
- public Long value;
-
- /**
- * Empty constructor used only by JAXB.
- */
- public AsLong() {
- }
-
- /**
- * Constructs an adapter for the given value.
- *
- * @param value The value.
- */
- private AsLong(final Long value) {
- this.value = value;
- }
-
- /**
- * Allows JAXB to generate a Long object using the value found in the adapter.
- *
- * @param value The value wrapped in an adapter.
- * @return The long value extracted from the adapter.
- */
- @Override
- public Long unmarshal(final AsLong value) {
- return (value != null) ? value.value : null;
- }
-
- /**
- * Allows JAXB to change the result of the marshalling process, according to the
- * ISO-19139 standard and its requirements about primitive types.
- *
- * @param value The integer value we want to surround by an element representing its type.
- * @return An adaptation of the integer value, that is to say a integer value surrounded
- * by {@code <gco:Integer>} element.
- */
- @Override
- public AsLong marshal(final Long value) {
- return (value != null) ? new AsLong(value) : null;
- }
+ * @param metadata The unmarshalled value.
+ */
+ public void setElement(final Integer metadata) {
+ this.metadata = metadata;
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Real.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Real.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Real.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Real.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -17,31 +17,25 @@
package org.apache.sis.internal.jaxb.gco;
import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* Surrounds double values by {@code <gco:Real>}.
- * The ISO-19139 standard specifies that primitive types have to be surrounded by an element
- * which represents the type of the value, using the namespace {@code gco} linked to the
- * {@code http://www.isotc211.org/2005/gco} URL. The JAXB default behavior is to marshal
- * primitive Java types directly "as is", without wrapping the value in the required element.
- * The role of this class is to add such wrapping.
+ * The ISO-19139 standard requires most types to be surrounded by an element representing the value type.
+ * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper element.
+ * The role of this class is to add the {@code <gco:…>} wrapper element required by ISO 19139.
+ *
+ * {@section Relationship with <code>GO_Decimal</code>}
+ * This adapter is identical to {@link GO_Decimal} except for the element name, which is {@code "Real"}
+ * instead than {@code "Decimal"}. This adapter is the most widely used one in IS 19139 XML schema.
+ * The few exceptions are documented in {@link GO_Decimal}.
*
* @author Cédric Briançon (Geomatys)
* @since 0.3 (derived from geotk-2.5)
* @version 0.3
* @module
- *
- * @see GO_Decimal
*/
-public final class GO_Real extends XmlAdapter<GO_Real, Double> {
- /**
- * The double value to handle.
- */
- @XmlElement(name = "Real")
- public Double value;
-
+public final class GO_Real extends PropertyType<GO_Real, Double> {
/**
* Empty constructor used only by JAXB.
*/
@@ -49,23 +43,20 @@ public final class GO_Real extends XmlAd
}
/**
- * Constructs an adapter for this value.
+ * Constructs a wrapper for the given value.
*
* @param value The value.
*/
private GO_Real(final Double value) {
- this.value = value;
+ super(value, value.isNaN());
}
/**
- * Allows JAXB to generate a Double object using the value found in the adapter.
- *
- * @param value The value extract from the adapter.
- * @return A double object.
+ * Returns the Java type which is bound by this adapter.
*/
@Override
- public Double unmarshal(final GO_Real value) {
- return (value != null) ? value.value : null;
+ protected Class<Double> getBoundType() {
+ return Double.class;
}
/**
@@ -77,7 +68,26 @@ public final class GO_Real extends XmlAd
* by {@code <gco:Real>} element.
*/
@Override
- public GO_Real marshal(final Double value) {
- return (value != null) ? new GO_Real(value) : null;
+ public GO_Real wrap(final Double value) {
+ return new GO_Real(value);
+ }
+
+ /**
+ * Invoked by JAXB at marshalling time for getting the actual value to write.
+ *
+ * @return The value to be marshalled.
+ */
+ @XmlElement(name = "Real")
+ public Double getElement() {
+ return skip() ? null : metadata;
+ }
+
+ /**
+ * Invoked by JAXB at unmarshalling time for storing the result temporarily.
+ *
+ * @param metadata The unmarshalled value.
+ */
+ public void setElement(final Double metadata) {
+ this.metadata = metadata;
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/InternationalStringConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/InternationalStringConverter.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/InternationalStringConverter.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/InternationalStringConverter.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -58,6 +58,6 @@ public final class InternationalStringCo
*/
@Override
public String marshal(final InternationalString value) {
- return (value != null) ? value.toString() : null;
+ return StringAdapter.toString(value);
}
}
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectIdentification.html
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectIdentification.html?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectIdentification.html (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectIdentification.html Sun Aug 25 15:49:51 2013
@@ -1,4 +1,24 @@
<!DOCTYPE html>
+
+<!--
+ 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.
+-->
+
<html>
<head>
<title>ObjectIdentification</title>
Modified: sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectReference.java
URL: http://svn.apache.org/viewvc/sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectReference.java?rev=1517321&r1=1517320&r2=1517321&view=diff
==============================================================================
--- sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectReference.java [UTF-8] (original)
+++ sis/branches/Shapefile/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/ObjectReference.java [UTF-8] Sun Aug 25 15:49:51 2013
@@ -17,15 +17,16 @@
package org.apache.sis.internal.jaxb.gco;
import java.util.UUID;
-
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
import org.apache.sis.xml.XLink;
import org.apache.sis.xml.IdentifierMap;
import org.apache.sis.xml.IdentifierSpace;
import org.apache.sis.xml.IdentifiedObject;
import org.apache.sis.xml.ReferenceResolver;
+import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.internal.jaxb.IdentifierMapAdapter;
import org.apache.sis.internal.jaxb.SpecializedIdentifier;
@@ -51,13 +52,13 @@ import org.apache.sis.internal.jaxb.Spec
*/
final class ObjectReference {
/**
- * A URN to an external resources, or to an other part of a XML document, or an identifier.
+ * A unique identifier to an external resources, or to an other part of a XML document.
* The {@code uuidref} attribute is used to refer to an XML element that has a corresponding
* {@code uuid} attribute.
*
* @see <a href="http://www.schemacentral.com/sc/niem21/a-uuidref-1.html">Usage of uuidref</a>
*/
- String anyUUID;
+ UUID uuid;
/**
* The {@code xlink} attributes, or {@code null} if none.
@@ -65,11 +66,6 @@ final class ObjectReference {
XLink xlink;
/**
- * The parsed value of {@link #anyUUID}, computed when first needed.
- */
- private transient UUID uuid;
-
- /**
* Creates an initially empty object reference.
*/
ObjectReference() {
@@ -77,23 +73,13 @@ final class ObjectReference {
/**
* Creates an object reference initialized to the given value.
- */
- ObjectReference(final UUID uuid, final String anyUUID, final XLink link) {
- this.uuid = uuid;
- this.anyUUID = anyUUID;
- this.xlink = link;
- }
-
- /**
- * Parses the given string as a UUID.
*
- * @param context The marshalling context, or {@code null} if none.
- * @param anyUUID The string to parse, or {@code null}.
- * @return The parsed UUID, or {@code null}.
- * @throws IllegalArgumentException If {@code anyUUID} can not be parsed.
+ * @see ReferenceResolver#canSubstituteByReference(MarshalContext, Class, Object, UUID)
+ * @see ReferenceResolver#canSubstituteByReference(MarshalContext, Class, Object, XLink)
*/
- static UUID toUUID(final Context context, final String anyUUID) throws IllegalArgumentException {
- return (anyUUID != null) ? Context.converter(context).toUUID(context, anyUUID) : null;
+ ObjectReference(final UUID uuid, final XLink link) {
+ this.uuid = uuid;
+ this.xlink = link;
}
/**
@@ -101,19 +87,15 @@ final class ObjectReference {
* declared in this {@code ObjectReference}. If the given metadata object is non-null,
* assigns to that object the identifiers declared in this {@code ObjectReference}.
*
- * <p>This method is invoked at unmarshalling time.</p>
+ * <p>This method is invoked at unmarshalling time by {@link PropertyType#resolve(Context)}.</p>
*
* @param <T> The compile-time type of the {@code type} argument.
* @param context The marshalling context, or {@code null} if none.
* @param type The expected type of the metadata object.
* @param metadata The metadata object, or {@code null}.
* @return A metadata object for the identifiers, or {@code null}
- * @throws IllegalArgumentException If the {@link #anyUUID} field can not be parsed.
*/
- final <T> T resolve(final Context context, final Class<T> type, T metadata) throws IllegalArgumentException {
- if (uuid == null) {
- uuid = toUUID(context, anyUUID);
- }
+ final <T> T resolve(final Context context, final Class<T> type, T metadata) {
if (metadata == null) {
final ReferenceResolver resolver = Context.resolver(context);
if ((uuid == null || (metadata = resolver.resolve(context, type, uuid )) == null) &&
@@ -129,38 +111,52 @@ final class ObjectReference {
metadata = resolver.newIdentifiedObject(context, type, identifiers);
}
} else {
- // If principle, the XML should contain a full metadata object OR a uuidref attribute.
+ // In principle, the XML should contain a full metadata object OR a uuidref attribute.
// However if both are present, assign the identifiers to that instance.
if (metadata instanceof IdentifiedObject) {
final IdentifierMap map = ((IdentifiedObject) metadata).getIdentifierMap();
- if (uuid != null) putInto(map, IdentifierSpace.UUID, uuid);
- if (xlink != null) putInto(map, IdentifierSpace.XLINK, xlink);
+ putInto(context, map, IdentifierSpace.UUID, uuid);
+ putInto(context, map, IdentifierSpace.XLINK, xlink);
}
}
return metadata;
}
/**
- * Adds a new identifier into the given map. This method is a shortcut which bypass the check
- * for previous values associated to same the authority. It is okay only when constructing
- * new instances, for example at XML unmarshalling time.
+ * Adds a new identifier into the given map, if non null. No previous value should exist in normal situation.
+ * However a previous value may exit in unusual (probably not very valid) XML, as in the following example:
+ *
+ * {@preformat xml
+ * <gmd:CI_Citation>
+ * <gmd:series uuidref="f8f5fcb1-d57b-4013-b3a4-4eaa40df6dcf">
+ * <gmd:CI_Series uuid="f8f5fcb1-d57b-4013-b3a4-4eaa40df6dcf">
+ * ...
+ * </gmd:CI_Series>
+ * </gmd:series>
+ * </gmd:CI_Citation>
+ * }
+ *
+ * In such situation, this method is silent if the two identifiers are equal, or logs a warning and restores
+ * the previous value if they are not equal. The previous value is the "{@code uuid}" attribute, which is
+ * assumed more closely tied to the actual metadata than the {@code uuidref} attribute.
*
* @param map The map in which to write the identifier.
* @param authority The identifier authority.
* @param value The identifier value, or {@code null} if not yet defined.
*/
- private static <T> void putInto(final IdentifierMap map, final IdentifierSpace<T> authority, final T value) {
- if (map instanceof IdentifierMapAdapter) {
- final SpecializedIdentifier<T> identifier = new SpecializedIdentifier<T>(authority, value);
- /*
- * If the following assert statement appears to fail in practice, then remove
- * completly this method and use the public putSpecialized(…) method instead.
- * Note: usage of 'put' is for having the compiler to check the key type.
- */
- assert map.put(authority, null) == null : identifier;
- ((IdentifierMapAdapter) map).identifiers.add(identifier);
- } else {
- map.putSpecialized(authority, value);
+ private static <T> void putInto(final Context context, final IdentifierMap map,
+ final IdentifierSpace<T> authority, final T value)
+ {
+ if (value != null) {
+ final T previous = map.putSpecialized(authority, value);
+ if (previous != null && !previous.equals(value)) {
+ final LogRecord record = Errors.getResources((context != null) ? context.getLocale() : null)
+ .getLogRecord(Level.WARNING, Errors.Keys.InconsistentAttribute_2, authority.getName(), value);
+ record.setSourceClassName(IdentifierMap.class.getName());
+ record.setSourceMethodName("putSpecialized");
+ Context.warningOccured(context, map, record);
+ map.putSpecialized(authority, previous);
+ }
}
}
}