killbill-memoizeit

osgi-bundles: add new logger bundle This new logger bundle

3/1/2013 4:57:16 PM

Details

diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
new file mode 100644
index 0000000..496394e
--- /dev/null
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2013 Ning, Inc.
+  ~
+  ~ Ning 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill-osgi-bundles</artifactId>
+        <version>0.1.56-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-osgi-bundles-logger</artifactId>
+    <name>Killbill billing platform: OSGI logger bundle</name>
+    <packaging>bundle</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>com.ning.billing.osgi.bundles.logger.Activator</Bundle-Activator>
+                        <Export-Package></Export-Package>
+                        <Private-Package>com.ning.billing.osgi.bundles.logger.*</Private-Package>
+                        <!-- Optional resolution because exported by the Felix system bundle -->
+                        <Import-Package>*;resolution:=optional</Import-Package>
+                    </instructions>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble-killbill-osgi-bundles-logger</id>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <createSourcesJar>true</createSourcesJar>
+                            <shadedArtifactAttached>true</shadedArtifactAttached>
+                            <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
+                            <filters>
+                                <filter>
+                                    <artifact>${project.groupId}:${project.artifactId}</artifact>
+                                </filter>
+                            </filters>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/Activator.java b/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/Activator.java
new file mode 100644
index 0000000..7ab3d97
--- /dev/null
+++ b/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/Activator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi.bundles.logger;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.osgi.framework.BundleActivator;
+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;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+
+    private static final Logger logger = LoggerFactory.getLogger(Activator.class);
+
+    private final LogListener killbillLogListener = new KillbillLogWriter();
+    private final List<LogReaderService> logReaderServices = new LinkedList<LogReaderService>();
+
+    private final ServiceListener logReaderServiceListener = new ServiceListener() {
+        public void serviceChanged(final ServiceEvent event) {
+            final ServiceReference serviceReference = event.getServiceReference();
+            if (serviceReference == null || serviceReference.getBundle() == null) {
+                return;
+            }
+
+            final BundleContext bundleContext = serviceReference.getBundle().getBundleContext();
+            if (bundleContext == null) {
+                return;
+            }
+
+            final LogReaderService logReaderService = (LogReaderService) bundleContext.getService(serviceReference);
+            if (logReaderService != null) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    registerLogReaderService(logReaderService);
+                } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    logReaderService.removeLogListener(killbillLogListener);
+                    logReaderServices.remove(logReaderService);
+                }
+            }
+        }
+    };
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        // Get a list of all the registered LogReaderService, and add the killbill listener
+        final ServiceTracker logReaderTracker = new ServiceTracker(context, LogReaderService.class.getName(), null);
+        logReaderTracker.open();
+        final Object[] readers = logReaderTracker.getServices();
+        if (readers != null) {
+            for (final Object reader : readers) {
+                final LogReaderService service = (LogReaderService) reader;
+                registerLogReaderService(service);
+            }
+        }
+        logReaderTracker.close();
+
+        // Add the ServiceListener
+        final String filter = "(objectclass=" + LogReaderService.class.getName() + ")";
+        try {
+            context.addServiceListener(logReaderServiceListener, filter);
+        } catch (InvalidSyntaxException e) {
+            logger.warn("Unable to register the killbill LogReaderService listener", e);
+        }
+    }
+
+    @Override
+    public void stop(final BundleContext context) throws Exception {
+        for (final Iterator<LogReaderService> iterator = logReaderServices.iterator(); iterator.hasNext(); ) {
+            final LogReaderService service = iterator.next();
+            service.removeLogListener(killbillLogListener);
+            iterator.remove();
+        }
+    }
+
+    private void registerLogReaderService(final LogReaderService service) {
+        logReaderServices.add(service);
+        service.addLogListener(killbillLogListener);
+    }
+}
diff --git a/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/KillbillLogWriter.java b/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/KillbillLogWriter.java
new file mode 100644
index 0000000..eea8293
--- /dev/null
+++ b/osgi-bundles/bundles/logger/src/main/java/com/ning/billing/osgi/bundles/logger/KillbillLogWriter.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.osgi.bundles.logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// Inspired by osgi-over-slf4j
+public class KillbillLogWriter implements LogListener {
+
+    private static final String UNKNOWN = "[Unknown]";
+
+    private final Map<String, Logger> delegates = new HashMap<String, Logger>();
+
+    // Invoked by the log service implementation for each log entry
+    public void logged(final LogEntry entry) {
+        final Bundle bundle = entry.getBundle();
+        final Logger delegate = getDelegateForBundle(bundle);
+
+        final ServiceReference serviceReference = entry.getServiceReference();
+        final int level = entry.getLevel();
+        final String message = entry.getMessage();
+        final Throwable exception = entry.getException();
+
+        if (serviceReference != null && exception != null) {
+            log(delegate, serviceReference, level, message, exception);
+        } else if (serviceReference != null) {
+            log(delegate, serviceReference, level, message);
+        } else if (exception != null) {
+            log(delegate, level, message, exception);
+        } else {
+            log(delegate, level, message);
+        }
+    }
+
+    private Logger getDelegateForBundle(/* @Nullable */ final Bundle bundle) {
+        final String loggerName;
+        if (bundle != null) {
+            final String name = bundle.getSymbolicName();
+            Version version = bundle.getVersion();
+            if (version == null) {
+                version = Version.emptyVersion;
+            }
+            loggerName = name + '.' + version;
+        } else {
+            loggerName = KillbillLogWriter.class.getName();
+        }
+
+        if (delegates.get(loggerName) == null) {
+            synchronized (delegates) {
+                if (delegates.get(loggerName) == null) {
+                    delegates.put(loggerName, LoggerFactory.getLogger(loggerName));
+                }
+            }
+        }
+
+        return delegates.get(loggerName);
+    }
+
+    private void log(final Logger delegate, final int level, final String message) {
+        switch (level) {
+            case LogService.LOG_DEBUG:
+                delegate.debug(message);
+                break;
+            case LogService.LOG_ERROR:
+                delegate.error(message);
+                break;
+            case LogService.LOG_INFO:
+                delegate.info(message);
+                break;
+            case LogService.LOG_WARNING:
+                delegate.warn(message);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void log(final Logger delegate, final int level, final String message, final Throwable exception) {
+        switch (level) {
+            case LogService.LOG_DEBUG:
+                delegate.debug(message, exception);
+                break;
+            case LogService.LOG_ERROR:
+                delegate.error(message, exception);
+                break;
+            case LogService.LOG_INFO:
+                delegate.info(message, exception);
+                break;
+            case LogService.LOG_WARNING:
+                delegate.warn(message, exception);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void log(final Logger delegate, final ServiceReference sr, final int level, final String message) {
+        switch (level) {
+            case LogService.LOG_DEBUG:
+                if (delegate.isDebugEnabled()) {
+                    delegate.debug(createMessage(sr, message));
+                }
+                break;
+            case LogService.LOG_ERROR:
+                if (delegate.isErrorEnabled()) {
+                    delegate.error(createMessage(sr, message));
+                }
+                break;
+            case LogService.LOG_INFO:
+                if (delegate.isInfoEnabled()) {
+                    delegate.info(createMessage(sr, message));
+                }
+                break;
+            case LogService.LOG_WARNING:
+                if (delegate.isWarnEnabled()) {
+                    delegate.warn(createMessage(sr, message));
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void log(final Logger delegate, final ServiceReference sr, final int level, final String message, final Throwable exception) {
+        switch (level) {
+            case LogService.LOG_DEBUG:
+                if (delegate.isDebugEnabled()) {
+                    delegate.debug(createMessage(sr, message), exception);
+                }
+                break;
+            case LogService.LOG_ERROR:
+                if (delegate.isErrorEnabled()) {
+                    delegate.error(createMessage(sr, message), exception);
+                }
+                break;
+            case LogService.LOG_INFO:
+                if (delegate.isInfoEnabled()) {
+                    delegate.info(createMessage(sr, message), exception);
+                }
+                break;
+            case LogService.LOG_WARNING:
+                if (delegate.isWarnEnabled()) {
+                    delegate.warn(createMessage(sr, message), exception);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Formats the log message to indicate the service sending it, if known.
+     *
+     * @param sr      the ServiceReference sending the message.
+     * @param message The message to log.
+     * @return The formatted log message.
+     */
+    private String createMessage(final ServiceReference sr, final String message) {
+        final StringBuilder output = new StringBuilder();
+        if (sr != null) {
+            output.append('[').append(sr.toString()).append(']');
+        } else {
+            output.append(UNKNOWN);
+        }
+        output.append(message);
+
+        return output.toString();
+    }
+}
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
index eaeeee5..ddb3703 100644
--- a/osgi-bundles/bundles/pom.xml
+++ b/osgi-bundles/bundles/pom.xml
@@ -28,6 +28,7 @@
     <packaging>pom</packaging>
     <modules>
         <module>jruby</module>
+        <module>logger</module>
         <module>meter</module>
         <module>webconsolebranding</module>
     </modules>
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index ee54038..ec98490 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -34,6 +34,10 @@
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-osgi-bundles-logger</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
             <artifactId>killbill-osgi-bundles-webconsolebranding</artifactId>
         </dependency>
         <dependency>
@@ -126,10 +130,6 @@
             <artifactId>org.apache.felix.webconsole</artifactId>
             <version>3.1.8</version>
         </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>osgi-over-slf4j</artifactId>
-        </dependency>
     </dependencies>
     <build>
         <plugins>

pom.xml 5(+5 -0)

diff --git a/pom.xml b/pom.xml
index 4ba75e5..3e80817 100644
--- a/pom.xml
+++ b/pom.xml
@@ -286,6 +286,11 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-osgi-bundles-logger</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
                 <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
                 <version>${project.version}</version>
             </dependency>