/*
* 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.persistence.admin;
import java.util.*;
import java.io.PrintWriter;
import java.text.*;
/**
* Provides single point for all log messages to written to. Currently this class only supports
* static methods and always writes to stdout.
*
*/
public class Logger {
private static final PrintWriter logWriter = new PrintWriter(System.out, true);
// Set LOGWIDTH to maxint as a cheap way of turning off formatting
private static final int LOGWIDTH = Integer.MAX_VALUE;
private static final SimpleDateFormat timeFormatter;
static {
final String defaultFormatPattern = "MM/dd/yy HH:mm:ss.SSS z";
final String resourceName = "org.apache.persistence.admin.LoggerResources";
final String keyName = "logger.timeStampFormat";
String formatPattern = defaultFormatPattern;
SimpleDateFormat sdf;
try {
ResourceBundle messageRB = ResourceBundle.getBundle(resourceName);
try {
formatPattern = messageRB.getString(keyName);
} catch (MissingResourceException e) {
System.out.println("NOTICE: Logger using default timestamp format."
+ " Could not get resource key \"" + keyName + "\" because: " + e);
}
} catch (MissingResourceException e) {
System.out.println("NOTICE: Logger using default timestamp format."
+ " Could not load resource bundle \"" + resourceName + "\" because: " + e);
}
if (formatPattern.length() == 0) {
sdf = null;
} else {
try {
sdf = new SimpleDateFormat(formatPattern);
} catch (RuntimeException e) {
System.out.println("NOTICE: ignoring timestamp pattern \"" + formatPattern + "\" because: "
+ e.toString());
System.out.println(" Using default pattern: \"" + defaultFormatPattern + "\".");
formatPattern = defaultFormatPattern;
sdf = new SimpleDateFormat(formatPattern);
}
}
timeFormatter = sdf;
}
static private void formatText(PrintWriter writer, String target, int maxLength,
int initialLength) {
BreakIterator boundary = BreakIterator.getLineInstance();
boundary.setText(target);
int start = boundary.first();
int end = boundary.next();
int lineLength = initialLength;
while (end != BreakIterator.DONE) {
// Look at the end and only accept whitespace breaks
char endChar = target.charAt(end - 1);
while (!Character.isWhitespace(endChar)) {
int lastEnd = end;
end = boundary.next();
if (end == BreakIterator.DONE) {
// give up. We are at the end of the string
end = lastEnd;
break;
}
endChar = target.charAt(end - 1);
}
int wordEnd = end;
if (endChar == '\n') {
// trim off the \n since println will do it for us
wordEnd--;
} else if (endChar == '\t') {
// figure tabs use 8 characters
lineLength += 7;
}
String word = target.substring(start, wordEnd);
if ((lineLength + word.length()) >= maxLength) {
if (lineLength != 0) {
writer.println();
writer.print(" ");
lineLength = 2;
}
}
lineLength += word.length();
writer.print(word);
if (endChar == '\n') {
// force end of line
writer.println();
writer.print(" ");
lineLength = 2;
}
start = end;
end = boundary.next();
}
if (lineLength != 0) {
writer.println();
}
}
/**
* Gets a String representation of the current time.
*
* @return a String representation of the current time.
*/
static public String getTimeStamp() {
return formatDate(new Date());
}
/**
* Convert a Date to a timestamp String.
*
* @param d a Date to format as a timestamp String.
* @return a String representation of the current time.
*/
static public String formatDate(Date d) {
if (timeFormatter == null) {
try {
// very simple format that shows millisecond resolution
return Long.toString(d.getTime());
} catch (Exception ignore) {
return "timestampFormatFailed";
}
}
try {
synchronized (timeFormatter) {
// Need sync: see bug 21858
return timeFormatter.format(d);
}
} catch (Exception e1) {
// Fix bug 21857
try {
return d.toString();
} catch (Exception e2) {
try {
return Long.toString(d.getTime());
} catch (Exception e3) {
return "timestampFormatFailed";
}
}
}
}
/**
* Logs a message to the static log destination.
*
* @param msg the actual message to log
*/
static public void put(String msg) {
put(msg, (Throwable) null);
}
/**
* Logs a message to the specified log destination.
*
* @param log the <code>PrintWriter</code> that the message will be written to.
* @param msg the actual message to log
*/
static public void put(PrintWriter log, String msg) {
put(log, msg, (Throwable) null);
}
/**
* Logs an exception to the static log destination.
*
* @param exception the actual Exception to log
*/
static public void put(Throwable exception) {
put((String) null, exception);
}
/**
* Logs an exception to the specified log destination.
*
* @param log the <code>PrintWriter</code> that the message will be written to.
* @param exception the actual Exception to log
*/
static public void put(PrintWriter log, Throwable exception) {
put(log, (String) null, exception);
}
/**
* Logs a message and an exception to the static log destination.
*
* @param msg the actual message to log
* @param exception the actual Exception to log
*/
static public void put(String msg, Throwable exception) {
put(logWriter, msg, exception);
}
/**
* Logs a message and an exception to the specified log destination.
*
* @param log the <code>PrintWriter</code> that the message will be written to. If null then the
* default stdout writer is used.
* @param msg the actual message to log
* @param exception the actual Exception to log
*/
static public void put(PrintWriter log, String msg, Throwable exception) {
java.io.StringWriter sw = new java.io.StringWriter();
String header;
PrintWriter pw = new PrintWriter(sw);
pw.println();
header = '[' + getTimeStamp() + ' ' + Thread.currentThread().getName() + "] ";
pw.print(header);
if (msg != null) {
try {
formatText(pw, msg, LOGWIDTH, header.length());
} catch (RuntimeException e) {
pw.println(msg);
pw.println("Ignoring exception:");
e.printStackTrace(pw);
}
} else {
pw.println();
}
if (exception != null) {
exception.printStackTrace(pw);
}
pw.close();
try {
sw.close();
} catch (java.io.IOException ignore) {
}
if (log == null) {
log = logWriter;
}
log.print(sw.toString());
log.flush();
}
/**
* Formats a message. Takes special care when invoking the toString() method of objects that might
* cause NPEs.
*/
public static String format(String format, Object[] objs) {
String[] strings = new String[objs.length];
for (int i = 0; i < objs.length; i++) {
Object obj = objs[i];
if (obj == null) {
strings[i] = "null";
} else {
try {
strings[i] = obj.toString();
} catch (Exception ex) {
strings[i] = obj.getClass().getName() + "@" + System.identityHashCode(obj);
}
}
}
return java.text.MessageFormat.format(format, (Object[]) strings);
}
}