You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2009/09/15 16:52:13 UTC

svn commit: r815351 - in /sling/trunk/contrib/extensions/osgi-profiler: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/sling/ src/main/java/org/apache/sling/osgi/ src/main/java/org/apache/sling/os...

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