Package org.geotools.util.logging

Source Code of org.geotools.util.logging.LoggedFormat

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2007-2008, Open Source Geospatial Foundation (OSGeo)
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*/
package org.geotools.util.logging;

import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;

import org.geotools.resources.Classes;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;


/**
* Wraps a {@link Format} object in order to either parse fully a string, or log a warning.
* This class provides a {@link #parse} method which performs the following tasks:
* <p>
* <ul>
*   <li>Checks if the string was fully parsed and log a warning if it was not. This is
*       different than the default {@link #parseObject(String)} behavior which check only
*       if the <em>begining</em> of the string was parsed and ignore any remaining characters.</li>
*   <li>Ensures that the parsed object is of some specific class specified at construction time.</li>
*   <li>If the string can't be fully parsed or is not of the expected class, logs a warning.</li>
* </ul>
*
* @since 2.4
*
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
*/
public class LoggedFormat<T> extends Format {
    /**
     * For cross-version compatibility.
     */
    private static final long serialVersionUID = 4578880360344271325L;

    /**
     * The wrapped format.
     */
    private final Format format;

    /**
     * The expected type for the parsed values.
     */
    private final Class<T> type;

    /**
     * The level to use for the messages to be logged.
     */
    private Level level;

    /**
     * The logger where to log warnings, or {@code null} if none.
     *
     * @see #setLogger
     */
    private String logger;

    /**
     * The class to declare in as the warning emitter, or {@code null} if none.
     *
     * @see #setCaller
     */
    private String className;

    /**
     * The method to declare in as the warning emitter, or {@code null} if none.
     *
     * @see #setCaller
     */
    private String methodName;

    /**
     * Creates a new format wrapping the specified one.
     *
     * @param format The format to use for parsing and formatting.
     * @param type   The expected type of parsed values.
     */
    protected LoggedFormat(final Format format, final Class<T> type) {
        this.format = format;
        this.type   = type;
        this.level  = Level.WARNING;
    }

    /**
     * Creates a new format wrapping the specified one.
     *
     * @param format The format to use for parsing and formatting.
     * @param type   The expected type of parsed values.
     */
    public static <T> LoggedFormat<T> getInstance(final Format format, final Class<T> type) {
        return new LoggedFormat<T>(format, type);
    }

    /**
     * Sets the logger where to send the warnings eventually emitted by the {@link #parse} method.
     *
     * @param logger The logger where to log warnings, or {@code null} if none.
     */
    public void setLogger(final String logger) {
        this.logger = logger;
    }

    /**
     * Sets the logger level for the warnings eventually emitted by the {@link #parse} method.
     * The default value is {@link Level#WARNING}.
     *
     * @param level The new logging level.
     *
     * @since 2.5
     */
    public void setLevel(final Level level) {
        if (level != null) {
            this.level = level;
        }
    }

    /**
     * Sets the {@linkplain LogRecord#setSourceClassName source class name} and
     * {@linkplain LogRecord#setSourceMethodName source method name} for the warnings
     * eventually emitted by the {@link #parse} method.
     *
     * @param caller The class to declare as the warning emitter, or {@code null} if none.
     * @param method The method to declare as the warning emitter, or {@code null} if none.
     */
    public void setCaller(final Class<?> caller, final String method) {
        this.className  = (caller != null) ? caller.getName() : null;
        this.methodName = method;
    }

    /**
     * Parses the specified string. If the string can't be parsed, then this method returns
     * {@code null}. If it can be parsed at least partially and is of the kind specified at
     * construction time, then it is returned. If the string has not been fully parsed, then
     * a {@linkplain LogRecord log record} is prepared and logged.
     *
     * @param  text The text to parse, or {@code null}.
     * @return The parsed object, or {@code null} if {@code text} was null or can't be parsed.
     */
    public T parse(String text) {
        if (text == null || (text=text.trim()).length() == 0) {
            return null;
        }
        final ParsePosition position = new ParsePosition(0);
        final Object value = parseObject(text, position);
        int index = position.getIndex();
        final int error = position.getErrorIndex();
        if (error >= 0 && error < index) {
            index = error;
        }
        if (index < text.length()) {
            doLogWarning(formatUnparsable(text, 0, index, getWarningLocale(), level));
        } else if (value!=null && !type.isInstance(value)) {
            doLogWarning(Errors.getResources(getWarningLocale()).getLogRecord(level,
                    ErrorKeys.ILLEGAL_CLASS_$2, value.getClass(), type));
            return null;
        }
        return type.cast(value);
    }

    /**
     * Parses text from a string to produce an object. This method delegates the work to the
     * {@linkplain Format format} specified at construction time. This method to not perform
     * any logging.
     *
     * @param  text The text to parse.
     * @return An object parsed from the string.
     * @throws ParseException if parsing failed.
     */
    @Override
    public Object parseObject(final String text) throws ParseException {
        return format.parseObject(text);
    }

    /**
     * Parses text from a string to produce an object. This method delegates the work to the
     * {@linkplain Format format} specified at construction time. This method to not perform
     * any logging.
     *
     * @param text The text to parse.
     * @param position Index and error index information.
     * @return An object parsed from the string, or {@code null} in case of error.
     */
    public Object parseObject(final String text, final ParsePosition position) {
        return format.parseObject(text, position);
    }

    /**
     * Formats the specified object. This method delegates the work to the
     * {@linkplain Format format} specified at construction time.
     *
     * @param value      The object to format.
     * @param toAppendTo The buffer where the text is to be appended.
     * @param position   Identifies a field in the formatted text.
     * @return           The string buffer passed in with formatted text appended.
     */
    public StringBuffer format(final Object value, final StringBuffer toAppendTo,
                               final FieldPosition position)
    {
        return format.format(value, toAppendTo, position);
    }

    /**
     * Formats the specified object. This method delegates the work to the
     * {@linkplain Format format} specified at construction time.
     *
     * @param value The object to format.
     * @return The character iterator describing the formatted value.
     */
    @Override
    public AttributedCharacterIterator formatToCharacterIterator(final Object value) {
        return format.formatToCharacterIterator(value);
    }

    /**
     * Logs a warning. The caller is set before to invoke the user-overridable method.
     */
    private void doLogWarning(final LogRecord warning) {
        if (className != null) {
            warning.setSourceClassName(className);
        }
        if (methodName != null) {
            warning.setSourceMethodName(methodName);
        }
        logWarning(warning);
    }

    /**
     * Logs a warning. This method is invoked automatically by the {@link #parse parse} method
     * when a text can't be fully parsed. The default implementation logs the warning to the
     * logger specified by the last call to the {@link #setLogger setLogger} method. Subclasses
     * may override this method if they want to change the log record before the logging.
     *
     * @param warning The warning to log.
     */
    protected void logWarning(final LogRecord warning) {
        if (logger != null) {
            final Logger logger = Logging.getLogger(this.logger);
            warning.setLoggerName(logger.getName());
            logger.log(warning);
        }
    }

    /**
     * Returns the locale to use for formatting warnings. The default implementation returns
     * the {@linkplain Locale#getDefault() default locale}.
     */
    protected Locale getWarningLocale() {
        return Locale.getDefault();
    }

    /**
     * Formats an error message for an unparsable string. This method performs the same work that
     * {@link #formatUnparsable(String, int, int, Locale, Level) formatUnparsable(..., Level)},
     * except that the result is returned as a {@link String} rather than a {@link LogRecord}.
     * This is provided as a convenience method for creating the message to give to an
     * {@linkplain Exception#Exception(String) exception constructor}.
     *
     * @param  text The unparsable string.
     * @param  index The parse position. This is usually {@link ParsePosition#getIndex}.
     * @param  errorIndex The index where the error occured. This is usually
     *         {@link ParsePosition#getErrorIndex}.
     * @param  locale The locale for the message, or {@code null} for the default one.
     * @return A formatted error message.
     *
     * @since 2.5
     */
    public static String formatUnparsable(final String text, final int index,
            final int errorIndex, final Locale locale)
    {
        return (String) doFormatUnparsable(text, index, errorIndex, locale, null);
    }

    /**
     * Formats a log record for an unparsable string. This method is invoked by the
     * {@link #parse parse} method for formatting the log record to be given to the
     * {@link #logWarning} method. It is made public as a convenience for implementors
     * who wish to manage loggings outside this {@code LoggedFormat} class.
     *
     * @param  text The unparsable string.
     * @param  index The parse position. This is usually {@link ParsePosition#getIndex}.
     * @param  errorIndex The index where the error occured. This is usually
     *         {@link ParsePosition#getErrorIndex}.
     * @param  locale The locale for the log message, or {@code null} for the default one.
     * @param  level The log record level.
     * @return A formatted log record.
     *
     * @since 2.5
     */
    public static LogRecord formatUnparsable(final String text, final int index,
            final int errorIndex, final Locale locale, Level level)
    {
        if (level == null) {
            // It is necessary to ensure that the level argument is non-null,
            // otherwise we would get a ClassCastException in the code below.
            level = Level.WARNING;
        }
        return (LogRecord) doFormatUnparsable(text, index, errorIndex, locale, level);
    }

    /**
     * Implementation of {@code formatUnparsable} methods. Returns a {@link LogRecord}
     * if {@code level} is non-null, or a {@link String} otherwise.
     */
    private static Object doFormatUnparsable(String text, final int index, int errorIndex,
                                             final Locale locale, final Level level)
    {
        final Errors resources = Errors.getResources(locale);
        final int length = text.length();
        if (errorIndex < index) {
            errorIndex = index;
        }
        if (errorIndex == length) {
            if (level != null) {
                return resources.getLogRecord(level, ErrorKeys.UNEXPECTED_END_OF_STRING);
            }
            return resources.getString(ErrorKeys.UNEXPECTED_END_OF_STRING);
        }
        int upper = errorIndex;
        if (upper < length) {
            final int type = Character.getType(text.charAt(upper));
            while (++upper < length) {
                if (Character.getType(text.charAt(upper)) != type) {
                    break;
                }
            }
        }
        final String error = text.substring(errorIndex, upper);
        text = text.substring(index);
        if (level != null) {
            return resources.getLogRecord(level, ErrorKeys.UNPARSABLE_STRING_$2, text, error);
        }
        return resources.getString(ErrorKeys.UNPARSABLE_STRING_$2, text, error);
    }

    /**
     * Returns a string representation for debugging purpose.
     */
    @Override
    public String toString() {
        final StringBuilder buffer = new StringBuilder(Classes.getShortClassName(this))
                .append('[').append(Classes.getShortClassName(format));
        if (logger != null) {
            buffer.append(", logger=").append(logger);
        }
        return buffer.append(']').toString();
    }
}
TOP

Related Classes of org.geotools.util.logging.LoggedFormat

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.