/* * Copyright (c) 2003-2008, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.service.log; import java.text.SimpleDateFormat; import java.util.Date; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; /** * LogRef is an utility class that simplifies the use of the LogService. * *

* * LogRef let you use the log without worrying about getting new * * service objects when the log service is restarted. It also * supplies methods * with short names that does logging with all the * different LogService * severity types. * * *

*

* * To use the LogRef you need to import * * org.knopflerfish.service.log.LogRef and instantiate * LogRef * with your bundle context as parameter. The bundle context * is used for * getting the LogService and adding a service listener. * * *

* * *

Example usage

* * The if statement that protects each call to the * LogRef instance below is there to save the effort * required for creating the message string object in cases where the * log will throw away the log entry due to its unimportance. The user * must have this if-test in his code since that is the * only way to avoid constructing the string object. Placing it in the * wrapper (LogRef) will not help due to the design of the Java * programming language. * *
 * package org.knopflerfish.example.hello;
 *
 * import
 * org.osgi.framework.*;
 * import org.knopflerfish.service.log.LogRef;
 *
 *
 * public class Hello implements BundleActivator {
 *   LogRef log;
 *
 *   public void start(BundleContext bundleContext) {
 *     log = new LogRef(bundleContext);
 *     if (log.doInfo()) log.info("Hello started.");
 *   }
 *
 *   public void stop(BundleContext bundleContext) {
 *     if (log.doDebug()) log.debug("Hello stopped.");
 *   }
 * }
 * 
* * * @author Gatespace AB * * @see org.osgi.service.log.LogService * @see org.knopflerfish.service.log.LogService */ public class LogRef implements ServiceListener, LogService { // Class name of the OSGI log service private final static String LOG_CLASS_OSGI = org.osgi.service.log.LogService.class .getName(); // Class name of Knopflerfish extended log service private final static String LOG_CLASS_KF = org.knopflerfish.service.log.LogService.class .getName(); private final static String logServiceFilter = "(|" + "(objectClass=" + LOG_CLASS_KF + ")(objectClass=" + LOG_CLASS_OSGI + "))"; // Date formater used then sending entries to System.out private static SimpleDateFormat simpleDateFormat = null; // Handle to the framework private BundleContext bc; // Service reference for the current log service private ServiceReference logSR; // The current log service private org.osgi.service.log.LogService log; // If true and no log service, print on System.out private boolean useOut; // The id of the calling bundle private long bundleId; // If true warn about using closed LogRef object private boolean doWarnIfClosed; /** * Create new LogRef object for a given bundle. * * @param bc * the bundle context of the bundle that this log ref * instance belongs too. * @param out * If true print messages on System.out when * there is no log service. */ public LogRef(BundleContext bc, boolean out) { init(bc, out); } /** * Create new LogRef object for a given bundle. * *

* * If the system property org.knopflerfish.log.out equals * "true", system.out will be used as fallback if no log service * is found. * *

* * @param bc * the bundle context of the bundle that this log ref * instance belongs too. */ public LogRef(BundleContext bc) { boolean b = false; try { b = "true".equals(System.getProperty("org.knopflerfish.log.out")); } catch (Throwable t) { System.err.println("get system property failed: " + t); t.printStackTrace(); } init(bc, b); } private void init(BundleContext bc, boolean out) { this.bc = bc; useOut = out; bundleId = bc.getBundle().getBundleId(); try { bc.addServiceListener(this, logServiceFilter); } catch (InvalidSyntaxException e) { error("Failed to register log service listener (filter=" + logServiceFilter + ")", e); } } /** * Service listener entry point. Releases the log service object * if one has been fetched. * * @param evt * Service event */ public void serviceChanged(ServiceEvent evt) { if (evt.getServiceReference() == logSR && evt.getType() == ServiceEvent.UNREGISTERING) { ungetLogService(); } } /** * Unget the log service. Note that this method is synchronized on * the same object as the internal method that calls the actual * log service. This ensures that the log service is not removed * by this method while a log message is generated. */ private synchronized void ungetLogService() { doWarnIfClosed = doDebug(); if (log != null) { bc.ungetService(logSR); logSR = null; log = null; } } /** * Close this LogRef object. Ungets the log service if active. */ public void close() { ungetLogService(); bc.removeServiceListener(this); bc = null; } /** * Sends a message to the log if possible. * * @param msg * Human readable string describing the condition. * @param level * The severity of the message (Should be one of the four * predefined severities). * @param sr * The ServiceReference of the service that this * message is associated with. * @param e * The exception that reflects the condition. */ protected synchronized void doLog(String msg, int level, ServiceReference sr, Throwable e) { if (bc != null && log == null) { logSR = bc.getServiceReference(LOG_CLASS_KF); if (logSR == null) { // No service implementing the Knopflerfish extended log, try to // look for a standard OSGi log service. logSR = bc.getServiceReference(LOG_CLASS_OSGI); } if (logSR != null) { log = (org.osgi.service.log.LogService) bc.getService(logSR); } if (log == null) { // Failed to get log service clear the service reference. logSR = null; } } if (log != null) { log.log(sr, level, msg, e); } else if (useOut || doWarnIfClosed) { if (bc == null) { System.err.println("WARNING! Bundle #" + bundleId + " called closed LogRef object"); } // No log service and request for messages on System.out System.out.print(LogUtil.fromLevel(level, 8)); System.out.print(" "); if (simpleDateFormat == null) { simpleDateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); } System.out.print(simpleDateFormat.format(new Date())); System.out.print(" "); System.out.print(getBundleName()); System.out.print(" - "); if (sr != null) { System.out.print("["); System.out.print(sr); System.out.print("] "); } System.out.print(msg); if (e != null) { System.out.print(" ("); System.out.print(e); System.out.print(")"); System.out.println(); e.printStackTrace(); } System.out.println(); } } /** * Returns the current log level. There is no use to generate log * entries with a severity level less than this value since such * entries will be thrown away by the log. * * @return the current severity log level for this bundle. */ public int getLogLevel() { if (log != null && (log instanceof LogService)) { return ((LogService) log).getLogLevel(); } return LOG_DEBUG; } /** * Returns true if messages with severity debug or higher are * saved by the log. * * @return true if messages with severity LOG_DEBUG * or higher are included in the log, otherwise * false. */ public boolean doDebug() { return getLogLevel() >= LOG_DEBUG; } /** * Returns true if messages with severity warning or higher are * saved by the log. * * @return true if messages with severity LOG_WARNING * or higher are included in the log, otherwise * false. */ public boolean doWarn() { return getLogLevel() >= LOG_WARNING; } /** * Returns true if messages with severity info or higher are saved * by the log. * * @return true if messages with severity LOG_INFO or * higher are included in the log, otherwise * false. */ public boolean doInfo() { return getLogLevel() >= LOG_INFO; } /** * Returns true if messages with severity error or higher are * saved by the log. * * @return true if messages with severity LOG_ERROR * or higher are included in the log, otherwise * false. */ public boolean doError() { return getLogLevel() >= LOG_ERROR; } /** * Log a debug level message * * @param msg * Log message. */ public void debug(String msg) { doLog(msg, LOG_DEBUG, (ServiceReference) null, (Throwable) null); } /** * Log a debug level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. */ public void debug(String msg, ServiceReference sr) { doLog(msg, LOG_DEBUG, sr, (Throwable) null); } /** * Log a debug level message. * * @param msg Log message * @param e The exception that reflects the condition. */ public void debug(String msg, Throwable e) { doLog(msg, LOG_DEBUG, (ServiceReference) null, e); } /** * Log a debug level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. * @param e The exception that reflects the condition. */ public void debug(String msg, ServiceReference sr, Throwable e) { doLog(msg, LOG_DEBUG, sr, e); } /** * Log an info level message. * * @param msg Log message */ public void info(String msg) { doLog(msg, LOG_INFO, (ServiceReference) null, (Throwable) null); } /** * Log an info level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. */ public void info(String msg, ServiceReference sr) { doLog(msg, LOG_INFO, sr, (Throwable) null); } /** * Log an info level message. * * @param msg Log message * @param e The exception that reflects the condition. */ public void info(String msg, Throwable e) { doLog(msg, LOG_INFO, (ServiceReference) null, e); } /** * Log an info level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. * @param e The exception that reflects the condition. */ public void info(String msg, ServiceReference sr, Throwable e) { doLog(msg, LOG_INFO, sr, e); } /** * Log a warning level message. * * @param msg Log message */ public void warn(String msg) { doLog(msg, LOG_WARNING, (ServiceReference) null, (Throwable) null); } /** * Log a warning level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. */ public void warn(String msg, ServiceReference sr) { doLog(msg, LOG_WARNING, sr, (Throwable) null); } /** * Log a warning level message. * * @param msg Log message * @param e The exception that reflects the condition. */ public void warn(String msg, Throwable e) { doLog(msg, LOG_WARNING, (ServiceReference) null, e); } /** * Log a warning level message. * * @param msg Log message * @param sr The ServiceReference of the service * that this message is associated with. * @param e The exception that reflects the condition. */ public void warn(String msg, ServiceReference sr, Throwable e) { doLog(msg, LOG_WARNING, sr, e); } /** * Log an error level message. * * @param msg Log message */ public void error(String msg) { doLog(msg, LOG_ERROR, (ServiceReference) null, (Throwable) null); } /** * Log an error level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. */ public void error(String msg, ServiceReference sr) { doLog(msg, LOG_ERROR, sr, (Throwable) null); } /** * Log an error level message. * * @param msg Log message * @param e The exception that reflects the condition. */ public void error(String msg, Throwable e) { doLog(msg, LOG_ERROR, (ServiceReference) null, e); } /** * Log an error level message. * * @param msg Log message * @param sr The ServiceReference of the service that * this message is associated with. * @param e The exception that reflects the condition. */ public void error(String msg, ServiceReference sr, Throwable e) { doLog(msg, LOG_ERROR, sr, e); } /** * Log a message. The ServiceDescription field and the Throwable * field of the LogEntry will be set to null. * * @param level The severity of the message. (Should be one of the * four predefined severities.) * @param message Human readable string describing the condition. */ public void log(int level, String message) { doLog(message, level, (ServiceReference) null, (Throwable) null); } /** * Log a message with an exception. The ServiceDescription field * of the LogEntry will be set to null. * * @param level The severity of the message. (Should be one of the * four predefined severities.) * @param message Human readable string describing the * condition. * @param exception The exception that reflects the condition. */ public void log(int level, String message, Throwable exception) { doLog(message, level, (ServiceReference) null, exception); } /** * Log a message associated with a specific Service. The Throwable * field of the LogEntry will be set to null. * * @param sr The ServiceReference of the service that * this message is associated with. * @param level The severity of the message. (Should be one of the * four predefined severities.) * @param message Human readable string describing the condition. */ public void log(ServiceReference sr, int level, String message) { doLog(message, level, sr, (Throwable) null); } /** * Log a message with an exception associated with a specific * Service. * * @param sr The ServiceReference of the service that * this message is associated with. * @param level The severity of the message. (Should be one of the * four predefined severities.) * @param message Human readable string describing the condition. * @param exception * The exception that reflects the condition. */ public void log(ServiceReference sr, int level, String message, Throwable exception) { doLog(message, level, sr, exception); } /** * Returns a human readable name for the bundle that * bc represents. * * @return Name of the bundle that uses this wrapper (at least 12 * characters). */ private String getBundleName() { StringBuffer bundleName = new StringBuffer(24); // We can't get bundle-name since it requires AdminPermission. // bundleName.append((String)bc.getBundle().getHeaders().get("Bundle-Name")); // If name was not found use the Bid as name. if (bundleName.length() <= 0) { bundleName.append("bid#"); bundleName.append(String.valueOf(bundleId)); } if (bundleName.length() < 12) { bundleName.append(" "); bundleName.setLength(12); } return bundleName.toString(); } }