You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2012/11/14 18:18:52 UTC
svn commit: r1409261 - in
/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis:
io/CompoundFormat.java util/Localized.java
Author: desruisseaux
Date: Wed Nov 14 17:18:51 2012
New Revision: 1409261
URL: http://svn.apache.org/viewvc?rev=1409261&view=rev
Log:
First draft of CompoundFormat, which will be the base class of
CoordinateFormat, WKTFormat and TreeTableFormat.
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java (with props)
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Localized.java
Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java?rev=1409261&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java Wed Nov 14 17:18:51 2012
@@ -0,0 +1,307 @@
+/*
+ * 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.io;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Date;
+import java.io.IOException;
+import java.text.Format;
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import net.jcip.annotations.NotThreadSafe;
+import org.opengis.util.InternationalString;
+
+import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.AngleFormat;
+import org.apache.sis.util.Localized;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.internal.util.LocalizedParseException;
+
+
+/**
+ * Base class of {@link Format} implementations which delegate part of their work to other
+ * {@code Format} instances. {@code CompoundFormat} subclasses typically work on relatively
+ * large blocks of data, for example a metadata tree or a <cite>Well Known Text</cite> (WKT).
+ * Those blocks of data usually contain smaller information units like numbers and dates,
+ * whose parsing and formatting can be delegated to {@link NumberFormat} and {@link DateFormat}
+ * respectively.
+ *
+ * <p>Since this subclasses may work on larger texts than the usual {@code Format} classes,
+ * they will work with {@link CharSequence} and {@link Appendable} as much as possible.
+ * The abstract methods to be defined by subclasses are:</p>
+ *
+ * <ul>
+ * <li>{@link #getValueType()} : return the {@code <T>} class</li>
+ * <li>{@link #parse(CharSequence, ParsePosition)}</li>
+ * <li>{@link #format(Object, Appendable)} throws {@link IOException}</li>
+ * </ul>
+ *
+ * @param <T> The type of objects parsed and formatted by this class.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+@NotThreadSafe
+public abstract class CompoundFormat<T> extends Format implements Localized {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -7094915750367581487L;
+
+ /**
+ * The locale given at construction time, or {@code null} for unlocalized format.
+ *
+ * @see #getLocale()
+ */
+ protected final Locale locale;
+
+ /**
+ * The timezone given at construction time, or {@code null} for UTC.
+ */
+ protected final TimeZone timezone;
+
+ /**
+ * The formats for smaller unit of information.
+ * Will be created only when first needed.
+ */
+ private transient Map<Class<?>,Format> formats;
+
+ /**
+ * Creates a new format for the given locale. The given locale can be {@code null} if this
+ * format shall parse and format "unlocalized" strings. See {@link #getLocale()} for more
+ * information on {@code null} locale.
+ *
+ * @param locale The locale, or {@code null} for unlocalized format.
+ * @param timezone The timezone, or {@code null} for UTC.
+ */
+ protected CompoundFormat(final Locale locale, final TimeZone timezone) {
+ this.locale = locale;
+ this.timezone = timezone;
+ }
+
+ /**
+ * Returns the locale given at construction time. The returned locale may be {@code null}
+ * if this format does not apply any localization. The definition of "unlocalized string"
+ * is implementation-dependent, but some typical examples are:
+ *
+ * <ul>
+ * <li>Format {@link Number}s using {@code toString()} instead than {@code NumberFormat}.</li>
+ * <li>Format {@link InternationalString}s using {@code toString(null)}. This has the desired
+ * behavior at least with {@linkplain org.apache.sis.util.Type.DefaultInternationalString
+ * SIS implementation}.</li>
+ * </ul>
+ *
+ * @return The locale used for this format, or {@code null} for unlocalized format.
+ */
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Returns the type of values formatted by this {@code Format} instance.
+ *
+ * @return The type of values formatted by this {@code Format} instance.
+ */
+ public abstract Class<T> getValueType();
+
+ /**
+ * Creates an object from the given character sequence, or returns {@code null} if an error
+ * occurred while parsing the characters.
+ *
+ * @param text The character sequence for the object to parse.
+ * @param pos The position where to start the parsing.
+ * @return The parsed object, or {@code null} if the given character sequence can not be parsed.
+ */
+ public abstract T parse(CharSequence text, ParsePosition pos);
+
+ /**
+ * Creates an object from the given string representation, or returns {@code null} if an error
+ * occurred while parsing the string. The default implementation delegates to
+ * {@link #parse(CharSequence, ParsePosition)}.
+ *
+ * @param text The string representation of the object to parse.
+ * @param pos The position where to start the parsing.
+ * @return The parsed object, or {@code null} if the given string can not be parsed.
+ */
+ @Override
+ public T parseObject(final String text, final ParsePosition pos) {
+ return parse(text, pos);
+ }
+
+ /**
+ * Creates an object from the given string representation.
+ * The default implementation delegates to {@link #parseObject(String, ParsePosition)}.
+ *
+ * @param text The string representation of the object to parse.
+ * @return The parsed object.
+ * @throws ParseException If an error occurred while parsing the tree.
+ */
+ @Override
+ public T parseObject(final String text) throws ParseException {
+ final ParsePosition pos = new ParsePosition(0);
+ final T table = parseObject(text, pos);
+ if (table != null) {
+ return table;
+ }
+ throw new LocalizedParseException(locale, getValueType(), text, pos);
+ }
+
+ /**
+ * Writes a textual representation of the given object in the given stream or buffer.
+ *
+ * @param object The object to format.
+ * @param toAppendTo Where to format the object.
+ * @throws IOException If an error occurred while writing in the given appender.
+ */
+ public abstract void format(T object, Appendable toAppendTo) throws IOException;
+
+ /**
+ * Writes a textual representation of the specified object in the given buffer.
+ * This method delegates its work to {@link #format(Object, Appendable)}, but
+ * without propagating {@link IOException}. The I/O exception should never
+ * occur since we are writing in a {@link StringBuffer}.
+ *
+ * {@note Strictly speaking, an <code>IOException</code> could still occur if the user
+ * overrides the above <code>format</code> method and performs some I/O operation outside
+ * the given <code>StringBuffer</code>. However this is not the intended usage of this
+ * class and implementors should avoid such unexpected I/O operation.}
+ *
+ * @param object The object to format.
+ * @param toAppendTo Where to format the object.
+ * @param pos Ignored in current implementation.
+ * @return The given buffer, returned for convenience.
+ */
+ @Override
+ public StringBuffer format(final Object object, final StringBuffer toAppendTo, final FieldPosition pos) {
+ final Class<T> valueType = getValueType();
+ ArgumentChecks.ensureCanCast("tree", valueType, object);
+ try {
+ format(valueType.cast(object), toAppendTo);
+ } catch (IOException e) {
+ /*
+ * Should never happen when writing into a StringBuffer, unless the user
+ * override the format(Object, Appendable) method. We do not rethrown an
+ * AssertionError because of this possibility.
+ */
+ throw new BackingStoreException(e);
+ }
+ return toAppendTo;
+ }
+
+ /**
+ * Returns the format to use for parsing and formatting values of the given type.
+ * This method applies the following algorithm:
+ *
+ * <ul>
+ * <li>If a format is cached for the given type, return that format.</li>
+ * <li>Otherwise if a format can be {@linkplain #createFormat(Class) created}
+ * for the given type, cache the newly created format and return it.</li>
+ * <li>Otherwise do again the same checks for the {@linkplain Class#getSuperclass() super class}.</li>
+ * <li>If no format can be created, returns {@code null}.</li>
+ * </ul>
+ *
+ * See {@link #createFormat(Class)} for the list of value types recognized by the default
+ * {@code CompoundFormat} implementation.
+ *
+ * @param valueType The base type of values to parse or format.
+ * @return The format to use for parsing and formatting values of the given type or any
+ * parent type, or {@code null} if none.
+ */
+ protected Format getFormat(final Class<?> valueType) {
+ Format format = null;
+ Map<Class<?>,Format> formats = this.formats;
+ for (Class<?> type=valueType; type!=null; type=type.getSuperclass()) {
+ if (formats != null) {
+ format = formats.get(type);
+ if (format != null) {
+ if (type != valueType) {
+ formats.put(valueType, format);
+ }
+ break;
+ }
+ }
+ format = createFormat(type);
+ if (format != null) {
+ if (formats == null) {
+ this.formats = formats = new HashMap<>(4);
+ }
+ formats.put(type, format);
+ break;
+ }
+ }
+ return format;
+ }
+
+ /**
+ * Creates a new format to use for parsing and formatting values of the given type.
+ * This method is invoked by {@link #getFormat(Class)} the first time that a format
+ * is needed for the given type.
+ *
+ * <p>The default implementation creates the following formats:</p>
+ *
+ * <table class="sis">
+ * <tr><th>Value type</th> <th>Format</th></tr>
+ * <tr><td>{@link Angle}</td> <td>{@link AngleFormat}</td></tr>
+ * <tr><td>{@link Date}</td> <td>{@link DateFormat}</td></tr>
+ * <tr><td>{@link Number}</td> <td>{@link NumberFormat}</td></tr>
+ * </table>
+ *
+ * Subclasses can override this method for adding more types, or for configuring the
+ * newly created {@link Format} instances. Note that implementations shall check the
+ * type using the {@code expected == type} comparator, not
+ * <code>expected.{@linkplain Class#isAssignableFrom(Class) isAssignableFrom}(type)</code>,
+ * because the check for parent types is done by the {@link #getFormat(Class)} method.
+ * This approach allows sub-classes to create specialized formats for different value
+ * sub-types. For example a sub-class may choose to format {@link Double} values differently
+ * than other type of numbers.
+ *
+ * @param valueType The base type of values to parse or format.
+ * @return The format to use for parsing of formatting values of the given type,
+ * or {@code null} if none.
+ */
+ protected Format createFormat(final Class<?> valueType) {
+ if (valueType == Number.class) {
+ if (locale == null) return null;
+ return NumberFormat.getInstance(locale);
+ }
+ if (valueType == Date.class) {
+ final DateFormat format;
+ if (locale != null) {
+ format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
+ } else {
+ format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
+ }
+ format.setTimeZone(timezone != null ? timezone : TimeZone.getTimeZone("UTC"));
+ }
+ if (valueType == Angle.class) {
+ if (locale == null) return null;
+ return AngleFormat.getInstance(locale);
+ }
+ return null;
+ }
+}
Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Localized.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Localized.java?rev=1409261&r1=1409260&r2=1409261&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Localized.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Localized.java Wed Nov 14 17:18:51 2012
@@ -30,10 +30,18 @@ import java.util.Locale;
public interface Localized {
/**
* Returns the locale of the implemented service. Some implementations may return
- * {@code null} if no locale is explicitly defined. In such case, the locale to use
- * is typically the {@linkplain Locale#getDefault() default} locale.
+ * {@code null} if no locale is explicitly defined. The meaning of null locale is
+ * implementation-dependent, but typical interpretations are:
+ *
+ * <ul>
+ * <li>A synonymous of the {@linkplain Locale#getDefault() system default locale};</li>
+ * <li>or an "unlocalized" service, for example formatting numbers using
+ * {@link Double#toString(double)} instead than {@link java.text.NumberFormat}.</li>
+ * </ul>
*
* @return The locale, or {@code null} if not explicitly defined.
+ *
+ * @see org.apache.sis.io.CompoundFormat#getLocale()
*/
Locale getLocale();
}