Moving the EventAdmin from sandbox to trunk (FELIX-19)
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@397861 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.eventadmin/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java b/org.apache.felix.eventadmin/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java
new file mode 100644
index 0000000..e1cc5e7
--- /dev/null
+++ b/org.apache.felix.eventadmin/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2005 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.felix.eventadmin.impl.util;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This class mimics the standard OSGi <tt>LogService</tt> interface. An
+ * instance of this class will be used by the EventAdmin for all logging. The
+ * implementation of this class sends log messages to standard output, if no
+ * <tt>LogService</tt> is present; it uses a log service if one is
+ * installed in the framework. To do that without creating a hard dependency on the
+ * package it uses fully qualified class names and registers a listener with the
+ * framework hence, it does not need access to the <tt>LogService</tt> class but will
+ * use it if the listener is informed about an available service. By using a
+ * DynamicImport-Package dependency we don't need the package but
+ * use it if present. Additionally, all log methods prefix the log message with
+ * <tt>EventAdmin: </tt>.
+ *
+ * @see org.osgi.service.log.LogService
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+**/
+// TODO: At the moment we log a message to all currently available LogServices.
+// Maybe, we should only log to the one with the highest ranking instead?
+// What is the best practice in this case?
+public class LogWrapper
+{
+ /**
+ * ERROR LEVEL
+ *
+ * @see org.osgi.service.log.LogService#LOG_ERROR
+ */
+ public static final int LOG_ERROR = 1;
+
+ /**
+ * WARNING LEVEL
+ *
+ * @see org.osgi.service.log.LogService#LOG_WARNING
+ */
+ public static final int LOG_WARNING = 2;
+
+ /**
+ * INFO LEVEL
+ *
+ * @see org.osgi.service.log.LogService#LOG_INFO
+ */
+ public static final int LOG_INFO = 3;
+
+ /**
+ * DEBUG LEVEL
+ *
+ * @see org.osgi.service.log.LogService#LOG_DEBUG
+ */
+ public static final int LOG_DEBUG = 4;
+
+ // A set containing the currently available LogServices. Furthermore used as lock
+ private final Set m_loggerRefs = new HashSet();
+
+ // Only null while not set and m_loggerRefs is empty hence, only needs to be
+ // checked in case m_loggerRefs is empty otherwise it will not be null.
+ private BundleContext m_context;
+
+ /*
+ * A thread save variant of the double checked locking singleton.
+ */
+ private static class LogWrapperLoader
+ {
+ static final LogWrapper m_singleton = new LogWrapper();
+ }
+
+ /**
+ * Returns the singleton instance of this LogWrapper that can be used to send
+ * log messages to all currently available LogServices or to standard output,
+ * respectively.
+ *
+ * @return the singleton instance of this LogWrapper.
+ */
+ public static LogWrapper getLogger()
+ {
+ return LogWrapperLoader.m_singleton;
+ }
+
+ /**
+ * Set the <tt>BundleContext</tt> of the bundle. This method registers a service
+ * listener for LogServices with the framework that are subsequently used to
+ * log messages.
+ *
+ * @param context The context of the bundle.
+ */
+ public static void setContext(final BundleContext context)
+ {
+ LogWrapperLoader.m_singleton.setBundleContext(context);
+
+ try
+ {
+ context.addServiceListener(new ServiceListener()
+ {
+ // Add a newly available LogService reference to the singleton.
+ public void serviceChanged(final ServiceEvent event)
+ {
+ if (ServiceEvent.REGISTERED == event.getType())
+ {
+ LogWrapperLoader.m_singleton.addLoggerRef(
+ event.getServiceReference());
+ }
+ // unregistered services are handled in the next log operation.
+ }
+
+ }, "(" + Constants.OBJECTCLASS
+ + "=org.osgi.service.log.LogService)");
+
+ // Add all available LogService references to the singleton.
+ final ServiceReference[] refs = context.getServiceReferences(
+ "org.osgi.service.log.LogService", null);
+
+ if (null != refs)
+ {
+ for (int i = 0; i < refs.length; i++)
+ {
+ LogWrapperLoader.m_singleton.addLoggerRef(refs[i]);
+ }
+ }
+ } catch (InvalidSyntaxException e)
+ {
+ // this never happens
+ }
+ }
+
+ /*
+ * The private singleton constructor.
+ */
+ LogWrapper()
+ {
+ // Singleton
+ }
+
+ /*
+ * Add a reference to a newly available LogService
+ */
+ void addLoggerRef(final ServiceReference ref)
+ {
+ synchronized (m_loggerRefs)
+ {
+ m_loggerRefs.add(ref);
+ }
+ }
+
+ /*
+ * Set the context of the bundle in the singleton implementation.
+ */
+ private void setBundleContext(final BundleContext context)
+ {
+ synchronized(m_loggerRefs)
+ {
+ m_context = context;
+ }
+ }
+
+ /**
+ * Log a message with the given log level. Note that this will prefix the message
+ * with <tt>EventAdmin: </tt>.
+ *
+ * @param level The log level with which to log the msg.
+ * @param msg The message to log.
+ */
+ public void log(final int level, final String msg)
+ {
+ // The method will remove any unregistered service reference as well.
+ synchronized(m_loggerRefs)
+ {
+ final String logMsg = "EventAdmin: " + msg;
+
+ if (!m_loggerRefs.isEmpty())
+ {
+ // There is at least one LogService available hence, we can use the
+ // class as well.
+ for (Iterator iter = m_loggerRefs.iterator(); iter.hasNext();)
+ {
+ org.osgi.service.log.LogService logger =
+ (org.osgi.service.log.LogService) m_context.getService(
+ (ServiceReference) iter.next());
+
+ if (null != logger)
+ {
+ logger.log(level, logMsg);
+ }
+ else
+ {
+ // The context returned null for the reference - it follows
+ // that the service is unregistered and we can remove it
+ iter.remove();
+ }
+ }
+ }
+ else
+ {
+ _log(null, level, logMsg, null);
+ }
+ }
+ }
+
+ /**
+ * Log a message with the given log level and the associated exception. Note that
+ * this will prefix the message with <tt>EventAdmin: </tt>.
+ *
+ * @param level The log level with which to log the msg.
+ * @param msg The message to log.
+ * @param ex The exception associated with the message.
+ */
+ public void log(final int level, final String msg, final Throwable ex)
+ {
+ // The method will remove any unregistered service reference as well.
+ synchronized(m_loggerRefs)
+ {
+ final String logMsg = "EventAdmin: " + msg;
+
+ if (!m_loggerRefs.isEmpty())
+ {
+ // There is at least one LogService available hence, we can use the
+ // class as well.
+ for (Iterator iter = m_loggerRefs.iterator(); iter.hasNext();)
+ {
+ org.osgi.service.log.LogService logger =
+ (org.osgi.service.log.LogService) m_context.getService(
+ (ServiceReference) iter.next());
+
+ if (null != logger)
+ {
+ logger.log(level, logMsg, ex);
+ }
+ else
+ {
+ // The context returned null for the reference - it follows
+ // that the service is unregistered and we can remove it
+ iter.remove();
+ }
+ }
+ }
+ else
+ {
+ _log(null, level, logMsg, ex);
+ }
+ }
+ }
+
+ /**
+ * Log a message with the given log level together with the associated service
+ * reference. Note that this will prefix the message with <tt>EventAdmin: </tt>.
+ *
+ * @param sr The reference of the service associated with this message.
+ * @param level The log level with which to log the msg.
+ * @param msg The message to log.
+ */
+ public void log(final ServiceReference sr, final int level, final String msg)
+ {
+ // The method will remove any unregistered service reference as well.
+ synchronized(m_loggerRefs)
+ {
+ final String logMsg = "EventAdmin: " + msg;
+
+ if (!m_loggerRefs.isEmpty())
+ {
+ // There is at least one LogService available hence, we can use the
+ // class as well.
+ for (Iterator iter = m_loggerRefs.iterator(); iter.hasNext();)
+ {
+ org.osgi.service.log.LogService logger =
+ (org.osgi.service.log.LogService) m_context.getService(
+ (ServiceReference) iter.next());
+
+ if (null != logger)
+ {
+ logger.log(sr, level, logMsg);
+ }
+ else
+ {
+ // The context returned null for the reference - it follows
+ // that the service is unregistered and we can remove it
+ iter.remove();
+ }
+ }
+ }
+ else
+ {
+ _log(sr, level, logMsg, null);
+ }
+ }
+ }
+
+ /**
+ * Log a message with the given log level, the associated service reference and
+ * exception. Note that this will prefix the message with <tt>EventAdmin: </tt>.
+ *
+ * @param sr The reference of the service associated with this message.
+ * @param level The log level with which to log the msg.
+ * @param msg The message to log.
+ * @param ex The exception associated with the message.
+ */
+ public void log(final ServiceReference sr, final int level, final String msg,
+ final Throwable ex)
+ {
+ // The method will remove any unregistered service reference as well.
+ synchronized(m_loggerRefs)
+ {
+ final String logMsg = "EventAdmin: " + msg;
+
+ if (!m_loggerRefs.isEmpty())
+ {
+ // There is at least one LogService available hence, we can use the
+ // class as well.
+ for (Iterator iter = m_loggerRefs.iterator(); iter.hasNext();)
+ {
+ org.osgi.service.log.LogService logger =
+ (org.osgi.service.log.LogService) m_context.getService(
+ (ServiceReference) iter.next());
+
+ if (null != logger)
+ {
+ logger.log(sr, level, logMsg, ex);
+ }
+ else
+ {
+ // The context returned null for the reference - it follows
+ // that the service is unregistered and we can remove it
+ iter.remove();
+ }
+ }
+ }
+ else
+ {
+ _log(sr, level, logMsg, ex);
+ }
+ }
+ }
+
+ /*
+ * Log the message to standard output. This appends the level to the message.
+ * null values are handled appropriate.
+ */
+ private void _log(final ServiceReference sr, final int level, final String msg,
+ Throwable ex)
+ {
+ String s = (sr == null) ? null : "SvcRef " + sr;
+ s = (s == null) ? msg : s + " " + msg;
+ s = (ex == null) ? s : s + " (" + ex + ")";
+
+ switch (level)
+ {
+ case LOG_DEBUG:
+ System.out.println("DEBUG: " + s);
+ break;
+ case LOG_ERROR:
+ System.out.println("ERROR: " + s);
+ if (ex != null)
+ {
+ if ((ex instanceof BundleException)
+ && (((BundleException) ex).getNestedException() != null))
+ {
+ ex = ((BundleException) ex).getNestedException();
+ }
+
+ ex.printStackTrace();
+ }
+ break;
+ case LOG_INFO:
+ System.out.println("INFO: " + s);
+ break;
+ case LOG_WARNING:
+ System.out.println("WARNING: " + s);
+ break;
+ default:
+ System.out.println("UNKNOWN[" + level + "]: " + s);
+ }
+ }
+}