/******************************************************************************* * Copyright (c) 2009 Paul VanderLei, Simon Archer, Jeff McAffer and others. All * rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Toast is an Equinox/OSGi system developed for the book Eclipse, Equinox and * OSGi - Creating Highly Modular Java Applications See http://equinoxosgi.org * * Contributors: Paul VanderLei, Simon Archer and Jeff McAffer - initial API and * implementation *******************************************************************************/ package net.certware.internal.core; import java.util.Calendar; import java.util.Date; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogService; /** * Log proxy implementing the basic log service. * @author Eclipse Toast * @since 1.0 */ public class LogProxy extends Object implements LogService { private static final char DATE_DELIMETER = '-'; private static final int DEFAULT_BUFFER_SIZE = 5 * 1024; // 5K private static final char TIME_DELIMETER = ':'; private static final char WHITESPACE = ' '; private static final char ZERO_PADDING = '0'; private static final Calendar CALENDAR = Calendar.getInstance(); private static Calendar getCalendar() { Date now = new Date(); LogProxy.CALENDAR.setTime(now); return LogProxy.CALENDAR; } private StringBuffer buffer; private LogService consoleLog; private volatile LogService log; private volatile int logLevel; /** * Constructor that builds a <code>LogProxy</code> that does not have a * contained <code>LogService</code>. Requests will be delegated to an * instance of <code>ConsoleLog</code>, which is created via lazy * initialization. */ public LogProxy() { super(); } /** * Constructor that builds a <code>LogProxy</code> with a contained * <code>LogService</code> to which requests will be delegated. * * @param log * A log service. */ public LogProxy(LogService log) { super(); setLog(log); } /** * Append the current date to the buffer. This code must be executed while * synchronized on the buffer. The date will be written out in the following * format: yyyy-mm-dd. * * @param calendar * A Calendar. */ private void appendDate(Calendar calendar) { StringBuffer buffer = getBuffer(); // Year int year = calendar.get(Calendar.YEAR); buffer.append(year); // Month buffer.append(LogProxy.DATE_DELIMETER); int month = calendar.get(Calendar.MONTH) + 1; if (month < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(month); // Day buffer.append(LogProxy.DATE_DELIMETER); int day = calendar.get(Calendar.DAY_OF_MONTH); if (day < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(day); } /** * Append the current time to the buffer. This code must be executed while * synchronized on the buffer. The date will be written out in the following * format: "hh:mm:ss.xxx". Note that "xxx" signifies milliseconds. * * @param calendar * A Calendar. */ private void appendTime(Calendar calendar) { StringBuffer buffer = getBuffer(); // Hours int hour = calendar.get(Calendar.HOUR_OF_DAY); if (hour < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(hour); // Minutes buffer.append(LogProxy.TIME_DELIMETER); int minute = calendar.get(Calendar.MINUTE); if (minute < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(minute); // Seconds buffer.append(LogProxy.TIME_DELIMETER); int second = calendar.get(Calendar.SECOND); if (second < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(second); // Milliseconds buffer.append('.'); int millisecond = calendar.get(Calendar.MILLISECOND); if (millisecond < 100) { buffer.append(LogProxy.ZERO_PADDING); } if (millisecond < 10) { buffer.append(LogProxy.ZERO_PADDING); } buffer.append(millisecond); } private void checkLevel(int level) { if (level >= LogService.LOG_ERROR && level <= LogService.LOG_DEBUG) return; // Early return. String message = "The log level " + level + " is unknown"; throw new IllegalArgumentException(message); } private String formatMessage(String message) { String formattedMessage; StringBuffer buffer = getBuffer(); // It is very important to synchronize on the buffer to ensure that only // one thread uses the buffer at a time. A buffer is used to improve // performance and reduce garbage generation. synchronized (buffer) { // Since the buffer is reused, it must be emptied before each use. int count = buffer.length(); buffer.delete(0, count); Calendar calendar = LogProxy.getCalendar(); appendDate(calendar); buffer.append(LogProxy.WHITESPACE); appendTime(calendar); buffer.append(LogProxy.WHITESPACE); buffer.append('-'); buffer.append(LogProxy.WHITESPACE); buffer.append(message); formattedMessage = buffer.toString(); } return formattedMessage; } private StringBuffer getBuffer() { synchronized (this) { if (buffer == null) { setBuffer(new StringBuffer(LogProxy.DEFAULT_BUFFER_SIZE)); } return buffer; } } private LogService getConsoleLog() { synchronized (this) { if (consoleLog == null) { setConsoleLog(new ConsoleLog()); } return consoleLog; } } /** * Gets the log. * @return log */ public LogService getLog() { return log; } /** * Gets the log level. * @return log level */ public int getLogLevel() { return logLevel; } private boolean isLogging(int level) { int threshold = getLogLevel(); boolean logging = threshold >= level; return logging; } /** * @see org.osgi.service.log.LogService#log(int, java.lang.String) */ public void log(int level, String message) { log(null, level, message, null); } /** * @see org.osgi.service.log.LogService#log(int, java.lang.String, * java.lang.Throwable) */ public void log(int level, String message, Throwable throwable) { log(null, level, message, throwable); } /** * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, * int, java.lang.String) */ @SuppressWarnings("rawtypes") public void log(org.osgi.framework.ServiceReference reference, int level, String message) { log(reference, level, message, null); } /** * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, * int, java.lang.String, java.lang.Throwable) */ @SuppressWarnings("rawtypes") public void log(ServiceReference reference, int level, String message, Throwable throwable) { boolean logging = isLogging(level); if (logging == false) return; LogService log = getLog(); if (log == null) { log = getConsoleLog(); } String formattedMessage = formatMessage(message); log.log(reference, level, formattedMessage, throwable); } private void setBuffer(StringBuffer buffer) { this.buffer = buffer; } private void setConsoleLog(LogService consoleLog) { this.consoleLog = consoleLog; } /** * Sets the log service. * @param log log service */ public void setLog(LogService log) { if (equals(log) == true) return; // Early return. if (this.log != null && log != null) return; // Early return. this.log = log; } /** * Sets the log level. * @param logLevel log level, checked */ public void setLogLevel(int logLevel) { checkLevel(logLevel); this.logLevel = logLevel; } }