Package org.apache.cocoon.util.log

Source Code of org.apache.cocoon.util.log.ExtensiblePatternFormatter$PatternRun

/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.cocoon.util.log;

import java.io.StringWriter;
import java.util.Stack;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.log.LogEvent;
import org.apache.log.Priority;
import org.apache.log.format.Formatter;
import org.apache.log.util.DefaultErrorHandler;

/**
* A refactoring of <code>org.apache.log.format.PatternFormatter</code> that
* can be extended.
* This formater formats the LogEntries according to a input pattern string.
*
* The format of each pattern element can be %[+|-]#.#{field:subformat}
*
* The +|- indicates left or right justify.
* The #.# indicates the minimum and maximum size of output.
* 'field' indicates which field is to be output and must be one of
*  properties of LogEvent
* 'subformat' indicates a particular subformat and is currently unused.
*
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
* @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
* @version CVS $Id: ExtensiblePatternFormatter.java,v 1.5 2004/03/28 10:27:20 antonio Exp $
*/
public class ExtensiblePatternFormatter
    implements Formatter
{
    protected final static int         TYPE_TEXT            = 1;
    protected final static int         TYPE_CATEGORY        = 2;
    protected final static int         TYPE_MESSAGE         = 4;
    protected final static int         TYPE_TIME            = 5;
    protected final static int         TYPE_RELATIVE_TIME   = 6;
    protected final static int         TYPE_THROWABLE       = 7;
    protected final static int         TYPE_PRIORITY        = 8;

    /**
     * The maximum value used for TYPEs. Subclasses can define their own TYPEs
     * starting at <code>MAX_TYPE + 1</code>.
     */
    protected final static int         MAX_TYPE             = 8;

    protected final static String      TYPE_CATEGORY_STR      = "category";
    protected final static String      TYPE_MESSAGE_STR       = "message";
    protected final static String      TYPE_TIME_STR          = "time";
    protected final static String      TYPE_RELATIVE_TIME_STR = "rtime";
    protected final static String      TYPE_THROWABLE_STR     = "throwable";
    protected final static String      TYPE_PRIORITY_STR      = "priority";

    protected static class PatternRun {
        public String    m_data;
        public boolean   m_rightJustify;
        public int       m_minSize;
        public int       m_maxSize;
        public int       m_type;
        public String    m_format;
    }

    protected PatternRun m_formatSpecification[];

    /**
     * Extract and build a pattern from input string.
     *
     * @param stack the stack on which to place patterns
     * @param pattern the input string
     * @param index the start of pattern run
     * @return the number of characters in pattern run
     */
    protected int addPatternRun(final Stack stack, final char pattern[], int index) {
        final PatternRun run = new PatternRun();
        final int start = index++;

        // first check for a +|- sign
        if ('+' == pattern[index]) {
            index++;
        } else if ('-' == pattern[index]) {
            run.m_rightJustify = true;
            index++;
        }

        if (Character.isDigit(pattern[index])) {
            int total = 0;
            while (Character.isDigit(pattern[index])) {
                total = total * 10 + (pattern[index] - '0');
                index++;
            }
            run.m_minSize = total;
        }

        //check for . sign indicating a maximum is to follow
        if (index < pattern.length && '.' == pattern[index]) {
            index++;
            if (Character.isDigit(pattern[index])) {
                int total = 0;
                while (Character.isDigit(pattern[index])) {
                    total = total * 10 + (pattern[ index ] - '0');
                    index++;
                }
                run.m_maxSize = total;
            }
        }

        if (index >= pattern.length || '{' != pattern[index]) {
            throw new IllegalArgumentException(
                    "Badly formed pattern at character " + index );
        }

        int typeStart = index;

        while (index < pattern.length &&
               pattern[index]!= ':' && pattern[index] != '}' ) {
            index++;
        }

        int typeEnd = index - 1;

        final String type = new String(pattern, typeStart + 1, typeEnd - typeStart);

        run.m_type = getTypeIdFor( type );

        if (index < pattern.length && pattern[index] == ':' ) {
            index++;
            while (index < pattern.length && pattern[index] != '}' ) {
                index++;
            }
            final int length = index - typeEnd - 2;

            if (0 != length) {
                run.m_format = new String(pattern, typeEnd + 2, length);
            }
        }

        if (index >= pattern.length || '}' != pattern[index]) {
            throw new IllegalArgumentException(
                    "Unterminated type in pattern at character " + index );
        }
        index++;
        stack.push( run );
        return index - start;
    }

    /**
     * Extract and build a text run  from input string.
     * It does special handling of '\n' and '\t' replaceing
     * them with newline and tab.
     *
     * @param stack the stack on which to place runs
     * @param pattern the input string
     * @param index the start of the text run
     * @return the number of characters in run
     */
    protected int addTextRun( final Stack stack, final char pattern[], int index ) {
        final PatternRun run = new PatternRun();
        final int start = index;
        boolean escapeMode = false;

        if ('%' == pattern[index]) {
            index++;
        }
        final StringBuffer sb = new StringBuffer();
        while (index < pattern.length && pattern[index] != '%') {
            if (escapeMode) {
                if ('n' == pattern[ index ]) {
                    sb.append( SystemUtils.LINE_SEPARATOR );
                } else if ('t' == pattern[ index ]) {
                    sb.append( '\t' );
                } else {
                    sb.append( pattern[ index ] );
                }
                escapeMode = false;
            } else if ('\\' == pattern[ index ]) {
                escapeMode = true;
            } else {
                sb.append( pattern[ index ] );
            }
            index++;
        }
        run.m_data = sb.toString();
        run.m_type = TYPE_TEXT;
        stack.push(run);
        return index - start;
    }

    /**
     * Utility to append a string to buffer given certain constraints.
     *
     * @param sb the StringBuffer
     * @param minSize the minimum size of output (0 to ignore)
     * @param maxSize the maximum size of output (0 to ignore)
     * @param rightJustify true if the string is to be right justified in it's box.
     * @param output the input string
     */
    protected void append(final StringBuffer sb, final int minSize, final int maxSize,
            final boolean rightJustify, final String output) {
        if (output.length() < minSize) {
            if (rightJustify) {
                sb.append(StringUtils.leftPad(output, minSize));
            } else {
                sb.append(StringUtils.rightPad(output, minSize));
            }
        } else if (maxSize > 0) {
            if (rightJustify) {
                sb.append(StringUtils.right(output, maxSize));
            } else {
                sb.append(StringUtils.left(output, maxSize));
            }
        } else {
            sb.append(output);
        }
    }

    /**
     * Format the event according to the pattern.
     *
     * @param event the event
     * @return the formatted output
     */
    public String format(final LogEvent event) {
        final StringBuffer sb = new StringBuffer();

        for( int i = 0; i < m_formatSpecification.length; i++ ) {
            final PatternRun run =  m_formatSpecification[i];
            //treat text differently as it doesn't need min/max padding
            if (run.m_type == TYPE_TEXT) {
                sb.append(run.m_data);
            } else {
                final String data = formatPatternRun(event, run);
                if (null != data) {
                    append(sb, run.m_minSize, run.m_maxSize, run.m_rightJustify, data);
                }
            }
        }
        return sb.toString();
    }

    /**
     * Formats a single pattern run (can be extended in subclasses).
     *
     * @param  run the pattern run to format.
     * @return the formatted result.
     */
    protected String formatPatternRun( final LogEvent event, final PatternRun run )
    {
        String str = null;

        switch (run.m_type)
        {
            case TYPE_RELATIVE_TIME:
                str = getTime( event.getRelativeTime(), run.m_format );
                break;
            case TYPE_TIME:
                str = getTime( event.getTime(), run.m_format );
                break;
            case TYPE_THROWABLE:
                str = getStackTrace( event.getThrowable(), run.m_format );
                break;
            case TYPE_MESSAGE:
                str = getMessage( event.getMessage(), run.m_format );
                break;
            case TYPE_CATEGORY:
                str = getCategory( event.getCategory(), run.m_format );
                break;
            case TYPE_PRIORITY:
                str = getPriority( event.getPriority(), run.m_format );
                break;
            default:
                new DefaultErrorHandler().error("Unknown Pattern specification." + run.m_type, null, null);
        }
        return str;
    }

    /**
     * Utility method to format category.
     *
     * @param category the category string
     * @param format ancilliary format parameter - allowed to be null
     * @return the formatted string
     */
    protected String getCategory(final String category, final String format) {
        return category;
    }

    /**
     * Get formatted priority string.
     */
    protected String getPriority(final Priority priority, final String format) {
        return priority.getName();
    }

    /**
     * Correct a context string by replacing '.''s with a '_'.
     *
     * @param context the un-fixed context
     * @return the fixed context
     */
    protected final String fix(final String context) {
        return context.replace( '.', '_' );
    }

    /**
     * Utility method to format message.
     *
     * @param message the message string
     * @param format ancilliary format parameter - allowed to be null
     * @return the formatted string
     */
    protected String getMessage(final String message, final String format) {
        return message;
    }

    /**
     * Utility method to format stack trace.
     *
     * @param throwable the throwable instance
     * @param format ancilliary format parameter - allowed to be null
     * @return the formatted string
     */
    protected String getStackTrace(final Throwable throwable, final String format) {
        if (null != throwable) {
            final StringWriter sw = new StringWriter();
            throwable.printStackTrace(new java.io.PrintWriter(sw));
            return sw.toString();
        }
        return "";
    }

    /**
     * Utility method to format time.
     *
     * @param time the time
     * @param format ancilliary format parameter - allowed to be null
     * @return the formatted string
     */
    protected String getTime(final long time, final String format) {
        return Long.toString(time);
    }

    /**
     * Retrieve the type-id for a particular string.
     *
     * @param type the string
     * @return the type-id
     */
    protected int getTypeIdFor(final String type) {
        if (type.equalsIgnoreCase(TYPE_CATEGORY_STR)) {
            return TYPE_CATEGORY;
        } else if (type.equalsIgnoreCase(TYPE_MESSAGE_STR)) {
            return TYPE_MESSAGE;
        } else if (type.equalsIgnoreCase(TYPE_PRIORITY_STR)) {
            return TYPE_PRIORITY;
        } else if (type.equalsIgnoreCase(TYPE_TIME_STR)) {
            return TYPE_TIME;
        } else if (type.equalsIgnoreCase(TYPE_RELATIVE_TIME_STR)) {
            return TYPE_RELATIVE_TIME;
        } else if (type.equalsIgnoreCase(TYPE_THROWABLE_STR)) {
            return TYPE_THROWABLE;
        } else {
            throw new IllegalArgumentException( "Unknown Type in pattern - " + type );
        }
    }

    /**
     * Parse the input pattern and build internal data structures.
     *
     * @param patternString the pattern
     */
    protected void parse(final String patternString) {
        final Stack stack = new Stack();
        final int size = patternString.length();
        final char pattern[] = new char[size];
        int index = 0;

        patternString.getChars(0, size, pattern, 0);
        while (index < size) {
            if (pattern[index] == '%' &&
                !(index != size - 1 && pattern[index + 1] == '%' )) {
                index += addPatternRun(stack, pattern, index);
            } else {
                index +=  addTextRun(stack, pattern, index);
            }
        }
        final int elementCount = stack.size();
        m_formatSpecification = new PatternRun[elementCount];

        for (int i = 0; i < elementCount; i++) {
            m_formatSpecification[i] = (PatternRun) stack.elementAt(i);
        }
    }

    /**
     * Set the string description that the format is extracted from.
     *
     * @param format the string format
     */
    public void setFormat(final String format) {
        parse(format);
    }
}
TOP

Related Classes of org.apache.cocoon.util.log.ExtensiblePatternFormatter$PatternRun

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.