0N/A/*
2362N/A * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage java.util.logging;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.nio.charset.Charset;
0N/Aimport java.util.*;
0N/A
0N/A/**
0N/A * Format a LogRecord into a standard XML format.
0N/A * <p>
0N/A * The DTD specification is provided as Appendix A to the
0N/A * Java Logging APIs specification.
0N/A * <p>
0N/A * The XMLFormatter can be used with arbitrary character encodings,
0N/A * but it is recommended that it normally be used with UTF-8. The
0N/A * character encoding can be set on the output Handler.
0N/A *
0N/A * @since 1.4
0N/A */
0N/A
0N/Apublic class XMLFormatter extends Formatter {
0N/A private LogManager manager = LogManager.getLogManager();
0N/A
0N/A // Append a two digit number.
0N/A private void a2(StringBuffer sb, int x) {
0N/A if (x < 10) {
0N/A sb.append('0');
0N/A }
0N/A sb.append(x);
0N/A }
0N/A
0N/A // Append the time and date in ISO 8601 format
0N/A private void appendISO8601(StringBuffer sb, long millis) {
0N/A Date date = new Date(millis);
0N/A sb.append(date.getYear() + 1900);
0N/A sb.append('-');
0N/A a2(sb, date.getMonth() + 1);
0N/A sb.append('-');
0N/A a2(sb, date.getDate());
0N/A sb.append('T');
0N/A a2(sb, date.getHours());
0N/A sb.append(':');
0N/A a2(sb, date.getMinutes());
0N/A sb.append(':');
0N/A a2(sb, date.getSeconds());
0N/A }
0N/A
0N/A // Append to the given StringBuffer an escaped version of the
0N/A // given text string where XML special characters have been escaped.
0N/A // For a null string we append "<null>"
0N/A private void escape(StringBuffer sb, String text) {
0N/A if (text == null) {
0N/A text = "<null>";
0N/A }
0N/A for (int i = 0; i < text.length(); i++) {
0N/A char ch = text.charAt(i);
0N/A if (ch == '<') {
0N/A sb.append("&lt;");
0N/A } else if (ch == '>') {
0N/A sb.append("&gt;");
0N/A } else if (ch == '&') {
0N/A sb.append("&amp;");
0N/A } else {
0N/A sb.append(ch);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Format the given message to XML.
0N/A * <p>
0N/A * This method can be overridden in a subclass.
0N/A * It is recommended to use the {@link Formatter#formatMessage}
0N/A * convenience method to localize and format the message field.
0N/A *
0N/A * @param record the log record to be formatted.
0N/A * @return a formatted log record
0N/A */
0N/A public String format(LogRecord record) {
0N/A StringBuffer sb = new StringBuffer(500);
0N/A sb.append("<record>\n");
0N/A
0N/A sb.append(" <date>");
0N/A appendISO8601(sb, record.getMillis());
0N/A sb.append("</date>\n");
0N/A
0N/A sb.append(" <millis>");
0N/A sb.append(record.getMillis());
0N/A sb.append("</millis>\n");
0N/A
0N/A sb.append(" <sequence>");
0N/A sb.append(record.getSequenceNumber());
0N/A sb.append("</sequence>\n");
0N/A
0N/A String name = record.getLoggerName();
0N/A if (name != null) {
0N/A sb.append(" <logger>");
0N/A escape(sb, name);
0N/A sb.append("</logger>\n");
0N/A }
0N/A
0N/A sb.append(" <level>");
0N/A escape(sb, record.getLevel().toString());
0N/A sb.append("</level>\n");
0N/A
0N/A if (record.getSourceClassName() != null) {
0N/A sb.append(" <class>");
0N/A escape(sb, record.getSourceClassName());
0N/A sb.append("</class>\n");
0N/A }
0N/A
0N/A if (record.getSourceMethodName() != null) {
0N/A sb.append(" <method>");
0N/A escape(sb, record.getSourceMethodName());
0N/A sb.append("</method>\n");
0N/A }
0N/A
0N/A sb.append(" <thread>");
0N/A sb.append(record.getThreadID());
0N/A sb.append("</thread>\n");
0N/A
0N/A if (record.getMessage() != null) {
0N/A // Format the message string and its accompanying parameters.
0N/A String message = formatMessage(record);
0N/A sb.append(" <message>");
0N/A escape(sb, message);
0N/A sb.append("</message>");
0N/A sb.append("\n");
0N/A }
0N/A
0N/A // If the message is being localized, output the key, resource
0N/A // bundle name, and params.
0N/A ResourceBundle bundle = record.getResourceBundle();
0N/A try {
0N/A if (bundle != null && bundle.getString(record.getMessage()) != null) {
0N/A sb.append(" <key>");
0N/A escape(sb, record.getMessage());
0N/A sb.append("</key>\n");
0N/A sb.append(" <catalog>");
0N/A escape(sb, record.getResourceBundleName());
0N/A sb.append("</catalog>\n");
0N/A }
0N/A } catch (Exception ex) {
0N/A // The message is not in the catalog. Drop through.
0N/A }
0N/A
0N/A Object parameters[] = record.getParameters();
0N/A // Check to see if the parameter was not a messagetext format
0N/A // or was not null or empty
0N/A if ( parameters != null && parameters.length != 0
0N/A && record.getMessage().indexOf("{") == -1 ) {
0N/A for (int i = 0; i < parameters.length; i++) {
0N/A sb.append(" <param>");
0N/A try {
0N/A escape(sb, parameters[i].toString());
0N/A } catch (Exception ex) {
0N/A sb.append("???");
0N/A }
0N/A sb.append("</param>\n");
0N/A }
0N/A }
0N/A
0N/A if (record.getThrown() != null) {
0N/A // Report on the state of the throwable.
0N/A Throwable th = record.getThrown();
0N/A sb.append(" <exception>\n");
0N/A sb.append(" <message>");
0N/A escape(sb, th.toString());
0N/A sb.append("</message>\n");
0N/A StackTraceElement trace[] = th.getStackTrace();
0N/A for (int i = 0; i < trace.length; i++) {
0N/A StackTraceElement frame = trace[i];
0N/A sb.append(" <frame>\n");
0N/A sb.append(" <class>");
0N/A escape(sb, frame.getClassName());
0N/A sb.append("</class>\n");
0N/A sb.append(" <method>");
0N/A escape(sb, frame.getMethodName());
0N/A sb.append("</method>\n");
0N/A // Check for a line number.
0N/A if (frame.getLineNumber() >= 0) {
0N/A sb.append(" <line>");
0N/A sb.append(frame.getLineNumber());
0N/A sb.append("</line>\n");
0N/A }
0N/A sb.append(" </frame>\n");
0N/A }
0N/A sb.append(" </exception>\n");
0N/A }
0N/A
0N/A sb.append("</record>\n");
0N/A return sb.toString();
0N/A }
0N/A
0N/A /**
0N/A * Return the header string for a set of XML formatted records.
0N/A *
0N/A * @param h The target handler (can be null)
0N/A * @return a valid XML string
0N/A */
0N/A public String getHead(Handler h) {
0N/A StringBuffer sb = new StringBuffer();
0N/A String encoding;
0N/A sb.append("<?xml version=\"1.0\"");
0N/A
0N/A if (h != null) {
0N/A encoding = h.getEncoding();
0N/A } else {
0N/A encoding = null;
0N/A }
0N/A
0N/A if (encoding == null) {
0N/A // Figure out the default encoding.
0N/A encoding = java.nio.charset.Charset.defaultCharset().name();
0N/A }
0N/A // Try to map the encoding name to a canonical name.
0N/A try {
0N/A Charset cs = Charset.forName(encoding);
0N/A encoding = cs.name();
0N/A } catch (Exception ex) {
0N/A // We hit problems finding a canonical name.
0N/A // Just use the raw encoding name.
0N/A }
0N/A
0N/A sb.append(" encoding=\"");
0N/A sb.append(encoding);
0N/A sb.append("\"");
0N/A sb.append(" standalone=\"no\"?>\n");
0N/A sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
0N/A sb.append("<log>\n");
0N/A return sb.toString();
0N/A }
0N/A
0N/A /**
0N/A * Return the tail string for a set of XML formatted records.
0N/A *
0N/A * @param h The target handler (can be null)
0N/A * @return a valid XML string
0N/A */
0N/A public String getTail(Handler h) {
0N/A return "</log>\n";
0N/A }
0N/A}