Author: bdelacretaz
Date: Tue Sep 15 14:52:13 2009
New Revision: 815351

URL: http://svn.apache.org/viewvc?rev=815351&view=rev
Log:
SLING-1109 - OSGi events recorder and console plugin

Added:
    sling/trunk/contrib/extensions/osgi-profiler/   (with props)
    sling/trunk/contrib/extensions/osgi-profiler/pom.xml   (with props)
    sling/trunk/contrib/extensions/osgi-profiler/src/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/java/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/impl/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
   (with props)
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
   (with props)
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
   (with props)
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
   (with props)
    sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/
    sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/
    
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties
   (with props)

Propchange: sling/trunk/contrib/extensions/osgi-profiler/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Sep 15 14:52:13 2009
@@ -0,0 +1,15 @@
+target
+sling
+bin
+logs
+jackrabbit-repository
+derby.log
+*.iml
+*.ipr
+*.iws
+.settings
+.project
+.classpath
+.externalToolBuilders
+maven-eclipse.xml
+

Added: sling/trunk/contrib/extensions/osgi-profiler/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/pom.xml?rev=815351&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/osgi-profiler/pom.xml (added)
+++ sling/trunk/contrib/extensions/osgi-profiler/pom.xml Tue Sep 15 14:52:13 
2009
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<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/maven-v4_0_0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>6</version>
+        <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.sling.osgi.event.recorder</artifactId>
+    <packaging>bundle</packaging>
+    <version>0.1-SNAPSHOT</version>
+
+    <name>Apache Sling OSGi events recorder</name>
+    <description>
+        Records OSGi events and displays a simple graph of events times
+        on the Felix Webconsole.
+    </description>
+
+    <scm>
+        
<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/event-recorder</connection>
+        
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/event-recorder</developerConnection>
+        
<url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/event-recorder</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.sling.osgi.event.recorder
+                        </Export-Package>
+                        <Private-Package>
+                            org.apache.sling.osgi.event.recorder.impl.*
+                        </Private-Package>
+                        <DynamicImport-Package>
+                            org.apache.felix.webconsole
+                        </DynamicImport-Package>
+                        <Bundle-Activator>
+                            org.apache.sling.osgi.event.recorder.impl.Activator
+                        </Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <excludePackageNames>
+                        org.apache.sling.osgi.event.recorder.impl
+                    </excludePackageNames>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.webconsole</artifactId>
+            <version>1.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

Propchange: sling/trunk/contrib/extensions/osgi-profiler/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java?rev=815351&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
 (added)
+++ 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
 Tue Sep 15 14:52:13 2009
@@ -0,0 +1,62 @@
+/*
+ * 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.sling.osgi.event.recorder;
+
+import java.util.Iterator;
+
+/** Record OSGi events and give access to them for display, profiling, etc. */
+public interface OsgiEventsRecorder {
+       
+       public static class RecordedEvent {
+               public RecordedEvent(String entity, String id, String action) {
+                       this.entity = entity;
+                       this.id = id;
+                       this.action = action;
+                       this.timestamp = System.currentTimeMillis();
+               }
+               
+               /** The OSGi "entity" (framework, bundle, service, etc.) 
+                *      that this event refers to */
+               public final String entity;
+
+               /** The entiy ID (bundle symbolic name, etc.) */
+               public final String id;
+               
+               /** What happened to the entity (STARTED, etc) */
+               public final String action;
+               
+               /** Event timestamp (clock time) */
+               public final long timestamp;
+       }
+       
+       /** When the service started */
+       long getStartupTimestamp();
+       
+       /** Timestamp of latest event (used to compute graph scales) */
+       long getLastTimestamp();
+       
+       /** Clear the list of events and reset startup time */
+       void clear();
+       
+       /** True if recording is enabled */
+       boolean isActive();
+
+       /** Return an Iterator on our recorded events */
+       Iterator<RecordedEvent> getEvents();
+}

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java?rev=815351&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
 (added)
+++ 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
 Tue Sep 15 14:52:13 2009
@@ -0,0 +1,33 @@
+/*
+ * 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.sling.osgi.event.recorder.impl;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+       public void start(BundleContext ctx) throws Exception {
+               FelixConsolePlugin.initPlugin(ctx);
+       }
+
+       public void stop(BundleContext ctx) throws Exception {
+               FelixConsolePlugin.destroyPlugin();
+       }
+}

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java?rev=815351&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
 (added)
+++ 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
 Tue Sep 15 14:52:13 2009
@@ -0,0 +1,202 @@
+/*
+ * 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.sling.osgi.event.recorder.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.WebConsoleConstants;
+import org.apache.sling.osgi.event.recorder.OsgiEventsRecorder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+/** Display recorded events as a simple graph on the Felix web console */
+...@suppresswarnings("serial")
+public class FelixConsolePlugin extends AbstractWebConsolePlugin {
+
+       public static final String LABEL = "OSGiEventsRecorder";
+       public static final String TITLE = "OSGi Events Recorder";
+       
+       private static FelixConsolePlugin instance;
+       private ServiceRegistration serviceRegistration;
+       private ServiceTracker osgiEventsRecorderTracker;
+       private String lastClearString = "" + System.currentTimeMillis();
+       
+       private static final String S = "overflow:visible; white-space:nowrap; 
text-align:right; padding: 2px; margin: 2px; ";
+       private static Map<String, String> styles = new HashMap<String, 
String>();
+       static {
+               styles.put(OsgiEventsRecorderImpl.ENTITY_BUNDLE, S + 
"background-color:#FFCACD; ");
+               styles.put(OsgiEventsRecorderImpl.ENTITY_FRAMEWORK, S + 
"background-color:#DCDCDC; ");
+               styles.put(OsgiEventsRecorderImpl.ENTITY_CONFIG, S + 
"background-color:#FFD700; ");
+               styles.put(OsgiEventsRecorderImpl.ENTITY_SERVICE, S + 
"background-color:#ADFF2F; ");
+       }
+
+       public void activate(BundleContext ctx) {
+               super.activate(ctx);
+               
+           Dictionary<String, Object> props = new Hashtable<String, Object>();
+           props.put(Constants.SERVICE_DESCRIPTION, "Web Console Plugin to 
display/profile OSGi events");
+           props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+           props.put(Constants.SERVICE_PID, getClass().getName());
+           props.put(WebConsoleConstants.PLUGIN_LABEL, LABEL);
+
+           serviceRegistration = 
ctx.registerService(WebConsoleConstants.SERVICE_NAME, this, props);
+           osgiEventsRecorderTracker = new ServiceTracker(ctx, 
OsgiEventsRecorder.class.getName(), null);
+           osgiEventsRecorderTracker.open();
+       }
+       
+       public void deactivate() {
+           if(serviceRegistration != null) {
+               serviceRegistration.unregister();
+               serviceRegistration = null;
+           }
+           
+           if(osgiEventsRecorderTracker != null) {
+               osgiEventsRecorderTracker.close();
+           }
+               super.deactivate();
+       }
+       
+       public static void initPlugin(BundleContext context) {
+               if (instance == null) {
+                       FelixConsolePlugin tmp = new FelixConsolePlugin();
+                       tmp.activate(context);
+                       instance = tmp;
+               }
+       }
+
+       public static void destroyPlugin() {
+               if (instance != null) {
+                       try {
+                               instance.deactivate();
+                       } finally {
+                               instance = null;
+                       }
+               }
+       }
+
+       @Override
+       public String getLabel() {
+               return LABEL;
+       }
+
+       @Override
+       public String getTitle() {
+               return TITLE;
+       }
+
+       @Override
+       protected void renderContent(HttpServletRequest request, 
HttpServletResponse response) 
+       throws ServletException, IOException {
+               if(osgiEventsRecorderTracker == null) {
+                       throw new ServletException("ServiceTracker not found");
+               }
+               
+               final OsgiEventsRecorder rec = 
(OsgiEventsRecorder)osgiEventsRecorderTracker.getService();
+               if(rec == null) {
+                       throw new ServletException("OsgiEventsRecorder not 
found");
+               }
+               
+               // Use unique numbers to clear, to avoid clearing again if the 
browser is refreshed
+               final String clear = request.getParameter("clear");
+               if(clear != null && !clear.equals(lastClearString)) {
+                       lastClearString = clear;
+                       rec.clear();
+               }
+               
+               final Iterator<OsgiEventsRecorder.RecordedEvent> it = 
rec.getEvents();
+               final PrintWriter w = response.getWriter();
+
+               w.println("<div class='fullwidth'><div class='statusline'>");
+               w.println("This plugin displays a timeline of OSGi events.");
+               w.println("<br/>");
+               w.println("Times in brackets are milliseconds since the first 
event was received.");
+               w.println("<br/>");
+               w.println("To profile system startup, install the recorder 
bundle with start level 1 to have it start early.");
+               w.println("</div></div>");
+               
+               // Compute scale: startTime is 0, lastTimestamp is 100%
+               final long startTime = rec.getStartupTimestamp();
+               final long endTime = rec.getLastTimestamp();
+               final float scale = 100.0f / (endTime - startTime);
+               
+               final String clearURL = "./" + LABEL + "?clear=" + 
System.currentTimeMillis();
+               w.println("<h3>OSGi Events Timeline (<a href='" + clearURL + 
"'>Clear</a>)</h3>");
+               w.println("<div class='fullwidth'>");
+               if(rec.isActive()) {
+                       int count = 0;
+                       while(it.hasNext()) {
+                               count++;
+                               renderEvent(w, it.next(), startTime, scale);
+                       }
+                       w.println("</div>");
+                       w.println("<div class='fullwidth'><div 
class='statusline'>");
+                       w.println(count);
+                       w.println(" OSGi events displayed.");
+                       w.println("</div>");
+               } else {
+                       w.println("<div class='fullwidth'><div 
class='statusline'>");
+                       w.println("OSGi Event Recorder is currently 
<b>disabled</b> by configuration.");
+                       w.println("</div>");
+               }
+       }
+       
+       private void renderEvent(PrintWriter w, 
OsgiEventsRecorder.RecordedEvent e, long start, float scale) {
+               final long msec = e.timestamp - start;
+               
+               // Compute color bar size and make sure the bar is visible
+               int percent = (int)((msec) * scale);
+               percent = Math.max(percent, 2);
+               
+               // Get style according to entity
+               String style = styles.get(e.entity);
+               if(style == null) {
+                       style = "";
+               }
+               
+               w.print("<div style='");
+               w.print(style);
+               w.print("width:");
+               w.print(percent);
+               w.print("%'>");
+               if(e.id != null) {
+                       w.print("<b>");
+                       w.print(e.id);
+                       w.print("</b> ");
+               }
+               w.print(e.entity);
+               w.print(" ");
+               w.print(e.action);
+               w.print(" <b>(");
+               w.print(msec);
+               w.println(")</b></div>");
+       }
+}

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java?rev=815351&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
 (added)
+++ 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
 Tue Sep 15 14:52:13 2009
@@ -0,0 +1,253 @@
+/*
+ * 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.sling.osgi.event.recorder.impl;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sling.osgi.event.recorder.OsgiEventsRecorder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Events recorder service implementation.
+ *  
+ *     @scr.component immediate="true"
+ *     @scr.property name="service.vendor" value="The Apache Software 
Foundation"
+ *     @scr.property name="service.description" value="OSGi events recorder"
+ *     @scr.service
+ */
+public class OsgiEventsRecorderImpl 
+       implements OsgiEventsRecorder, BundleListener, FrameworkListener, 
ServiceListener, ConfigurationListener {
+       
+       private final Logger log = LoggerFactory.getLogger(getClass());
+       private ServiceRegistration configReg;
+       private BundleContext ctx;
+       private long startupTime;
+       private long lastTimestamp;
+       private List<RecordedEvent> events;
+       
+       static final String ENTITY_FRAMEWORK = "Framework";
+       static final String ENTITY_BUNDLE = "Bundle";
+       static final String ENTITY_CONFIG = "Config";
+       static final String ENTITY_SERVICE = "Service";
+       
+    /** @scr.property type="Integer" valueRef="DEFAULT_MAX_EVENTS_RECORDED" */
+    public static final String PROP_MAX_EVENTS_RECORDED = 
"max.events.recorded";
+    public static final int DEFAULT_MAX_EVENTS_RECORDED = 5000;
+    private int maxEvents;
+    
+    /** @scr.property type="Boolean" valueRef="DEFAULT_ACTIVE" */
+    public static final String PROP_ACTIVE = "recorder.active";
+    public static final boolean DEFAULT_ACTIVE = false;
+    private boolean active;
+    
+       public void activate(ComponentContext cc) {
+        Dictionary<?, ?> cfg = cc.getProperties();
+        Object o = cfg.get(PROP_ACTIVE);
+        if(o != null) {
+               active = ((Boolean)o).booleanValue();
+        } else {
+               active = DEFAULT_ACTIVE;
+        }
+        o = cfg.get(PROP_MAX_EVENTS_RECORDED);
+        if(o != null) {
+               maxEvents = ((Integer)o).intValue();
+        } else {
+               maxEvents = DEFAULT_MAX_EVENTS_RECORDED;
+        }
+        
+               if(!active) {
+                       log.info("Recorder deactivated by configuration");
+                       return;
+               }
+               log.info("Activating recorder, a maximum of {} events will be 
recorded", maxEvents);
+               
+               startupTime = System.currentTimeMillis();
+               ctx = cc.getBundleContext();
+               ctx.addBundleListener(this);
+               ctx.addFrameworkListener(this);
+               ctx.addServiceListener(this);
+               configReg = 
ctx.registerService(ConfigurationListener.class.getName(),
+                               this, null);
+               
+               events = new LinkedList<RecordedEvent>();
+
+               log.warn("The OSGi event recorder consumes resources when 
recording events, turn it off if not using it");
+       }
+
+       public void deactivate(ComponentContext cc) {
+               configReg.unregister();
+               ctx.removeServiceListener(this);
+               ctx.removeFrameworkListener(this);
+               ctx.removeBundleListener(this);
+               events = null;
+       }
+       
+       public Iterator<RecordedEvent> getEvents() {
+               if(events == null) {
+                       return new LinkedList<RecordedEvent>().iterator();
+               }
+               return events.iterator();
+       }
+       
+       public void clear() {
+               if(events != null) {
+                       synchronized (events) {
+                               events.clear();
+                               startupTime = System.currentTimeMillis();
+                       }
+               }
+       }
+
+       public long getStartupTimestamp() {
+               return startupTime;
+       }
+       
+       public long getLastTimestamp() {
+               return lastTimestamp;
+       }
+       
+       public boolean isActive() {
+               return active;
+       }
+
+       private void recordEvent(String entity, String id, String action) {
+               final RecordedEvent r = new RecordedEvent(entity, id, action);
+               synchronized (events) {
+                       while(events.size() > maxEvents) {
+                               events.remove(0);
+                       }
+                       // First event resets start time
+                       if(events.size() == 0) {
+                               startupTime = System.currentTimeMillis();
+                       }
+                       events.add(r);
+                       lastTimestamp = r.timestamp;
+               }
+       }
+       
+       public void frameworkEvent(FrameworkEvent e) {
+               if(events != null) {
+                       recordEvent(ENTITY_FRAMEWORK, null, 
getFrameworkEventType(e.getType()));
+               }
+       }
+
+       public void bundleChanged(BundleEvent e) {
+               if(events != null) {
+                       recordEvent(ENTITY_BUNDLE, 
e.getBundle().getSymbolicName(), getBundleEventType(e.getType()));
+               }
+       }
+
+       public void configurationEvent(ConfigurationEvent e) {
+               if(events != null) {
+                       recordEvent(ENTITY_CONFIG, e.getPid(), "CHANGED");
+               }
+       }
+
+       public void serviceChanged(ServiceEvent e) {
+               if(events != null) {
+                       final ServiceReference ref = e.getServiceReference();
+                       final StringBuilder id = new StringBuilder();
+                       final Object pid = ref.getProperty("service.pid");
+                       final Object sid = ref.getProperty("service.id");
+                       if(pid != null) {
+                               id.append(pid.toString());
+                       } else {
+                               final Object o = ref.getProperty("objectClass");
+                               if(o instanceof String []) {
+                                       
id.append(Arrays.asList((String[])o).toString());
+                               } else {
+                                       id.append(o.toString());
+                               }
+                               id.append(" (");
+                               id.append(ref.getBundle().getSymbolicName());
+                               id.append(" bundle)");
+                       }
+                       if(sid != null) {
+                               id.append(" (id=");
+                               id.append(sid);
+                               id.append(")");
+                       }
+                       recordEvent(ENTITY_SERVICE,  id.toString(), 
getServiceEventType(e.getType()));
+               }
+       }
+       
+       private static String getBundleEventType(int t) {
+               if(t == BundleEvent.STARTED) {
+                       return "STARTED";
+               } else if(t == BundleEvent.RESOLVED) {
+                       return "RESOLVED";
+               } else if(t == BundleEvent.STOPPED) {
+                       return "STOPPED";
+               } else if(t == BundleEvent.UNRESOLVED) {
+                       return "UNRESOLVED";
+               } else if(t == BundleEvent.UNINSTALLED) {
+                       return "UNINSTALLED";
+               } else if(t == BundleEvent.INSTALLED) {
+                       return "INSTALLED";
+               } else if(t == BundleEvent.UPDATED) {
+                       return "UPDATED";
+               }
+               return String.valueOf(t);
+       }
+       
+       private static String getFrameworkEventType(int t) {
+               if(t == FrameworkEvent.STARTED) {
+                       return "STARTED";
+               } else if(t == FrameworkEvent.ERROR) {
+                       return "ERROR";
+               } else if(t == FrameworkEvent.INFO) {
+                       return "INFO";
+               } else if(t == FrameworkEvent.PACKAGES_REFRESHED) {
+                       return "PACKAGES_REFRESHED";
+               } else if(t == FrameworkEvent.STARTLEVEL_CHANGED) {
+                       return "STARTLEVEL_CHANGED";
+               } else if(t == FrameworkEvent.WARNING) {
+                       return "WARNING";
+               }
+               return String.valueOf(t);
+       }
+       
+       private static String getServiceEventType(int t) {
+               if(t == ServiceEvent.MODIFIED) {
+                       return "MODIFIED";
+               } else if(t == ServiceEvent.REGISTERED) {
+                       return "REGISTERED";
+               } else if(t == ServiceEvent.UNREGISTERING) {
+                       return "UNREGISTERING";
+               }
+               return String.valueOf(t);
+       }
+
+}
\ No newline at end of file

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=815351&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties
 (added)
+++ 
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties
 Tue Sep 15 14:52:13 2009
@@ -0,0 +1,30 @@
+#
+#  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.
+#
+
+org.apache.sling.osgi.event.recorder.impl.OsgiEventsRecorderImpl.name = Apache 
Sling OSGi Events Recorder
+
+max.events.recorded.name = Max.events recorded
+max.events.recorded.description = The maximum number of events \
+       to record. If more events are received, the oldest ones are \
+       deleted to make room.
+       
+recorder.active.name = Recorder active?
+recorder.active.description = Enable/disable events recording  
+       
+       
\ No newline at end of file

Propchange: 
sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to