Author: desruisseaux Date: Wed Dec 5 08:03:27 2012 New Revision: 1417302 URL: http://svn.apache.org/viewvc?rev=1417302&view=rev Log: Initial implementation of MarshalContext (internal API).
Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java (with props) Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultInternationalString.java sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java?rev=1417302&view=auto ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java (added) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java Wed Dec 5 08:03:27 2012 @@ -0,0 +1,362 @@ +/* + * 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.internal.jaxb; + +import java.util.Collection; +import java.util.Map; +import java.util.Locale; +import java.util.TimeZone; +import org.opengis.metadata.Identifier; +import org.apache.sis.util.Version; +import org.apache.sis.xml.ValueConverter; +import org.apache.sis.xml.ReferenceResolver; +import org.apache.sis.util.collection.UnmodifiableArrayList; + + +/** + * Thread-local status of a marshalling or unmarshalling process. + * Contains also static methods for managing the collections to be marshalled. + * + * @author Martin Desruisseaux (Geomatys) + * @since 0.3 (derived from geotk-3.07) + * @version 0.3 + * @module + */ +public final class MarshalContext extends org.apache.sis.xml.MarshalContext { + /** + * The bit flag telling if a marshalling process is under progress. + * This flag is unset for unmarshalling processes. + */ + public static final int MARSHALING = 1; + + /** + * The bit flag for enabling substitution of language codes by character strings. + */ + public static final int SUBSTITUTE_LANGUAGE = 2; + + /** + * The bit flag for enabling substitution of country codes by character strings. + */ + public static final int SUBSTITUTE_COUNTRY = 4; + + /** + * The thread-local context. + */ + private static final ThreadLocal<MarshalContext> CURRENT = new ThreadLocal<>(); + + /** + * The value converter currently in use, or {@code null} for {@link ValueConverter#DEFAULT}. + */ + private ValueConverter converter; + + /** + * The reference resolver currently in use, or {@code null} for {@link ReferenceResolver#DEFAULT}. + */ + private ReferenceResolver resolver; + + /** + * The GML version to be marshalled or unmarshalled, or {@code null} if unspecified. + * If null, than the latest version is assumed. + */ + private Version versionGML; + + /** + * 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. + */ + private Map<String,String> schemas; + + /** + * The locale to use for marshalling, or {@code null} if no locale were explicitly specified. + */ + private Locale locale; + + /** + * The timezone, or {@code null} if unspecified. + * In the later case, an implementation-default (typically UTC) timezone is used. + */ + private TimeZone timezone; + + /** + * Various boolean attributes determines by the above static constants. + */ + private int bitMasks; + + /** + * The context which was previously used. This form a linked list allowing + * to push properties (e.g. {@link #pushLocale(Locale)}) and pull back the + * context to its previous state once finished. + */ + private final MarshalContext previous; + + /** + * Invoked when a marshalling or unmarshalling process is about to begin. + * Must be followed by a call to {@link #finish()} in a {@code finally} block. + * + * {@preformat java + * MarshalContext context = new MarshalContext(â¦); + * try { + * ... + * } finally { + * context.finish(); + * } + * } + * + * @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 #MARSHALING}, {@link #SUBSTITUTE_LANGUAGE}, + * {@link #SUBSTITUTE_COUNTRY} or other bit masks. + */ + public MarshalContext(final ValueConverter converter, final ReferenceResolver resolver, + final Version versionGML, final Map<String,String> schemas, + final Locale locale, final TimeZone timezone, final int bitMasks) + { + 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; + previous = current(); + CURRENT.set(this); + } + + /** + * Inherits all configuration from the previous context, if any. + * + * @param previous The context from which to inherit the configuration, or {@code null}. + * + * @see #push(Locale) + */ + private MarshalContext(final MarshalContext 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; + } + this.previous = previous; + CURRENT.set(this); + } + + /** + * Returns the context of the XML (un)marshalling currently progressing in the current thread, + * or {@code null} if none. + * + * @return The current (un)marshalling context, or {@code null} if none. + */ + public static MarshalContext current() { + return CURRENT.get(); + } + + /** + * Returns {@code true} if the given flag is set. + * + * @param flag One of {@link #MARSHALING}, {@link #SUBSTITUTE_LANGUAGE}, + * {@link #SUBSTITUTE_COUNTRY} or other bit masks. + * @return {@code true} if the given flag is set. + */ + public static boolean isFlagSet(final int flag) { + final MarshalContext current = current(); + return (current != null) && (current.bitMasks & flag) != 0; + } + + /** + * 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 current The current context, or {@code null} if none. + * @return The current value converter (never null). + */ + public static ValueConverter converter(final MarshalContext current) { + if (current != null) { + final ValueConverter converter = current.converter; + if (converter != null) { + return converter; + } + } + return ValueConverter.DEFAULT; + } + + /** + * Returns the reference resolver in use for the current marshalling or unmarshalling process. + * If no resolver were explicitely set, then this method returns {@link ReferenceResolver#DEFAULT}. + * + * {@note This method is static for the convenience of performing the check for null context.} + * + * @param current The current context, or {@code null} if none. + * @return The current reference resolver (never null). + */ + public static ReferenceResolver resolver(final MarshalContext current) { + if (current != null) { + final ReferenceResolver resolver = current.resolver; + if (resolver != null) { + return resolver; + } + } + return ReferenceResolver.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. + * + * {@note This method is static for the convenience of performing the check for null context.} + * + * @param current 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. + */ + public static String schema(final MarshalContext current, final String key, final String defaultSchema) { + if (current != null) { + final Map<String,String> schemas = current.schemas; + if (schemas != null) { + final String schema = schemas.get(key); + if (schema != null) { + return schema; + } + } + } + return defaultSchema; + } + + /** + * 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 current 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 MarshalContext current, final Version version) { + if (current != null) { + final Version versionGML = current.versionGML; + if (versionGML != null) { + return versionGML.compareTo(version) >= 0; + } + } + return true; + } + + /** + * 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 timezone, or {@code null} if none were explicitely defined. + * In the later case, an implementation-default (typically UTC) timezone is used. + */ + @Override + public final TimeZone getTimeZone() { + return timezone; + } + + /** + * Returns the locale to use for marshalling, or {@code null} if no locale were explicitly + * specified. A {@code null} value means that some locale-neutral language should be used + * if available, or an implementation-default locale (typically English) otherwise. + */ + @Override + public final Locale getLocale() { + return locale; + } + + /** + * Sets the locale to the given value. The old locales are remembered and will + * be restored by the next call to {@link #pullLocale()}. + * + * @param locale The locale to set, or {@code null}. + */ + public static void push(final Locale locale) { + final MarshalContext current = new MarshalContext(current()); + if (locale != null) { + current.locale = locale; + } + } + + /** + * Restores the locale (or any other setting) which was used prior the call to + * {@link #push(Locale)}. + */ + public static void pull() { + final MarshalContext current = current(); + if (current != null) { + current.finish(); + } + } + + /** + * If marshalling, filters the given collection of identifiers in order to omit any identifiers + * for which the authority is one of the {@link org.apache.sis.xml.IdentifierSpace} constants. + * + * @param identifiers The identifiers to filter, or {@code null}. + * @return The identifiers to marshal, or {@code null} if none. + */ + public static Collection<Identifier> filterIdentifiers(Collection<Identifier> identifiers) { + if (identifiers != null && isFlagSet(MARSHALING)) { + int count = identifiers.size(); + if (count != 0) { + final Identifier[] copy = identifiers.toArray(new Identifier[count]); + for (int i=count; --i>=0;) { + final Identifier id = copy[i]; + if (id == null || (id.getAuthority() instanceof NonMarshalledAuthority)) { + System.arraycopy(copy, i+1, copy, i, --count - i); + } + } + identifiers = (count != 0) ? UnmodifiableArrayList.wrap(copy, 0, count) : null; + } + } + return identifiers; + } + + /** + * Invoked in a {@code finally} block when a unmarshalling process is finished. + */ + public final void finish() { + if (previous != null) { + CURRENT.set(previous); + } else { + CURRENT.remove(); + } + } +} Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/MarshalContext.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultInternationalString.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultInternationalString.java?rev=1417302&r1=1417301&r2=1417302&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultInternationalString.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/DefaultInternationalString.java Wed Dec 5 08:03:27 2012 @@ -256,10 +256,17 @@ public class DefaultInternationalString * {@section Handling of <code>null</code> argument value} * A {@code null} argument value can be given to this method for * requesting a "unlocalized" string - typically some programmatic strings like - * {@linkplain org.opengis.annotation.UML#identifier() UML identifiers}. While such - * identifiers often look like English words, they are not considered as the - * {@linkplain Locale#ENGLISH English locale}. In order to produce a value close - * to the common practice, this method handles {@code null} argument value as below: + * {@linkplain org.opengis.annotation.UML#identifier() UML identifiers}. + * While such identifiers often look like English words, they are not considered + * as the {@linkplain Locale#ENGLISH English locale}. For example: + * + * <ul> + * <li>Numbers are formatted using {@code Number.toString()} rather than {@link java.text.NumberFormat}.</li> + * <li>Dates are formatted according the ISO standard rather than the English locale.</li> + * </ul> + * + * In order to produce a value close to the common practice, + * this method handles {@code null} argument value as below: * * <ul> * <li>If a string has been explicitly {@linkplain #add(Locale, String) added} for the Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java?rev=1417302&r1=1417301&r2=1417302&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java Wed Dec 5 08:03:27 2012 @@ -79,6 +79,23 @@ public abstract class MarshalContext { * In particular children of {@link org.opengis.metadata.Metadata} inherit the locale * specified by the {@link org.opengis.metadata.Metadata#getLanguage()} attribute. * + * {@section Null locale} + * Null locales are typically interpreted as a request for locale-independent strings in SIS. + * The meaning of "locale-independent" is implementation specific - + * this is usually very close to the English locale, but not necessarily + * (e.g. dates formatted according ISO standard instead then English locale). + * If the locale is {@code null}, then callers shall select a default locale as documented + * in the {@link org.apache.sis.util.type.DefaultInternationalString#toString(Locale)} javadoc. + * As a matter of rule: + * + * <ul> + * <li>If the locale is given to an {@code InternationalString.toString(Locale)} method, + * keep the {@code null} value since the international string is already expected to + * returns a "unlocalized" string in such case.</li> + * <li>Otherwise, if a {@code Locale} instance is really needed, use {@link Locale#US} + * as an approximation of "unlocalized" string.</li> + * </ul> + * * @return The locale for the XML fragment being (un)marshalled, or {@code null} is unspecified. */ public abstract Locale getLocale();