[jboss-cvs] JBossAS SVN: r84726 - in projects/jboss-osgi/branches/tdiesler: service and 33 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Feb 25 07:05:12 EST 2009


Author: thomas.diesler at jboss.com
Date: 2009-02-25 07:05:12 -0500 (Wed, 25 Feb 2009)
New Revision: 84726

Added:
   projects/jboss-osgi/branches/tdiesler/service/
   projects/jboss-osgi/branches/tdiesler/service/http/
   projects/jboss-osgi/branches/tdiesler/service/http/.classpath
   projects/jboss-osgi/branches/tdiesler/service/http/.project
   projects/jboss-osgi/branches/tdiesler/service/http/.settings/
   projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.eclipse.jdt.core.prefs
   projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.maven.ide.eclipse.prefs
   projects/jboss-osgi/branches/tdiesler/service/http/pom.xml
   projects/jboss-osgi/branches/tdiesler/service/http/src/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/GenericEndpointServlet.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpContextImpl.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpEndpointDeployer.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceActivator.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoader.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoaderMBean.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceException.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceImpl.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContext.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContextMBean.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServlet.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServletMBean.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/NotImplementedException.java
   projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/WebMetaDataFactory.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/.classpath
   projects/jboss-osgi/branches/tdiesler/service/webconsole/.project
   projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.eclipse.jdt.core.prefs
   projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.maven.ide.eclipse.prefs
   projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.felix
   projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.jquery
   projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.json
   projects/jboss-osgi/branches/tdiesler/service/webconsole/NOTICE
   projects/jboss-osgi/branches/tdiesler/service/webconsole/obr.xml
   projects/jboss-osgi/branches/tdiesler/service/webconsole/pom.xml
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Action.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/ConfigurationPrinter.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Render.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseWebConsolePlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerPlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Util.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AbstractScrPlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundleAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/SetStartLevelAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/AssemblyListRender.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/EventAdminServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/LicenseServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/RenderBridge.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/GCAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownAction.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownRender.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/VMStatRender.java
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/metatype/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/asc.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/bg.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/desc.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/down.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_add.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_delete.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_run.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_stop.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/favicon.ico
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/felix_logo.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/left.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/logo.png
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/right.gif
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.css
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/bundles.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/configmanager.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/datatable.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/events.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery-1.2.6.min.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery.tablesorter-2.0.3.min.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.css
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/packages.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.css
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.js
   projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/ui.js
Modified:
   projects/jboss-osgi/branches/tdiesler/pom.xml
Log:
wip

Modified: projects/jboss-osgi/branches/tdiesler/pom.xml
===================================================================
--- projects/jboss-osgi/branches/tdiesler/pom.xml	2009-02-25 11:57:35 UTC (rev 84725)
+++ projects/jboss-osgi/branches/tdiesler/pom.xml	2009-02-25 12:05:12 UTC (rev 84726)
@@ -28,8 +28,8 @@
     <module>microcontainer</module>
     <module>repository</module>
     <module>runtime</module>
+    <module>service</module>
     <!-- 
-    <module>service</module>
     <module>testsuite</module>
     -->
   </modules>
@@ -38,11 +38,14 @@
     <version.felix.framework>1.4.1</version.felix.framework>
     <version.felix.javax.servlet>1.0.0</version.felix.javax.servlet>
     <version.felix.osgi.core>1.2.0</version.felix.osgi.core>
+    <version.jbossas>5.0.0.GA</version.jbossas>
     <version.jboss.aop>2.0.0.SP1</version.jboss.aop>
     <version.jboss.common.core>2.2.10.GA</version.jboss.common.core>
     <version.jboss.deployers>2.0.3.GA</version.jboss.deployers>
+    <version.jboss.jacc>1.1.0.GA</version.jboss.jacc>
     <version.jboss.logging.spi>2.0.5.GA</version.jboss.logging.spi>
     <version.jboss.logging.log4j>2.0.5.GA</version.jboss.logging.log4j>
+    <version.jboss.metadata>1.0.0.CR11</version.jboss.metadata>
     <version.jboss.microcontainer>2.0.2.GA</version.jboss.microcontainer>
     <version.junit>4.4</version.junit>
     <version.log4j>1.2.14</version.log4j>
@@ -69,6 +72,21 @@
       </dependency>
       <dependency>
         <groupId>org.jboss.deployers</groupId>
+        <artifactId>jboss-deployers-client</artifactId>
+        <version>${version.jboss.deployers}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.deployers</groupId>
+        <artifactId>jboss-deployers-client-spi</artifactId>
+        <version>${version.jboss.deployers}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.deployers</groupId>
+        <artifactId>jboss-deployers-structure-spi</artifactId>
+        <version>${version.jboss.deployers}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.deployers</groupId>
         <artifactId>jboss-deployers-vfs-spi</artifactId>
         <version>${version.jboss.deployers}</version>
       </dependency>
@@ -83,6 +101,27 @@
         <version>${version.jboss.common.core}</version>
       </dependency>
       <dependency>
+        <groupId>org.jboss.javaee</groupId>
+        <artifactId>jboss-jacc-api</artifactId>
+        <version>${version.jboss.jacc}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.jbossas</groupId>
+        <artifactId>jboss-as-server</artifactId>
+        <version>${version.jbossas}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.jbossas</groupId>
+        <artifactId>jboss-as-system-jmx</artifactId>
+        <version>${version.jbossas}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jboss.jbossas</groupId>
+        <artifactId>jboss-as-client</artifactId>
+        <version>${version.jbossas}</version>
+        <type>pom</type>
+      </dependency>
+      <dependency>
         <groupId>org.jboss.logging</groupId>
         <artifactId>jboss-logging-spi</artifactId>
         <version>${version.jboss.logging.spi}</version>
@@ -93,11 +132,21 @@
         <version>${version.jboss.logging.log4j}</version>
       </dependency>
       <dependency>
+        <groupId>org.jboss.metadata</groupId>
+        <artifactId>jboss-metadata</artifactId>
+        <version>${version.jboss.metadata}</version>
+      </dependency>
+      <dependency>
         <groupId>org.jboss.aop</groupId>
         <artifactId>jboss-aop</artifactId>
         <version>${version.jboss.aop}</version>
       </dependency>
       <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>${version.junit}</version>
+      </dependency>
+      <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>${version.log4j}</version>
@@ -138,12 +187,6 @@
         <scope>test</scope>
       </dependency>
       <dependency>
-        <groupId>junit</groupId>
-        <artifactId>junit</artifactId>
-        <version>${version.junit}</version>
-        <scope>test</scope>
-      </dependency>
-      <dependency>
         <groupId>org.jboss.deployers</groupId>
         <artifactId>jboss-deployers-impl</artifactId>
         <version>${version.jboss.deployers}</version>


Property changes on: projects/jboss-osgi/branches/tdiesler/service
___________________________________________________________________
Name: svn:mergeinfo
   + 

Added: projects/jboss-osgi/branches/tdiesler/service/http/.classpath
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/.classpath	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/.classpath	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

Added: projects/jboss-osgi/branches/tdiesler/service/http/.project
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/.project	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/.project	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>jboss-osgi-service-http</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.maven.ide.eclipse.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.maven.ide.eclipse.maven2Nature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.eclipse.jdt.core.prefs	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.eclipse.jdt.core.prefs	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,5 @@
+#Thu Jan 29 07:27:04 CET 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.source=1.5

Added: projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.maven.ide.eclipse.prefs
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.maven.ide.eclipse.prefs	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/.settings/org.maven.ide.eclipse.prefs	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,9 @@
+#Tue Feb 17 14:09:38 CET 2009
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1

Added: projects/jboss-osgi/branches/tdiesler/service/http/pom.xml
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/pom.xml	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/pom.xml	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+
+  <name>JBoss OSGi - Service HTTP</name>
+
+  <groupId>org.jboss.osgi</groupId>
+  <artifactId>jboss-osgi-service-http</artifactId>
+  <packaging>bundle</packaging>
+
+  <!-- Parent -->
+  <parent>
+    <groupId>org.jboss.osgi</groupId>
+    <artifactId>jboss-osgi-service</artifactId>
+    <version>1.0.0.Alpha3</version>
+  </parent>
+
+  <!-- Properties -->
+  <properties>
+  </properties>
+
+  <!-- Dependencies -->
+  <dependencies>
+    <dependency>
+      <groupId>org.jboss.osgi</groupId>
+      <artifactId>jboss-osgi-spi</artifactId>
+      <version>${version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.framework</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.deployers</groupId>
+      <artifactId>jboss-deployers-client</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.deployers</groupId>
+      <artifactId>jboss-deployers-client-spi</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.deployers</groupId>
+      <artifactId>jboss-deployers-structure-spi</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.deployers</groupId>
+      <artifactId>jboss-deployers-vfs-spi</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.javaee</groupId>
+      <artifactId>jboss-jacc-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.jbossas</groupId>
+      <artifactId>jboss-as-server</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.metadata</groupId>
+      <artifactId>jboss-metadata</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>org.jboss.osgi.service.http</Bundle-SymbolicName>
+            <Bundle-Activator>org.jboss.osgi.service.http.HttpServiceActivator</Bundle-Activator>
+            <Private-Package>org.jboss.osgi.service.http</Private-Package>
+            <Import-Package>
+               javax.servlet,
+               javax.servlet.http,
+               javax.management, 
+               javax.security.jacc,
+               org.jboss.classloading.spi, 
+               org.jboss.deployers.client.plugins.deployment, 
+               org.jboss.deployers.client.spi, 
+               org.jboss.deployers.spi.attachments, 
+               org.jboss.deployers.spi.structure, 
+               org.jboss.deployers.structure.spi, 
+               org.jboss.metadata.javaee.spec, 
+               org.jboss.metadata.javaee.support, 
+               org.jboss.metadata.web.jboss, 
+               org.jboss.metadata.web.spec, 
+               org.jboss.mx.util, 
+               org.jboss.osgi.service, 
+               org.jboss.osgi.spi, 
+               org.jboss.osgi.spi.framework, 
+               org.jboss.osgi.spi.jmx, 
+               org.jboss.virtual, 
+               org.jboss.web, 
+               org.osgi.framework,
+               org.osgi.service.http,
+               org.osgi.util.tracker
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/GenericEndpointServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/GenericEndpointServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/GenericEndpointServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jboss.mx.util.MBeanProxy;
+import org.jboss.mx.util.MBeanProxyCreationException;
+import org.jboss.osgi.service.MicrocontainerService;
+import org.jboss.osgi.spi.framework.OSGiConfiguration;
+import org.jboss.osgi.spi.framework.OSGiFramework;
+import org.jboss.osgi.spi.jmx.ObjectNameFactory;
+import org.jboss.virtual.VFSUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A generic servlet that handles http service requests
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 05-Feb-2009
+ */
+ at SuppressWarnings("serial")
+public class GenericEndpointServlet extends HttpServlet
+{
+  private ObjectName httpContextName;
+  private ObjectName httpServletName;
+  private ManagedHttpContextMBean httpContext;
+  private ManagedServletMBean httpServlet;
+  private String resourceLocation;
+
+  @Override
+  public void init(ServletConfig config) throws ServletException
+  {
+    super.init(config);
+
+    // Get the MBeanServer
+    OSGiFramework framework = OSGiConfiguration.getFramework();
+    BundleContext context = framework.getSystemBundleContext();
+    ServiceReference sref = context.getServiceReference(MicrocontainerService.class.getName());
+    MicrocontainerService service = (MicrocontainerService)context.getService(sref);
+    MBeanServer server = service.getMbeanServer();
+
+    try
+    {
+      // Get the HttpContext, which must alway be there
+      httpContextName = ObjectNameFactory.create(getInitParameter(HttpEndpointDeployer.INIT_PARAM_HTTP_CONTEXT_NAME));
+      httpContext = (ManagedHttpContextMBean)MBeanProxy.get(ManagedHttpContextMBean.class, httpContextName, server);
+      
+      // Get the HttpSerlet, which must be there for a registered servlet
+      String servletName = getInitParameter(HttpEndpointDeployer.INIT_PARAM_SERVLET_NAME);
+      if (servletName != null)
+      {
+        httpServletName = ObjectNameFactory.create(servletName);
+        httpServlet = (ManagedServletMBean)MBeanProxy.get(ManagedServletMBean.class, httpServletName, server);
+        httpServlet.init(config);
+      }
+      
+      // Get the resource location, which must be there for a registered resources
+      resourceLocation = getInitParameter(HttpEndpointDeployer.INIT_PARAM_RESOURCE_LOCATION);
+    }
+    catch (MBeanProxyCreationException ex)
+    {
+      throw new ServletException("Cannot obtain MBeanProxy", ex);
+    }
+  }
+
+  @Override
+  protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
+  {
+    // Handle a service request to a registered servlet
+    if (httpServlet != null)
+    {
+      httpServlet.service(req, res);
+    }
+    
+    // Handle a service request to a registered resource
+    else 
+    {
+      String resourcePath = resourceLocation + req.getPathInfo();
+
+      URL resourceUrl = httpContext.getResource(resourcePath);
+      if (resourceUrl != null)
+      {
+        String mimeType = httpContext.getMimeType(resourcePath);
+        if (mimeType != null)
+          res.setContentType(mimeType);
+
+        ServletOutputStream outStream = res.getOutputStream();
+        InputStream inStream = resourceUrl.openStream();
+        VFSUtils.copyStream(inStream, outStream);
+        outStream.close();
+        inStream.close();
+      }
+      else
+      {
+        res.sendError(HttpServletResponse.SC_NOT_FOUND, resourcePath);
+      }
+    }
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpContextImpl.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpContextImpl.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpContextImpl.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: HttpContextImpl.java 84058 2009-02-10 14:02:01Z thomas.diesler at jboss.com $
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpContext;
+
+/**
+ * An implementation of the HTTPContext
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public class HttpContextImpl implements HttpContext
+{
+  private Bundle bundle;
+  
+  public HttpContextImpl(Bundle bundle)
+  {
+    this.bundle = bundle;
+  }
+
+  public String getMimeType(String name)
+  {
+    if (name == null)
+      throw new IllegalArgumentException("Cannot obtain MimeType for: " + name);
+    
+    String mimeType = null;
+    if (name.endsWith(".jpg") || name.endsWith(".jpeg"))
+    {
+      mimeType = "image/jpeg";
+    }
+    else if (name.endsWith(".gif"))
+    {
+      mimeType = "image/gif";
+    }
+    else if (name.endsWith(".css"))
+    {
+      mimeType = "text/css";
+    }
+    else if (name.endsWith(".txt"))
+    {
+      mimeType = "text/plain";
+    }
+    else if (name.endsWith(".htm") || name.endsWith(".html"))
+    {
+      mimeType = "text/html";
+    }
+    return mimeType;
+  }
+
+  public URL getResource(String name)
+  {
+    return bundle.getResource(name);
+  }
+
+  public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException
+  {
+    return true;
+  }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpEndpointDeployer.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpEndpointDeployer.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpEndpointDeployer.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,274 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.Servlet;
+
+import org.jboss.deployers.client.plugins.deployment.AbstractDeployment;
+import org.jboss.deployers.client.spi.DeployerClient;
+import org.jboss.deployers.client.spi.Deployment;
+import org.jboss.deployers.client.spi.DeploymentFactory;
+import org.jboss.deployers.spi.attachments.MutableAttachments;
+import org.jboss.deployers.structure.spi.ClassLoaderFactory;
+import org.jboss.deployers.structure.spi.DeploymentUnit;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.osgi.service.MicrocontainerService;
+import org.jboss.osgi.spi.jmx.ObjectNameFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Generates a webapp for a HttpService servlet registration
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 26-Jan-2009
+ */
+public class HttpEndpointDeployer
+{
+  static final String INIT_PARAM_RESOURCE_LOCATION = "org.jboss.osgi.service.http.resource.location";
+  static final String INIT_PARAM_HTTP_CONTEXT_NAME = "org.jboss.osgi.service.http.context.name";
+  static final String INIT_PARAM_SERVLET_NAME = "org.jboss.osgi.service.http.servlet.name";
+
+  private DeployerClient mainDeployer;
+  private MBeanServer mbeanServer;
+
+  private DeploymentFactory factory = new DeploymentFactory();
+  private Map<String, Deployment> deployments = new HashMap<String, Deployment>();
+
+  public HttpEndpointDeployer(BundleContext context)
+  {
+    ServiceTracker tracker = new ServiceTracker(context, MicrocontainerService.class.getName(), null)
+    {
+      @Override
+      public Object addingService(ServiceReference reference)
+      {
+        MicrocontainerService mcService = (MicrocontainerService)super.addingService(reference);
+        mainDeployer = (DeployerClient)mcService.getRegisteredBean("MainDeployer");
+        mbeanServer = mcService.getMbeanServer();
+        return mcService;
+      }
+    };
+    tracker.open();
+  }
+
+  @SuppressWarnings("unchecked")
+  public void registerServlet(String alias, ManagedServlet servlet, Dictionary initParams, ManagedHttpContext httpContext)
+  {
+    registerServletInternal(alias, servlet, initParams, httpContext);
+  }
+
+  public void registerResources(String alias, String name, ManagedHttpContext httpContext)
+  {
+    Properties initParams = new Properties();
+    initParams.setProperty(HttpEndpointDeployer.INIT_PARAM_RESOURCE_LOCATION, name);
+    registerServletInternal(alias, null, initParams, httpContext);
+  }
+
+  public void unregister(String alias)
+  {
+    assertAlias(alias);
+
+    Deployment deployment = deployments.remove(alias);
+    if (deployment != null)
+    {
+      try
+      {
+        if (mainDeployer != null)
+          mainDeployer.undeploy(deployment);
+
+        MutableAttachments mutableAttachments = (MutableAttachments)deployment.getPredeterminedManagedObjects();
+        unregisterManagedObject(mutableAttachments.getAttachment(INIT_PARAM_HTTP_CONTEXT_NAME, ObjectName.class));
+        unregisterManagedObject(mutableAttachments.getAttachment(INIT_PARAM_SERVLET_NAME, ObjectName.class));
+        unregisterManagedObject(mutableAttachments.getAttachment(HttpServiceClassLoader.class.getName(), ObjectName.class));
+      }
+      catch (Exception ex)
+      {
+        throw new IllegalStateException("Cannot undeploy webapp: " + alias, ex);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void registerServletInternal(String alias, ManagedServlet servlet, Dictionary initParams, ManagedHttpContext httpContext)
+  {
+    assertAlias(alias);
+
+    if (initParams == null)
+      initParams = new Properties();
+
+    ObjectName contextName = null;
+    ObjectName loaderName = null;
+    ObjectName servletName = null;
+    try
+    {
+      contextName = registerHttpContext(alias, httpContext);
+      initParams.put(INIT_PARAM_HTTP_CONTEXT_NAME, contextName.getCanonicalName());
+
+      HttpServiceClassLoader classLoader = null;
+      if (servlet != null)
+      {
+        ClassLoader osgiLoader = servlet.getClassLoader();
+        classLoader = createHttpServiceClassLoader(osgiLoader);
+        loaderName = registerClassLoader(alias, classLoader);
+        
+        servletName = registerServlet(alias, servlet);
+        initParams.put(INIT_PARAM_SERVLET_NAME, servletName.getCanonicalName());
+      }
+
+      // Add the registered objects to the deployment, so that they can be unregistered again
+      Deployment deployment = deployWebApp(alias, new GenericEndpointServlet(), initParams, classLoader);
+      MutableAttachments mutableAttachments = (MutableAttachments)deployment.getPredeterminedManagedObjects();
+      mutableAttachments.addAttachment(INIT_PARAM_HTTP_CONTEXT_NAME, contextName, ObjectName.class);
+      
+      if (servlet != null)
+      {
+        mutableAttachments.addAttachment(INIT_PARAM_SERVLET_NAME, servletName, ObjectName.class);
+      }
+    }
+    catch (RuntimeException rte)
+    {
+      unregisterManagedObject(contextName);
+      unregisterManagedObject(loaderName);
+      unregisterManagedObject(servletName);
+      throw rte;
+    }
+    catch (Exception ex)
+    {
+      unregisterManagedObject(contextName);
+      unregisterManagedObject(loaderName);
+      unregisterManagedObject(servletName);
+      throw new IllegalStateException("Cannot deploy webapp: " + alias, ex);
+    }
+  }
+
+  private ObjectName registerServlet(String alias, ManagedServlet managedServlet) throws Exception
+  {
+    ObjectName objectName = ObjectNameFactory.create("jboss.osgi:service=http,object=servlet,alias=" + alias);
+    mbeanServer.registerMBean(managedServlet, objectName);
+    return objectName;
+  }
+
+  private ObjectName registerHttpContext(String alias, ManagedHttpContext managedContext) throws Exception
+  {
+    ObjectName objectName = ObjectNameFactory.create("jboss.osgi:service=http,object=httpcontext,alias=" + alias);
+    mbeanServer.registerMBean(managedContext, objectName);
+    return objectName;
+  }
+
+  private ObjectName registerClassLoader(String alias, HttpServiceClassLoader classLoader) throws Exception
+  {
+    ObjectName objectName = ObjectNameFactory.create("jboss.osgi:service=http,object=classloader,alias=" + alias);
+    mbeanServer.registerMBean(classLoader, objectName);
+    classLoader.setObjectName(objectName);
+    return objectName;
+  }
+
+  @SuppressWarnings("unchecked")
+  private Deployment deployWebApp(String alias, Servlet servlet, Dictionary initParams, HttpServiceClassLoader classLoader) throws Exception
+  {
+    WebMetaDataFactory metaDatafactory = new WebMetaDataFactory();
+    JBossWebMetaData jbwmd = metaDatafactory.generateWebMetaData(alias, servlet, initParams);
+
+    String contextRoot = jbwmd.getContextRoot();
+
+    Deployment deployment = deployments.get(contextRoot);
+    if (deployment != null)
+      throw new IllegalStateException("HttpService alias already deployed: " + contextRoot);
+
+    String depName = "http://osgi-http-service" + contextRoot;
+    deployment = new AbstractDeployment(depName);
+    factory.addContext(deployment, "");
+
+    metaDatafactory.generateJACCPermissions(depName, jbwmd);
+
+    MutableAttachments mutableAttachments = (MutableAttachments)deployment.getPredeterminedManagedObjects();
+    mutableAttachments.addAttachment("org.jboss.web.explicitDocBase", "/", String.class);
+    mutableAttachments.addAttachment(JBossWebMetaData.class, jbwmd);
+    
+    if (classLoader != null)
+    {
+      mutableAttachments.addAttachment(ClassLoaderFactory.class, new ContextClassLoaderFactory(classLoader));
+      mutableAttachments.addAttachment(HttpServiceClassLoader.class.getName(), classLoader.getObjectName(), ObjectName.class);
+    }
+
+    mainDeployer.deploy(deployment);
+
+    deployments.put(contextRoot, deployment);
+    return deployment;
+  }
+
+  private HttpServiceClassLoader createHttpServiceClassLoader(ClassLoader osgiLoader) throws Exception
+  {
+    ClassLoader kernelLoader = mainDeployer.getClass().getClassLoader();
+    HttpServiceClassLoader classLoader = new HttpServiceClassLoader(kernelLoader, osgiLoader);
+    return classLoader;
+  }
+
+  private void unregisterManagedObject(ObjectName objectName)
+  {
+    if (objectName != null && mbeanServer != null && mbeanServer.isRegistered(objectName))
+    {
+      try
+      {
+        mbeanServer.unregisterMBean(objectName);
+      }
+      catch (Exception ex)
+      {
+        // ignore;
+      }
+    }
+  }
+
+  private void assertAlias(String alias)
+  {
+    if (alias.equals("/") == false && (alias.startsWith("/") == false || alias.endsWith("/")))
+      throw new IllegalArgumentException("An alias must begin with slash ('/') and must not end with slash ('/')");
+  }
+
+  private static class ContextClassLoaderFactory implements ClassLoaderFactory
+  {
+    private ClassLoader classLoader;
+
+    public ContextClassLoaderFactory(ClassLoader classLoader)
+    {
+      this.classLoader = classLoader;
+    }
+
+    public ClassLoader createClassLoader(DeploymentUnit unit) throws Exception
+    {
+      return classLoader;
+    }
+
+    public void removeClassLoader(DeploymentUnit unit) throws Exception
+    {
+      classLoader = null;
+    }
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceActivator.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceActivator.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceActivator.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,70 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: HttpServiceActivator.java 84058 2009-02-10 14:02:01Z thomas.diesler at jboss.com $
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpService;
+
+/**
+ * An HTTPService Activator
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public class HttpServiceActivator implements BundleActivator
+{
+  /*
+   * Implements BundleActivator.start(). 
+   * Registers an instance of a HTTP Service using the bundle context.
+   */
+  public void start(BundleContext context)
+  {
+    context.registerService(HttpService.class.getName(), new HttpContextServiceFactory(), null);
+  }
+
+  /*
+   * Implements BundleActivator.stop(). 
+   * Does nothing since the framework will automatically unregister any registered services.
+   */
+  public void stop(BundleContext context)
+  {
+    // NOTE: The service is automatically unregistered.
+  }
+  
+  static class HttpContextServiceFactory implements ServiceFactory
+  {
+    public Object getService(Bundle bundle, ServiceRegistration reg)
+    {
+      return new HttpServiceImpl(bundle);
+    }
+
+    public void ungetService(Bundle bundle, ServiceRegistration reg, Object service)
+    {
+    }
+  }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoader.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoader.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoader.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,104 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import java.net.URL;
+import java.security.SecureClassLoader;
+
+import javax.management.ObjectName;
+
+
+/**
+ * A ClassLoader that implements RealClassLoader and delegates to 
+ * the JBoss system classloader when a class cannot be found in the 
+ * OSGi class loader.
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 29-Jan-2009
+ */
+public class HttpServiceClassLoader extends SecureClassLoader implements HttpServiceClassLoaderMBean
+{
+  private ClassLoader osgiLoader;
+  private ObjectName objectName;
+
+  public HttpServiceClassLoader(ClassLoader kernelLoader, ClassLoader osgiLoader)
+  {
+    super(kernelLoader);
+    this.osgiLoader = osgiLoader;
+  }
+
+  public ObjectName getObjectName()
+  {
+    return objectName;
+  }
+
+  public void setObjectName(ObjectName objectName)
+  {
+    this.objectName = objectName;
+  }
+
+  @Override
+  public Class<?> loadClass(String name) throws ClassNotFoundException
+  {
+    Class<?> clazz;
+    try
+    {
+      clazz = osgiLoader.loadClass(name);
+    }
+    catch (ClassNotFoundException ex)
+    {
+      clazz = super.loadClass(name);
+    }
+    return clazz;
+  }
+
+  @Override
+  public URL getResource(String name)
+  {
+    URL resUrl = osgiLoader.getResource(name);
+    return resUrl;
+  }
+
+  public void clearBlackList(String name)
+  {
+  }
+
+  public Class<?> getCachedClass(String name)
+  {
+    return null;
+  }
+
+  public URL getCachedResource(String name)
+  {
+    return null;
+  }
+
+  public boolean isValid()
+  {
+    return true;
+  }
+
+  public URL getResourceLocally(String name)
+  {
+    return null;
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoaderMBean.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoaderMBean.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceClassLoaderMBean.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import org.jboss.classloading.spi.RealClassLoader;
+
+/**
+ * The associated MBean interface 
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 29-Jan-2009
+ */
+public interface HttpServiceClassLoaderMBean extends RealClassLoader
+{
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceException.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceException.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceException.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+// $Id: HttpServiceException.java 84058 2009-02-10 14:02:01Z thomas.diesler at jboss.com $
+
+/**
+ * A RuntimeException that should be thrown for unrecoverable HttpService errors
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 26-Jan-2009
+ */
+ at SuppressWarnings("serial")
+public class HttpServiceException extends RuntimeException
+{
+  public HttpServiceException(String message)
+  {
+    super(message);
+  }
+  
+  public HttpServiceException(String message, Exception cause)
+  {
+    super(message, cause);
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceImpl.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceImpl.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/HttpServiceImpl.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: HttpServiceImpl.java 84123 2009-02-12 13:51:34Z thomas.diesler at jboss.com $
+
+import java.util.Dictionary;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+/**
+ * An implementation of the HTTP Service Specification
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public class HttpServiceImpl implements HttpService
+{
+  private Bundle bundle;
+  private HttpEndpointDeployer webappDeployer;
+
+  public HttpServiceImpl(Bundle bundle)
+  {
+    this.bundle = bundle;
+    this.webappDeployer = new HttpEndpointDeployer(bundle.getBundleContext());
+  }
+
+  public HttpContext createDefaultHttpContext()
+  {
+    return new HttpContextImpl(bundle);
+  }
+
+  @SuppressWarnings("unchecked")
+  public void registerServlet(String alias, Servlet servlet, Dictionary initParams, HttpContext httpContext) throws ServletException, NamespaceException
+  {
+    if (httpContext == null)
+      httpContext = createDefaultHttpContext();
+    
+      webappDeployer.registerServlet(alias, new ManagedServlet(servlet), initParams, new ManagedHttpContext(httpContext));
+  }
+
+  public void registerResources(String alias, String name, HttpContext httpContext) throws NamespaceException
+  {
+    if (httpContext == null)
+      httpContext = createDefaultHttpContext();
+    
+      webappDeployer.registerResources(alias, name, new ManagedHttpContext(httpContext));
+  }
+
+  public void unregister(String alias)
+  {
+    webappDeployer.unregister(alias);
+  }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContext.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContext.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContext.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: ManagedHttpContext.java 84123 2009-02-12 13:51:34Z thomas.diesler at jboss.com $
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.service.http.HttpContext;
+
+/**
+ * An HTTPContext that can be registered with the MBeanServer
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public class ManagedHttpContext implements ManagedHttpContextMBean
+{
+  private HttpContext httpContext;
+
+  public ManagedHttpContext(Object delegate)
+  {
+    this.httpContext = (HttpContext)delegate;
+  }
+
+  public String getMimeType(String name)
+  {
+    return httpContext.getMimeType(name);
+  }
+
+  public URL getResource(String name)
+  {
+    return httpContext.getResource(name);
+  }
+
+  public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException
+  {
+    return httpContext.handleSecurity(req, res);
+  }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContextMBean.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContextMBean.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedHttpContextMBean.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * An MBean interface for the HttpContext
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 06-Feb-2009
+ */
+public interface ManagedHttpContextMBean
+{
+  String getMimeType(String name);
+
+  URL getResource(String name);
+
+  boolean handleSecurity(HttpServletRequest req, HttpServletResponse res) throws IOException;
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: ManagedServlet.java 84123 2009-02-12 13:51:34Z thomas.diesler at jboss.com $
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ * A Servlet that can be registered with the MBeanServer
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public class ManagedServlet implements ManagedServletMBean
+{
+  private Servlet delegate;
+  private ClassLoader classLoader;
+
+  public ManagedServlet(Servlet delegate)
+  {
+    this.delegate = delegate;
+    this.classLoader = delegate.getClass().getClassLoader();
+  }
+
+  public ClassLoader getClassLoader()
+  {
+    return classLoader;
+  }
+
+  public void destroy()
+  {
+    delegate.destroy();
+  }
+
+  public ServletConfig getServletConfig()
+  {
+    return delegate.getServletConfig();
+  }
+
+  public String getServletInfo()
+  {
+    return delegate.getServletInfo();
+  }
+
+  public void init(ServletConfig config) throws ServletException
+  {
+    delegate.init(config);
+  }
+
+  public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
+  {
+    delegate.service(req, res);
+  }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServletMBean.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServletMBean.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/ManagedServletMBean.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,37 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+//$Id: ManagedServletMBean.java 84123 2009-02-12 13:51:34Z thomas.diesler at jboss.com $
+
+import javax.servlet.Servlet;
+
+/**
+ * A Servlet that can be registered with the MBeanServer
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 23-Jan-2009
+ */
+public interface ManagedServletMBean extends Servlet
+{
+  ClassLoader getClassLoader();
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/NotImplementedException.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/NotImplementedException.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/NotImplementedException.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+// $Id: NotImplementedException.java 84058 2009-02-10 14:02:01Z thomas.diesler at jboss.com $
+
+/**
+ * A RuntimeException that should be thrown for unimplemented features
+ * 
+ * @author thomas.diesler at jboss.com
+ * @since 18-Jun-2008
+ */
+ at SuppressWarnings("serial")
+public class NotImplementedException extends RuntimeException
+{
+  public NotImplementedException()
+  {
+  }
+  
+  public NotImplementedException(String message)
+  {
+    super(message);
+  }
+  
+  public NotImplementedException(String jiraIssue, String message)
+  {
+    super("[" + jiraIssue + "] " + message);
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/WebMetaDataFactory.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/WebMetaDataFactory.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/http/src/main/java/org/jboss/osgi/service/http/WebMetaDataFactory.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,129 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.osgi.service.http;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.security.jacc.PolicyConfiguration;
+import javax.security.jacc.PolicyConfigurationFactory;
+import javax.security.jacc.PolicyContextException;
+import javax.servlet.Servlet;
+
+import org.jboss.metadata.javaee.spec.ParamValueMetaData;
+import org.jboss.metadata.web.jboss.JBossServletMetaData;
+import org.jboss.metadata.web.jboss.JBossServletsMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.spec.ServletMappingMetaData;
+import org.jboss.web.WebPermissionMapping;
+
+/**
+ * Generates a webapp for a HttpService servlet registration
+ * 
+ * @author Thomas.Diesler at jboss.org
+ * @since 26-Jan-2009
+ */
+public class WebMetaDataFactory
+{
+  @SuppressWarnings("unchecked")
+  public JBossWebMetaData generateWebMetaData(String alias, Servlet servletImpl, Dictionary initParams)
+  {
+    String servletClass = servletImpl.getClass().getName();
+    String servletName = servletClass;
+
+    JBossWebMetaData jbwmd = new JBossWebMetaData();
+    jbwmd.setContextRoot(alias);
+
+    /*
+     * <servlet> 
+     *  <servlet-name> 
+     *  <servlet-class> 
+     * </servlet>
+     */
+    JBossServletsMetaData servlets = jbwmd.getServlets();
+    JBossServletMetaData servlet = new JBossServletMetaData();
+    servlet.setServletName(servletName);
+    servlet.setServletClass(servletClass);
+    servlets.add(servlet);
+
+    /*
+     * <init-param>
+     *  <param-name>
+     *  <param-value>
+     * </init-param>
+     */
+    if (initParams != null)
+    {
+      List<ParamValueMetaData> servletParams = servlet.getInitParam();
+      if (servletParams == null)
+      {
+        servletParams = new ArrayList<ParamValueMetaData>();
+        servlet.setInitParam(servletParams);
+      }
+      Enumeration en = initParams.keys();
+      while (en.hasMoreElements())
+      {
+        String name = (String)en.nextElement();
+        String value = (String)initParams.get(name);
+        ParamValueMetaData param = new ParamValueMetaData();
+        param.setParamName(name);
+        param.setParamValue(value);
+        servletParams.add(param);
+      }
+    }
+
+    /*
+     * <servlet-mapping> 
+     *  <servlet-name> 
+     *  <url-pattern> 
+     * </servlet-mapping>
+     */
+    List<ServletMappingMetaData> servletMappings = jbwmd.getServletMappings();
+    if (servletMappings == null)
+    {
+      servletMappings = new ArrayList<ServletMappingMetaData>();
+      jbwmd.setServletMappings(servletMappings);
+    }
+    ServletMappingMetaData servletMapping = new ServletMappingMetaData();
+    servletMapping.setServletName(servletName);
+    servletMapping.setUrlPatterns(Arrays.asList(new String[] { "/*" }));
+    servletMappings.add(servletMapping);
+
+    return jbwmd;
+  }
+
+  /**
+   * JBAS-5935: The dynamic web application does not go through the war security deployer. 
+   * Hence the JACC permissions are not created. There is a need to explicitly create
+   * the war jacc permissions.
+   */
+  public void generateJACCPermissions(String depName, JBossWebMetaData jbwmd) throws ClassNotFoundException, PolicyContextException
+  {
+    PolicyConfigurationFactory policyConfigurationFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
+    PolicyConfiguration policyConfiguration = policyConfigurationFactory.getPolicyConfiguration(depName, false);
+    WebPermissionMapping.createPermissions(jbwmd, policyConfiguration);
+    policyConfiguration.commit();
+  }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/.classpath
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/.classpath	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/.classpath	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/.project
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/.project	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/.project	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.felix.webconsole</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.maven.ide.eclipse.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.maven.ide.eclipse.maven2Nature</nature>
+	</natures>
+</projectDescription>

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.eclipse.jdt.core.prefs	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.eclipse.jdt.core.prefs	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,5 @@
+#Fri Feb 13 10:13:14 CET 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.source=1.5

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.maven.ide.eclipse.prefs
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.maven.ide.eclipse.prefs	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/.settings/org.maven.ide.eclipse.prefs	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,9 @@
+#Tue Feb 17 14:09:38 CET 2009
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.felix
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.felix	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.felix	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.jquery
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.jquery	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.jquery	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,20 @@
+Copyright (c) 2008 John Resig, http://jquery.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.json
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.json	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/LICENSE.json	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,21 @@
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/NOTICE
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/NOTICE	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/NOTICE	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,33 @@
+Apache Felix OSGi Web Console
+Copyright 2007-2008 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright 2006 The OSGi Alliance.
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+This product includes software from http://www.jquery.com
+Licensed under the MIT License
+
+II. Used Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright 2006 The OSGi Alliance.
+Licensed under the Apache License 2.0.
+
+
+III. License Summary
+- Apache License 2.0
+- JSON License
+- MIT License
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/obr.xml
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/obr.xml	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/obr.xml	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,54 @@
+<?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.
+-->
+<obr>
+    <require extend="false"
+        filter="(service=org.osgi.service.log.LogService)"
+        multiple="false" name="service" optional="true">
+        Import Service org.osgi.service.log.LogService
+    </require>
+    <require extend="false"
+        filter="(service=javax.servlet.Servlet)"
+        multiple="true" name="service" optional="true">
+        Import Service javax.servlet.Servlet
+    </require>
+    <require extend="false"
+        filter="(service=org.apache.felix.webconsole.Render)"
+        multiple="true" name="service" optional="true">
+        Import Service org.apache.felix.webconsole.Render
+    </require>
+    <require extend="false"
+        filter="(service=org.apache.felix.webconsole.Action)"
+        multiple="true" name="service" optional="true">
+        Import Service org.apache.felix.webconsole.Action
+    </require>
+    <require extend="false"
+        filter="(service=org.osgi.service.http.HttpService)"
+        multiple="false" name="service" optional="false">
+        Import Service org.osgi.service.http.HttpService
+    </require>
+    <capability name="service">
+        <p n="service" v="org.osgi.service.cm.ManagedService" />
+        <p n="service.description"
+            v="OSGi Management Console Configuration Receiver" />
+        <p n="service.pid"
+            v="org.apache.felix.webconsole.internal.servlet.OsgiManager" />
+        <p n="service.vendor" v="he Apache Software Foundation" />
+    </capability>
+</obr>

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/pom.xml
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/pom.xml	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/pom.xml	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,144 @@
+<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>
+
+  <name>JBoss OSGi - Service Web Console</name>
+  <description>JBoss OSGi - Web Console Service</description>
+
+  <groupId>org.jboss.osgi</groupId>
+  <artifactId>jboss-osgi-webconsole</artifactId>
+  <packaging>bundle</packaging>
+
+  <parent>
+    <groupId>org.jboss.osgi</groupId>
+    <artifactId>jboss-osgi</artifactId>
+    <version>1.0.0.Alpha3</version>
+  </parent>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <showDeprecation>false</showDeprecation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-scr-plugin</artifactId>
+        <version>1.0.6</version>
+        <executions>
+          <execution>
+            <id>generate-scr-scrdescriptor</id>
+            <goals>
+              <goal>scr</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.4.3</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>${artifactId}</Bundle-SymbolicName>
+            <Bundle-Vendor>JBoss, a division of RedHat</Bundle-Vendor>
+            <Bundle-Activator>org.apache.felix.webconsole.internal.OsgiManagerActivator</Bundle-Activator>
+            <Export-Package>
+              org.apache.felix.webconsole,
+              org.osgi.service.obr
+            </Export-Package>
+            <Private-Package>
+              !org.apache.felix.webconsole,
+              org.apache.felix.webconsole.*,
+
+              <!-- File Upload functionality -->
+              org.apache.commons.fileupload,
+              org.apache.commons.fileupload.disk,
+              org.apache.commons.fileupload.servlet,
+
+              <!-- Required by FileUpload and Util -->
+              org.apache.commons.io,
+              org.apache.commons.io.filefilter,
+              org.apache.commons.io.output
+            </Private-Package>
+            <Import-Package>
+              org.apache.felix.scr;
+              org.apache.felix.shell;
+              org.osgi.service.*;resolution:=optional,*
+            </Import-Package>
+            <Embed-Dependency>
+              <!-- Import/Export-Package parsing, OBR -->
+              org.apache.felix.bundlerepository,
+              
+              <!-- Required for JSON data transfer -->
+              json
+            </Embed-Dependency>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.4</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <!-- This adds commons-io transitively -->
+    <dependency>
+      <groupId>commons-fileupload</groupId>
+      <artifactId>commons-fileupload</artifactId>
+      <version>1.1.1</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>1.0.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>1.2.0</version>
+      <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>javax.servlet</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+      <version>20070829</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr</artifactId>
+      <version>1.0.0</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.bundlerepository</artifactId>
+      <version>1.0.3</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+
+  </dependencies>
+</project>

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,313 @@
+/*
+ * 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.felix.webconsole;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.MessageFormat;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.servlet.ServletRequestContext;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+
+public abstract class AbstractWebConsolePlugin extends HttpServlet
+{
+
+    /** Pseudo class version ID to keep the IDE quite. */
+    private static final long serialVersionUID = 1L;
+
+    /** The name of the request attribute containig the map of FileItems from the POST request */
+    public static final String ATTR_FILEUPLOAD = "org.apache.felix.webconsole.fileupload";
+
+    private static final String HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+        + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"xhtml1-transitional.dtd\">"
+        + "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+        + "<head>"
+        + "<meta http-equiv=\"Content-Type\" content=\"text/html; utf-8\">"
+        + "<link rel=\"icon\" href=\"{6}/res/imgs/favicon.ico\">"
+        + "<title>{0} - {2}</title>"
+        + "<script src=\"{5}/res/ui/admin.js\" language=\"JavaScript\"></script>"
+        + "<script src=\"{5}/res/ui/ui.js\" language=\"JavaScript\"></script>"
+        + "<script language=\"JavaScript\">"
+        + "appRoot = \"{5}\";"
+        + "pluginRoot = appRoot + \"/{6}\";"
+        + "</script>"
+        + "<link href=\"{5}/res/ui/admin.css\" rel=\"stylesheet\" type=\"text/css\">"
+        + "</head>"
+        + "<body>"
+        + "<div id=\"main\">"
+        + "<div id=\"lead\">"
+        + "<h1>"
+        + "{0}<br>{2}"
+        + "</h1>"
+        + "<p>"
+        + "<a target=\"_blank\" href=\"{3}\" title=\"{1}\"><img src=\"{5}/res/imgs/logo.png\" width=\"123\" height=\"103\" border=\"0\"></a>"
+        + "</p>" + "</div>";
+
+    /**
+    String header = MessageFormat.format( HEADER, new Object[]
+         { adminTitle, productName, getTitle(), productWeb, vendorName,
+                 ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT ), getLabel() } );
+    */
+    private BundleContext bundleContext;
+
+    private String adminTitle;
+    private String productName;
+    private String productWeb;
+    private String vendorName;
+
+
+    //---------- HttpServlet Overwrites ----------------------------------------
+
+    /**
+     * Returns the title for this plugin as returned by {@link #getTitle()}
+     */
+    public String getServletName()
+    {
+        return getTitle();
+    }
+
+
+    /**
+     * Renders the web console page for the request. This consist of the following
+     * four parts called in order:
+     * <ol>
+     * <li>{@link #startResponse(HttpServletRequest, HttpServletResponse)}</li>
+     * <li>{@link #renderTopNavigation(HttpServletRequest, PrintWriter)}</li>
+     * <li>{@link #renderContent(HttpServletRequest, HttpServletResponse)}</li>
+     * <li>{@link #endResponse(PrintWriter)}</li>
+     * </ol>
+     */
+    protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+        PrintWriter pw = startResponse( request, response );
+        renderTopNavigation( request, pw );
+        renderContent( request, response );
+        endResponse( request, pw );
+    }
+
+
+    //---------- AbstractWebConsolePlugin API ----------------------------------
+
+    public void activate( BundleContext bundleContext )
+    {
+        this.bundleContext = bundleContext;
+
+        Dictionary headers = bundleContext.getBundle().getHeaders();
+
+        adminTitle = ( String ) headers.get( Constants.BUNDLE_NAME ); // "OSGi Management Console";
+        productName = "Apache Felix";
+        productWeb = ( String ) headers.get( Constants.BUNDLE_DOCURL );
+        vendorName = ( String ) headers.get( Constants.BUNDLE_VENDOR );
+    }
+
+
+    public void deactivate()
+    {
+        this.bundleContext = null;
+    }
+
+
+    public abstract String getTitle();
+
+
+    public abstract String getLabel();
+
+
+    protected abstract void renderContent( HttpServletRequest req, HttpServletResponse res ) throws ServletException,
+        IOException;
+
+
+    protected BundleContext getBundleContext()
+    {
+        return bundleContext;
+    }
+
+
+    protected PrintWriter startResponse( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+        response.setCharacterEncoding( "utf-8" );
+        response.setContentType( "text/html" );
+
+        PrintWriter pw = response.getWriter();
+
+        String header = MessageFormat.format( HEADER, new Object[]
+            { adminTitle, productName, getTitle(), productWeb, vendorName,
+                ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT ), getLabel() } );
+        pw.println( header );
+
+        return pw;
+    }
+
+
+    protected void renderTopNavigation( HttpServletRequest request, PrintWriter pw )
+    {
+        // assume pathInfo to not be null, else this would not be called
+        boolean linkToCurrent = true;
+        String current = request.getPathInfo();
+        int slash = current.indexOf( "/", 1 );
+        if ( slash < 0 )
+        {
+            slash = current.length();
+            linkToCurrent = false;
+        }
+        current = current.substring( 1, slash );
+
+        boolean disabled = false;
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        Map labelMap = ( Map ) request.getAttribute( OsgiManager.ATTR_LABEL_MAP );
+        if ( labelMap != null )
+        {
+            pw.println( "<div id='technav'>" );
+
+            SortedMap map = new TreeMap();
+            for ( Iterator ri = labelMap.entrySet().iterator(); ri.hasNext(); )
+            {
+                Map.Entry labelMapEntry = ( Map.Entry ) ri.next();
+                if ( labelMapEntry.getKey() == null )
+                {
+                    // ignore renders without a label
+                }
+                else if ( disabled || current.equals( labelMapEntry.getKey() ) )
+                {
+                    if ( linkToCurrent )
+                    {
+                        map.put( labelMapEntry.getValue(), "<a class='technavat' href='" + appRoot + "/"
+                            + labelMapEntry.getKey() + "'>" + labelMapEntry.getValue() + "</a>" );
+                    }
+                    else
+                    {
+                        map.put( labelMapEntry.getValue(), "<span class='technavat'>" + labelMapEntry.getValue()
+                            + "</span>" );
+                    }
+                }
+                else
+                {
+                    map.put( labelMapEntry.getValue(), "<a href='" + appRoot + "/" + labelMapEntry.getKey() + "'>"
+                        + labelMapEntry.getValue() + "</a>" );
+                }
+            }
+
+            for ( Iterator li = map.values().iterator(); li.hasNext(); )
+            {
+                pw.print( "<nobr>" );
+                pw.print( li.next() );
+                pw.println( "</nobr>" );
+            }
+
+            pw.println( "</div>" );
+        }
+    }
+
+
+    protected void endResponse( HttpServletRequest request, PrintWriter pw )
+    {
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<img src='" + appRoot + "/res/imgs/felix_logo.png' width='55' height='21' border='0'>&nbsp;<a target='_blank' href='http://felix.apache.org/site/apache-felix-web-console.html'>Apache Felix Web Console</a>" );
+        pw.println( "</body>" );
+        pw.println( "</html>" );
+    }
+
+
+    public static String getParameter( HttpServletRequest request, String name )
+    {
+        // just get the parameter if not a multipart/form-data POST
+        if ( !ServletFileUpload.isMultipartContent( new ServletRequestContext( request ) ) )
+        {
+            return request.getParameter( name );
+        }
+
+        // check, whether we alread have the parameters
+        Map params = ( Map ) request.getAttribute( ATTR_FILEUPLOAD );
+        if ( params == null )
+        {
+            // parameters not read yet, read now
+            // Create a factory for disk-based file items
+            DiskFileItemFactory factory = new DiskFileItemFactory();
+            factory.setSizeThreshold( 256000 );
+
+            // Create a new file upload handler
+            ServletFileUpload upload = new ServletFileUpload( factory );
+            upload.setSizeMax( -1 );
+
+            // Parse the request
+            params = new HashMap();
+            try
+            {
+                List items = upload.parseRequest( request );
+                for ( Iterator fiter = items.iterator(); fiter.hasNext(); )
+                {
+                    FileItem fi = ( FileItem ) fiter.next();
+                    FileItem[] current = ( FileItem[] ) params.get( fi.getFieldName() );
+                    if ( current == null )
+                    {
+                        current = new FileItem[]
+                            { fi };
+                    }
+                    else
+                    {
+                        FileItem[] newCurrent = new FileItem[current.length + 1];
+                        System.arraycopy( current, 0, newCurrent, 0, current.length );
+                        newCurrent[current.length] = fi;
+                        current = newCurrent;
+                    }
+                    params.put( fi.getFieldName(), current );
+                }
+            }
+            catch ( FileUploadException fue )
+            {
+                // TODO: log
+            }
+            request.setAttribute( ATTR_FILEUPLOAD, params );
+        }
+
+        FileItem[] param = ( FileItem[] ) params.get( name );
+        if ( param != null )
+        {
+            for ( int i = 0; i < param.length; i++ )
+            {
+                if ( param[i].isFormField() )
+                {
+                    return param[i].getString();
+                }
+            }
+        }
+
+        // no valid string parameter, fail
+        return null;
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Action.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Action.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Action.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,79 @@
+/*
+ * 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.felix.webconsole;
+
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * The <code>Action</code> interface defines a service interface for actions
+ * to be plugged into the web console.
+ * <p>
+ * <strong>NOTE: This interface is just an intermediate solution for making the
+ * web console extensible. Future releases of the web console will remove this
+ * and the {@link Render} interfaces and use the
+ * <code>javax.servlet.Servlet</code> interface with predefined service
+ * registration properties instead.</strong>
+ * 
+ * @deprecated This interface will be removed when <a
+ *             href="https://issues.apache.org/jira/browse/FELIX-574">FELIX-574</a>
+ *             will be implemented.
+ */
+public interface Action
+{
+
+    static final String SERVICE = Action.class.getName();
+
+    /**
+     * The name of a request attribute, which may be set by performAction if
+     * redirecting.
+     */
+    static final String ATTR_REDIRECT_PARAMETERS = "redirectParameters";
+
+
+    String getName();
+
+
+    String getLabel();
+
+
+    /**
+     * Performs the action the request data optionally sending a response to
+     * the HTTP Servlet Response.
+     *
+     * @param request
+     * @param response
+     *
+     * @return <code>true</code> the client should be redirected after the
+     *      action has been taken. <code>false</code> if this method also
+     *      provided response to the client and nore more processing is
+     *      required.
+     *
+     * @throws IOException May be thrown if an I/O error occurrs
+     * @throws ServletException May be thrown if another error occurrs while
+     *      processing the action. The <code>rootCause</code> of the exception
+     *      should contain the cause of the error.
+     */
+    boolean performAction( HttpServletRequest request, HttpServletResponse response ) throws IOException,
+        ServletException;
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/ConfigurationPrinter.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/ConfigurationPrinter.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/ConfigurationPrinter.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,54 @@
+/*
+ * 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.felix.webconsole;
+
+
+import java.io.PrintWriter;
+
+
+/**
+ * The <code>ConfigurationPrinter</code> is a service interface to be used by
+ * providers which want to hook into the display of the current configuration
+ * of the OSGi framework.
+ */
+public interface ConfigurationPrinter
+{
+
+    /**
+     * The service name under which services of this class must be registered
+     * to be picked for inclusion in the configuration report.
+     */
+    static final String SERVICE = ConfigurationPrinter.class.getName();
+
+
+    /**
+     * Returns a human readable title string to be place in front of the configuration
+     * report generated by the {@link #printConfiguration(PrintWriter)} method.
+     */
+    String getTitle();
+
+
+    /**
+     * Prints the configuration report to the given <code>printWriter</code>.
+     * Implementations are free to print whatever information they deem useful.
+     * The <code>printWriter</code> may be flushed but must not be closed.
+     */
+    void printConfiguration( PrintWriter printWriter );
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Render.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Render.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/Render.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,50 @@
+/*
+ * 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.felix.webconsole;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * The <code>Render</code> interface defines a service interface for
+ * information renderings to be plugged into the web console.
+ * <p>
+ * <strong>NOTE: This interface is just an intermediate solution for making the
+ * web console extensible. Future releases of the web console will remove this
+ * and the {@link Action} interfaces and use the
+ * <code>javax.servlet.Servlet</code> interface with predefined service
+ * registration properties instead.</strong>
+ * 
+ * @deprecated This interface will be removed when <a
+ *             href="https://issues.apache.org/jira/browse/FELIX-574">FELIX-574</a>
+ *             will be implemented.
+ */
+public interface Render {
+
+    static final String SERVICE = Render.class.getName();
+
+    String getName();
+
+    String getLabel();
+
+    void render(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException;
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,41 @@
+/*
+ * 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.felix.webconsole;
+
+
+public interface WebConsoleConstants
+{
+
+    /**
+     * The name of the service to register as to be used as a "plugin" for
+     * the OSGi Manager (value is "javax.servlet.Servlet").
+     */
+    public static final String SERVICE_NAME = "javax.servlet.Servlet";
+
+    /**
+     * The URI address label under which the OSGi Manager plugin is called by
+     * the OSGi Manager (value is "felix.webconsole.label").
+     * <p>
+     * Only {@link #SERVICE_NAME} services with this service registration
+     * property set to a non-empty String values are accepted by the OSGi
+     * Manager as a plugin.
+     */
+    public static final String PLUGIN_LABEL = "felix.webconsole.label";
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,105 @@
+/*
+ * 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.felix.webconsole.internal;
+
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class BaseManagementPlugin implements OsgiManagerPlugin
+{
+
+    private BundleContext bundleContext;
+    private Logger log;
+
+    private ServiceTracker startLevelService;
+
+    private ServiceTracker packageAdmin;
+
+
+    protected BaseManagementPlugin()
+    {
+    }
+
+
+    public void activate( BundleContext bundleContext )
+    {
+        this.bundleContext = bundleContext;
+        this.log = new Logger( bundleContext );
+    }
+
+
+    public void deactivate()
+    {
+        if ( log != null )
+        {
+            log.dispose();
+        }
+
+        if ( startLevelService != null )
+        {
+            startLevelService.close();
+            startLevelService = null;
+        }
+
+        if ( packageAdmin != null )
+        {
+            packageAdmin.close();
+            packageAdmin = null;
+        }
+    }
+
+
+    protected BundleContext getBundleContext()
+    {
+        return bundleContext;
+    }
+
+
+    protected Logger getLog()
+    {
+        return log;
+    }
+
+
+    protected StartLevel getStartLevel()
+    {
+        if ( startLevelService == null )
+        {
+            startLevelService = new ServiceTracker( getBundleContext(), StartLevel.class.getName(), null );
+            startLevelService.open();
+        }
+        return ( StartLevel ) startLevelService.getService();
+    }
+
+
+    protected PackageAdmin getPackageAdmin()
+    {
+        if ( packageAdmin == null )
+        {
+            packageAdmin = new ServiceTracker( getBundleContext(), PackageAdmin.class.getName(), null );
+            packageAdmin.open();
+        }
+        return ( PackageAdmin ) packageAdmin.getService();
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseWebConsolePlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseWebConsolePlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseWebConsolePlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,96 @@
+/*
+ * 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.felix.webconsole.internal;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public abstract class BaseWebConsolePlugin extends AbstractWebConsolePlugin implements OsgiManagerPlugin
+{
+
+    private static String PACKAGE_ADMIN_NAME = PackageAdmin.class.getName();
+    private static String START_LEVEL_NAME = StartLevel.class.getName();
+
+    private Logger log;
+
+    private Map services = new HashMap();
+
+
+    public void deactivate()
+    {
+        for ( Iterator ti = services.values().iterator(); ti.hasNext(); )
+        {
+            ServiceTracker tracker = ( ServiceTracker ) ti.next();
+            tracker.close();
+            ti.remove();
+        }
+
+        if ( log != null )
+        {
+            log.dispose();
+            log = null;
+        }
+    }
+
+
+    protected Logger getLog()
+    {
+        if ( log == null )
+        {
+            log = new Logger( getBundleContext() );
+        }
+
+        return log;
+    }
+
+
+    protected StartLevel getStartLevel()
+    {
+        return ( StartLevel ) getService( START_LEVEL_NAME );
+    }
+
+
+    protected PackageAdmin getPackageAdmin()
+    {
+        return ( PackageAdmin ) getService( PACKAGE_ADMIN_NAME );
+    }
+
+
+    protected Object getService( String serviceName )
+    {
+        ServiceTracker serviceTracker = ( ServiceTracker ) services.get( serviceName );
+        if ( serviceTracker == null )
+        {
+            serviceTracker = new ServiceTracker( getBundleContext(), serviceName, null );
+            serviceTracker.open();
+
+            services.put( serviceName, serviceTracker );
+        }
+
+        return serviceTracker.getService();
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,96 @@
+/*
+ * 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.felix.webconsole.internal;
+
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class Logger
+{
+
+    private ServiceTracker logTracker;
+
+
+    public Logger( BundleContext bundleContext )
+    {
+        logTracker = new ServiceTracker( bundleContext, LogService.class.getName(), null );
+        logTracker.open();
+    }
+
+
+    public void dispose()
+    {
+        if ( logTracker != null )
+        {
+            logTracker.close();
+        }
+    }
+
+
+    public void log( int logLevel, String message )
+    {
+        log( logLevel, message, null );
+    }
+
+
+    public void log( int logLevel, String message, Throwable t )
+    {
+        Object log = logTracker.getService();
+        if ( log != null )
+        {
+            ( ( LogService ) log ).log( logLevel, message, t );
+        }
+        else
+        {
+            String level;
+            switch ( logLevel )
+            {
+                case LogService.LOG_DEBUG:
+                    level = "*DEBUG*";
+                    break;
+                case LogService.LOG_INFO:
+                    level = "*INFO *";
+                    break;
+                case LogService.LOG_WARNING:
+                    level = "*WARN *";
+                    break;
+                case LogService.LOG_ERROR:
+                    level = "*ERROR*";
+                    break;
+                default:
+                    level = "*" + logLevel + "*";
+                    break;
+            }
+
+            if ( message == null && t != null )
+            {
+                message = t.getMessage();
+            }
+
+            System.out.println( level + " " + message );
+            if ( t != null )
+            {
+                t.printStackTrace( System.out );
+            }
+        }
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,47 @@
+/*
+ * 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.felix.webconsole.internal;
+
+
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+
+public class OsgiManagerActivator implements BundleActivator
+{
+
+    private OsgiManager osgiManager;
+
+
+    public void start( BundleContext bundleContext )
+    {
+        osgiManager = new OsgiManager( bundleContext );
+    }
+
+
+    public void stop( BundleContext arg0 )
+    {
+        if ( osgiManager != null )
+        {
+            osgiManager.dispose();
+        }
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerPlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerPlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerPlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -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.felix.webconsole.internal;
+
+
+import org.osgi.framework.BundleContext;
+
+
+public interface OsgiManagerPlugin
+{
+
+    void activate( BundleContext bundleContext );
+
+
+    void deactivate();
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Util.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Util.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/Util.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,195 @@
+/*
+ * 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.felix.webconsole.internal;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+
+/**
+ * The <code>Util</code> TODO
+ */
+public class Util
+{
+
+    /** web apps subpage */
+    public static final String PAGE_WEBAPPS = "/webapps";
+
+    /** vm statistics subpage */
+    public static final String PAGE_VM_STAT = "/vmstat";
+
+    /** Logs subpage */
+    public static final String PAGE_LOGS = "/logs";
+
+    /** Parameter name */
+    public static final String PARAM_ACTION = "action";
+
+    /** Parameter name */
+    public static final String PARAM_CONTENT = "content";
+
+    /** Parameter name */
+    public static final String PARAM_SHUTDOWN = "shutdown";
+
+    /** Parameter value */
+    public static final String VALUE_SHUTDOWN = "shutdown";
+
+
+    public static void startScript( PrintWriter pw )
+    {
+        pw.println( "<script type='text/javascript'>" );
+        pw.println( "// <![CDATA[" );
+    }
+
+
+    public static void endScript( PrintWriter pw )
+    {
+        pw.println( "// ]]>" );
+        pw.println( "</script>" );
+    }
+
+
+    public static void spool( String res, HttpServletResponse resp ) throws IOException
+    {
+        InputStream ins = getResource( res );
+        if ( ins != null )
+        {
+            try
+            {
+                IOUtils.copy( ins, resp.getOutputStream() );
+            }
+            finally
+            {
+                IOUtils.closeQuietly( ins );
+            }
+        }
+    }
+
+
+    private static InputStream getResource( String resource )
+    {
+        return Util.class.getResourceAsStream( resource );
+    }
+
+
+    /**
+     * Return a display name for the given <code>bundle</code>:
+     * <ol>
+     * <li>If the bundle has a non-empty <code>Bundle-Name</code> manifest
+     * header that value is returned.</li>
+     * <li>Otherwise the symbolic name is returned if set</li>
+     * <li>Otherwise the bundle's location is returned if defined</li>
+     * <li>Finally, as a last ressort, the bundles id is returned</li>
+     * </ol>
+     */
+    public static String getName( Bundle bundle )
+    {
+        String name = ( String ) bundle.getHeaders().get( Constants.BUNDLE_NAME );
+        if ( name == null || name.length() == 0 )
+        {
+            name = bundle.getSymbolicName();
+            if ( name == null )
+            {
+                name = bundle.getLocation();
+                if ( name == null )
+                {
+                    name = String.valueOf( bundle.getBundleId() );
+                }
+            }
+        }
+        return name;
+    }
+
+
+    /**
+     * Orders the bundles according to their name as returned by
+     * {@link #getName(Bundle)}, with the exception that the system bundle is
+     * always place as the first entry. If two bundles have the same name, they
+     * are ordered according to their version. If they have the same version,
+     * the bundle with the lower bundle id comes before the other.
+     */
+    public static void sort( Bundle[] bundles )
+    {
+        Arrays.sort( bundles, BUNDLE_NAME_COMPARATOR );
+    }
+
+    // ---------- inner classes ------------------------------------------------
+
+    private static final Comparator BUNDLE_NAME_COMPARATOR = new Comparator()
+    {
+        public int compare( Object o1, Object o2 )
+        {
+            return compare( ( Bundle ) o1, ( Bundle ) o2 );
+        }
+
+
+        public int compare( Bundle b1, Bundle b2 )
+        {
+
+            // the same bundles
+            if ( b1 == b2 || b1.getBundleId() == b2.getBundleId() )
+            {
+                return 0;
+            }
+
+            // special case for system bundle, which always is first
+            if ( b1.getBundleId() == 0 )
+            {
+                return -1;
+            }
+            else if ( b2.getBundleId() == 0 )
+            {
+                return 1;
+            }
+
+            // compare the symbolic names
+            int snComp = Util.getName( b1 ).compareToIgnoreCase( Util.getName( b2 ) );
+            if ( snComp != 0 )
+            {
+                return snComp;
+            }
+
+            // same names, compare versions
+            Version v1 = Version.parseVersion( ( String ) b1.getHeaders().get( Constants.BUNDLE_VERSION ) );
+            Version v2 = Version.parseVersion( ( String ) b2.getHeaders().get( Constants.BUNDLE_VERSION ) );
+            int vComp = v1.compareTo( v2 );
+            if ( vComp != 0 )
+            {
+                return vComp;
+            }
+
+            // same version ? Not really, but then, we compare by bundle id
+            if ( b1.getBundleId() < b2.getBundleId() )
+            {
+                return -1;
+            }
+
+            // b1 id must be > b2 id because equality is already checked
+            return 1;
+        }
+    };
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AbstractScrPlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AbstractScrPlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AbstractScrPlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,52 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import org.apache.felix.scr.ScrService;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class AbstractScrPlugin extends BaseManagementPlugin
+{
+
+    private ServiceTracker scrServiceTracker;
+
+
+    protected ScrService getScrService()
+    {
+        if ( scrServiceTracker == null )
+        {
+            try
+            {
+                scrServiceTracker = new ServiceTracker( getBundleContext(), ScrService.class.getName(), null );
+                scrServiceTracker.open();
+            }
+            catch ( Throwable t )
+            {
+                // missing ScrService class ??
+                return null;
+            }
+        }
+
+        return ( ScrService ) scrServiceTracker.getService();
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,226 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.Reference;
+import org.apache.felix.scr.ScrService;
+import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
+
+
+public class ComponentConfigurationPrinter extends AbstractScrPlugin implements ConfigurationPrinter
+{
+
+    private ServiceRegistration registration;
+
+
+    public void activate( BundleContext bundleContext )
+    {
+        super.activate( bundleContext );
+
+        registration = bundleContext.registerService( ConfigurationPrinter.SERVICE, this, null );
+    }
+
+
+    public String getTitle()
+    {
+        return "Declarative Services Components";
+    }
+
+
+    public void printConfiguration( PrintWriter pw )
+    {
+        ScrService scrService = getScrService();
+        if ( scrService != null )
+        {
+            Component[] components = scrService.getComponents();
+
+            if ( components == null || components.length == 0 )
+            {
+
+                pw.println( "  No Components Registered" );
+
+            }
+            else
+            {
+
+                // order components by id
+                TreeMap componentMap = new TreeMap();
+                for ( int i = 0; i < components.length; i++ )
+                {
+                    Component component = components[i];
+                    componentMap.put( new Long( component.getId() ), component );
+                }
+
+                // render components
+                for ( Iterator ci = componentMap.values().iterator(); ci.hasNext(); )
+                {
+                    Component component = ( Component ) ci.next();
+                    component( pw, component );
+                }
+            }
+        }
+        else
+        {
+            pw.println( "  Apache Felix Declarative Service not installed" );
+        }
+    }
+
+
+    private void component( PrintWriter pw, Component component )
+    {
+
+        pw.print( component.getId() );
+        pw.print( "=[" );
+        pw.print( component.getName() );
+        pw.println( "]" );
+
+        pw.println( "  Bundle" + component.getBundle().getSymbolicName() + " (" + component.getBundle().getBundleId()
+            + ")" );
+        pw.println( "  State=" + ComponentsServlet.toStateString( component.getState() ) );
+        pw.println( "  DefaultState=" + ( component.isDefaultEnabled() ? "enabled" : "disabled" ) );
+        pw.println( "  Activation=" + ( component.isImmediate() ? "immediate" : "delayed" ) );
+
+        listServices( pw, component );
+        listReferences( pw, component );
+        listProperties( pw, component );
+
+        pw.println();
+    }
+
+
+    private void listServices( PrintWriter pw, Component component )
+    {
+        String[] services = component.getServices();
+        if ( services == null )
+        {
+            return;
+        }
+
+        pw.println( "  ServiceType=" + ( component.isServiceFactory() ? "service factory" : "service" ) );
+
+        StringBuffer buf = new StringBuffer();
+        for ( int i = 0; i < services.length; i++ )
+        {
+            if ( i > 0 )
+            {
+                buf.append( ", " );
+            }
+            buf.append( services[i] );
+        }
+
+        pw.println( "  Services=" + buf );
+    }
+
+
+    private void listReferences( PrintWriter pw, Component component )
+    {
+        Reference[] refs = component.getReferences();
+        if ( refs != null )
+        {
+            for ( int i = 0; i < refs.length; i++ )
+            {
+
+                pw.println( "  Reference=" + refs[i].getName() + ", "
+                    + ( refs[i].isSatisfied() ? "Satisfied" : "Unsatisfied" ) );
+
+                pw.println( "    Service Name: " + refs[i].getServiceName() );
+
+                if ( refs[i].getTarget() != null )
+                {
+                    pw.println( "  Target Filter: " + refs[i].getTarget() );
+                }
+
+                pw.println( "    Multiple: " + ( refs[i].isMultiple() ? "multiple" : "single" ) );
+                pw.println( "    Optional: " + ( refs[i].isOptional() ? "optional" : "mandatory" ) );
+                pw.println( "    Policy: " + ( refs[i].isStatic() ? "static" : "dynamic" ) );
+
+                // list bound services
+                ServiceReference[] boundRefs = refs[i].getServiceReferences();
+                if ( boundRefs != null && boundRefs.length > 0 )
+                {
+                    for ( int j = 0; j < boundRefs.length; j++ )
+                    {
+                        pw.print( "    Bound Service: ID " );
+                        pw.print( boundRefs[j].getProperty( Constants.SERVICE_ID ) );
+
+                        String name = ( String ) boundRefs[j].getProperty( ComponentConstants.COMPONENT_NAME );
+                        if ( name == null )
+                        {
+                            name = ( String ) boundRefs[j].getProperty( Constants.SERVICE_PID );
+                            if ( name == null )
+                            {
+                                name = ( String ) boundRefs[j].getProperty( Constants.SERVICE_DESCRIPTION );
+                            }
+                        }
+                        if ( name != null )
+                        {
+                            pw.print( " (" );
+                            pw.print( name );
+                            pw.print( ")" );
+                        }
+                    }
+                }
+                else
+                {
+                    pw.print( "    No Services bound" );
+                }
+                pw.println();
+            }
+        }
+    }
+
+
+    private void listProperties( PrintWriter pw, Component component )
+    {
+        Dictionary props = component.getProperties();
+        if ( props != null )
+        {
+
+            pw.println( "  Properties=" );
+            TreeSet keys = new TreeSet( Collections.list( props.keys() ) );
+            for ( Iterator ki = keys.iterator(); ki.hasNext(); )
+            {
+                String key = ( String ) ki.next();
+                Object value = props.get( key );
+                if ( value.getClass().isArray() )
+                {
+                    value = Arrays.asList( ( Object[] ) value );
+                }
+                pw.println( "    " + key + "=" + value );
+            }
+        }
+
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,475 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.Reference;
+import org.apache.felix.scr.ScrService;
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentConstants;
+
+
+public class ComponentsServlet extends BaseWebConsolePlugin
+{
+
+    public static final String NAME = "components";
+
+    public static final String LABEL = "Components";
+
+    public static final String COMPONENT_ID = "componentId";
+
+    public static final String OPERATION = "action";
+
+    public static final String OPERATION_ENABLE = "enable";
+
+    public static final String OPERATION_DISABLE = "disable";
+
+    private static final String SCR_SERVICE = ScrService.class.getName();
+
+
+    public String getTitle()
+    {
+        return LABEL;
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+        ScrService scrService = getScrService();
+        if ( scrService != null )
+        {
+
+            long componentId = getComponentId( request );
+            Component component = scrService.getComponent( componentId );
+
+            if ( component != null )
+            {
+                String op = request.getParameter( OPERATION );
+                if ( OPERATION_ENABLE.equals( op ) )
+                {
+                    component.enable();
+                }
+                else if ( OPERATION_DISABLE.equals( op ) )
+                {
+                    component.disable();
+                }
+
+                sendAjaxDetails( component, response );
+            }
+
+        }
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+        PrintWriter pw = response.getWriter();
+
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<script src='" + appRoot + "/res/ui/datatable.js' language='JavaScript'></script>" );
+
+        Util.startScript( pw );
+
+        pw.print( "var components = " );
+        renderResult( request, pw );
+        pw.println( ";" );
+
+        pw.println( "renderDataTable( components );" );
+
+        Util.endScript( pw );
+    }
+
+
+    private void renderResult( HttpServletRequest request, PrintWriter pw ) throws IOException
+    {
+        JSONWriter jw = new JSONWriter( pw );
+        try
+        {
+            jw.object();
+
+            jw.key( "numActions" );
+            jw.value( 2 );
+
+            ScrService scrService = getScrService();
+            if ( scrService == null )
+            {
+                jw.key( "error" );
+                jw.value( "Apache Felix Declarative Service required for this function" );
+            }
+            else
+            {
+                Component[] components = null;
+                boolean details = false;
+
+                long componentId = getComponentId( request );
+                if ( componentId >= 0 )
+                {
+                    Component component = scrService.getComponent( componentId );
+                    if ( component != null )
+                    {
+                        components = new Component[]
+                            { component };
+                        details = true;
+                    }
+                }
+
+                if ( components == null )
+                {
+                    components = scrService.getComponents();
+                }
+
+                if ( components == null || components.length == 0 )
+                {
+                    jw.key( "error" );
+                    jw.value( "No components installed currently" );
+                }
+                else
+                {
+                    // order components by name
+                    TreeMap componentMap = new TreeMap();
+                    for ( int i = 0; i < components.length; i++ )
+                    {
+                        Component component = components[i];
+                        componentMap.put( component.getName(), component );
+                    }
+
+                    // render components
+                    jw.key( "data" );
+                    jw.array();
+                    for ( Iterator ci = componentMap.values().iterator(); ci.hasNext(); )
+                    {
+                        component( jw, ( Component ) ci.next(), details );
+                    }
+                    jw.endArray();
+                }
+            }
+
+            jw.endObject();
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+    }
+
+
+    private void sendAjaxDetails( Component component, HttpServletResponse response ) throws IOException
+    {
+
+        // send the result
+        response.setContentType( "text/javascript" );
+
+        JSONWriter jw = new JSONWriter( response.getWriter() );
+        try
+        {
+            if ( component != null )
+            {
+                component( jw, component, true );
+            }
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+    }
+
+
+    private void component( JSONWriter jw, Component component, boolean details ) throws JSONException
+    {
+        String id = String.valueOf( component.getId() );
+        String name = component.getName();
+        int state = component.getState();
+
+        jw.object();
+
+        // component information
+        jw.key( "id" );
+        jw.value( id );
+        jw.key( "name" );
+        jw.value( name );
+        jw.key( "state" );
+        jw.value( toStateString( state ) );
+
+        // component actions
+        jw.key( "actions" );
+        jw.array();
+
+        jw.object();
+        jw.key( "name" );
+        jw.value( "Enable" );
+        jw.key( "link" );
+        jw.value( OPERATION_ENABLE );
+        jw.key( "enabled" );
+        jw.value( state == Component.STATE_DISABLED );
+        jw.endObject();
+
+        jw.object();
+        jw.key( "name" );
+        jw.value( "Disable" );
+        jw.key( "link" );
+        jw.value( OPERATION_DISABLE );
+        jw.key( "enabled" );
+        jw.value( state != Component.STATE_DISABLED && state != Component.STATE_DESTROYED );
+        jw.endObject();
+
+        jw.endArray();
+
+        // component details
+        if ( details )
+        {
+            gatherComponentDetails( jw, component );
+        }
+
+        jw.endObject();
+    }
+
+
+    private void gatherComponentDetails( JSONWriter jw, Component component ) throws JSONException
+    {
+        jw.key( "props" );
+        jw.array();
+
+        keyVal( jw, "Bundle", component.getBundle().getSymbolicName() + " (" + component.getBundle().getBundleId()
+            + ")" );
+        keyVal( jw, "Default State", component.isDefaultEnabled() ? "enabled" : "disabled" );
+        keyVal( jw, "Activation", component.isImmediate() ? "immediate" : "delayed" );
+
+        listServices( jw, component );
+        listReferences( jw, component );
+        listProperties( jw, component );
+
+        jw.endArray();
+    }
+
+
+    private void listServices( JSONWriter jw, Component component )
+    {
+        String[] services = component.getServices();
+        if ( services == null )
+        {
+            return;
+        }
+
+        keyVal( jw, "Service Type", component.isServiceFactory() ? "service factory" : "service" );
+
+        StringBuffer buf = new StringBuffer();
+        for ( int i = 0; i < services.length; i++ )
+        {
+            if ( i > 0 )
+            {
+                buf.append( "<br />" );
+            }
+            buf.append( services[i] );
+        }
+
+        keyVal( jw, "Services", buf.toString() );
+    }
+
+
+    private void listReferences( JSONWriter jw, Component component )
+    {
+        Reference[] refs = component.getReferences();
+        if ( refs != null )
+        {
+            for ( int i = 0; i < refs.length; i++ )
+            {
+                StringBuffer buf = new StringBuffer();
+                buf.append( refs[i].isSatisfied() ? "Satisfied" : "Unsatisfied" ).append( "<br />" );
+                buf.append( "Service Name: " ).append( refs[i].getServiceName() ).append( "<br />" );
+                if ( refs[i].getTarget() != null )
+                {
+                    buf.append( "Target Filter: " ).append( refs[i].getTarget() ).append( "<br />" );
+                }
+                buf.append( "Multiple: " ).append( refs[i].isMultiple() ? "multiple" : "single" ).append( "<br />" );
+                buf.append( "Optional: " ).append( refs[i].isOptional() ? "optional" : "mandatory" ).append( "<br />" );
+                buf.append( "Policy: " ).append( refs[i].isStatic() ? "static" : "dynamic" ).append( "<br />" );
+
+                // list bound services
+                ServiceReference[] boundRefs = refs[i].getServiceReferences();
+                if ( boundRefs != null && boundRefs.length > 0 )
+                {
+                    for ( int j = 0; j < boundRefs.length; j++ )
+                    {
+                        if ( j > 0 )
+                        {
+                            buf.append( "<br />" );
+                        }
+
+                        buf.append( "Bound Service ID " );
+                        buf.append( boundRefs[j].getProperty( Constants.SERVICE_ID ) );
+
+                        String name = ( String ) boundRefs[j].getProperty( ComponentConstants.COMPONENT_NAME );
+                        if ( name == null )
+                        {
+                            name = ( String ) boundRefs[j].getProperty( Constants.SERVICE_PID );
+                            if ( name == null )
+                            {
+                                name = ( String ) boundRefs[j].getProperty( Constants.SERVICE_DESCRIPTION );
+                            }
+                        }
+                        if ( name != null )
+                        {
+                            buf.append( " (" );
+                            buf.append( name );
+                            buf.append( ")" );
+                        }
+                    }
+                }
+                else
+                {
+                    buf.append( "No Services bound" );
+                }
+                buf.append( "<br />" );
+
+                keyVal( jw, "Reference " + refs[i].getName(), buf.toString() );
+            }
+        }
+    }
+
+
+    private void listProperties( JSONWriter jw, Component component )
+    {
+        Dictionary props = component.getProperties();
+        if ( props != null )
+        {
+            StringBuffer buf = new StringBuffer();
+            TreeSet keys = new TreeSet( Collections.list( props.keys() ) );
+            for ( Iterator ki = keys.iterator(); ki.hasNext(); )
+            {
+                String key = ( String ) ki.next();
+                buf.append( key ).append( " = " );
+
+                Object prop = props.get( key );
+                if ( prop.getClass().isArray() )
+                {
+                    prop = Arrays.asList( ( Object[] ) prop );
+                }
+                buf.append( prop );
+                if ( ki.hasNext() )
+                {
+                    buf.append( "<br />" );
+                }
+            }
+
+            keyVal( jw, "Properties", buf.toString() );
+        }
+
+    }
+
+
+    private void keyVal( JSONWriter jw, String key, Object value )
+    {
+        if ( key != null && value != null )
+        {
+            try
+            {
+                jw.object();
+                jw.key( "key" );
+                jw.value( key );
+                jw.key( "value" );
+                jw.value( value );
+                jw.endObject();
+            }
+            catch ( JSONException je )
+            {
+                // don't care
+            }
+        }
+    }
+
+
+    static String toStateString( int state )
+    {
+        switch ( state )
+        {
+            case Component.STATE_DISABLED:
+                return "disabled";
+            case Component.STATE_ENABLED:
+                return "enabled";
+            case Component.STATE_UNSATISFIED:
+                return "unsatisifed";
+            case Component.STATE_ACTIVATING:
+                return "activating";
+            case Component.STATE_ACTIVE:
+                return "active";
+            case Component.STATE_REGISTERED:
+                return "registered";
+            case Component.STATE_FACTORY:
+                return "factory";
+            case Component.STATE_DEACTIVATING:
+                return "deactivating";
+            case Component.STATE_DESTROYED:
+                return "destroyed";
+            default:
+                return String.valueOf( state );
+        }
+    }
+
+
+    protected long getComponentId( HttpServletRequest request )
+    {
+        String componentIdPar = request.getParameter( ComponentsServlet.COMPONENT_ID );
+        if ( componentIdPar == null )
+        {
+            String info = request.getPathInfo();
+            componentIdPar = info.substring( info.lastIndexOf( '/' ) + 1 );
+        }
+
+        try
+        {
+            return Long.parseLong( componentIdPar );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            // TODO: log
+        }
+
+        // no bundleId or wrong format
+        return -1;
+    }
+
+
+    private ScrService getScrService()
+    {
+        return ( ScrService ) getService( SCR_SERVICE );
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,913 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.Map.Entry;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.*;
+import org.osgi.framework.*;
+import org.osgi.service.cm.*;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+
+/**
+ * The <code>ConfigManager</code> TODO
+ */
+public class ConfigManager extends ConfigManagerBase
+{
+
+    private static final String PID_FILTER = "pidFilter";
+
+    public static final String NAME = "configMgr";
+
+    public static final String LABEL = "Configuration";
+
+    public static final String PID = "pid";
+
+    public static final String factoryPID = "factoryPid";
+
+    private static final String PLACEHOLDER_PID = "[Temporary PID replaced by real PID upon save]";
+
+
+    public String getTitle()
+    {
+        return LABEL;
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+        // needed multiple times below
+        String pid = request.getParameter( ConfigManager.PID );
+        if ( pid == null )
+        {
+            String info = request.getPathInfo();
+            pid = info.substring( info.lastIndexOf( '/' ) + 1 );
+        }
+
+        // the filter to select part of the configurations
+        String pidFilter = request.getParameter( PID_FILTER );
+
+        ConfigurationAdmin ca = this.getConfigurationAdmin();
+
+        // ignore this request if the pid and/or configuration admin is missing
+        if ( pid == null || ca == null )
+        {
+            // should log this here !!
+            return;
+        }
+
+        // the configuration to operate on (to be created or "missing")
+        Configuration config = null;
+
+        // should actually apply the configuration before redirecting
+        if ( request.getParameter( "create" ) != null )
+        {
+            config = new PlaceholderConfiguration( pid ); // ca.createFactoryConfiguration( pid, null );
+            pid = config.getPid();
+        }
+        else if ( request.getParameter( "apply" ) != null )
+        {
+            String redirect = applyConfiguration( request, ca, pid );
+            if ( redirect != null )
+            {
+                if (pidFilter != null) {
+                    redirect += "?" + PID_FILTER + "=" + pidFilter;
+                }
+
+                response.sendRedirect( redirect );
+            }
+
+            return;
+        }
+
+        if ( config == null )
+        {
+            config = getConfiguration( ca, pid );
+        }
+
+        // send the result
+        response.setContentType( "text/javascript" );
+        response.setCharacterEncoding( "UTF-8" );
+        printConfigurationJson( response.getWriter(), pid, config, pidFilter, getLocale( request ) );
+    }
+
+
+    public void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+
+        // true if MetaType service information is not required
+        boolean optionalMetaType = false;
+
+        // extract the configuration pid from the request path
+        String pid = request.getPathInfo();
+        pid = pid.substring( pid.lastIndexOf( '/' ) + 1 );
+
+        // check whether the pid is actually a filter for the selection
+        // of configurations to display, if the filter correctly converts
+        // into an OSGi filter, we use it to select configurations
+        // to display
+        String pidFilter = request.getParameter( PID_FILTER );
+        if ( pidFilter == null )
+        {
+            pidFilter = pid;
+        }
+        try
+        {
+            getBundleContext().createFilter( pidFilter );
+
+            // if the pidFilter was set from the pid, clear the pid
+            if ( pid == pidFilter )
+            {
+                pid = null;
+            }
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            // its ok, if the pid is just a single PID
+            pidFilter = null;
+        }
+
+        Locale loc = getLocale( request );
+        String locale = ( loc != null ) ? loc.toString() : null;
+
+        PrintWriter pw = response.getWriter();
+
+        String appRoot = (String) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<script src='" + appRoot + "/res/ui/configmanager.js' language='JavaScript'></script>" );
+
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+
+        ConfigurationAdmin ca = this.getConfigurationAdmin();
+        if ( ca == null )
+        {
+            pw.println( "<tr class='content' id='configField'>" );
+            pw.println( "<td class='content'>&nbsp;</th>" );
+            pw.println( "<td class='content'>" );
+            pw.print( "Configuration Admin Service not available" );
+            pw.println( "</td>" );
+            pw.println( "</tr>" );
+        }
+        else
+        {
+            pw.println( "<tr class='content' id='configField'>" );
+            pw.println( "<td class='content'>Configurations</th>" );
+            pw.println( "<td class='content'>" );
+            this.listConfigurations( pw, ca, pidFilter, optionalMetaType, locale );
+            pw.println( "</td>" );
+            pw.println( "</tr>" );
+
+            pw.println( "<tr class='content' id='factoryField'>" );
+            pw.println( "<td class='content'>Factory Configurations</th>" );
+            pw.println( "<td class='content'>" );
+            this.listFactoryConfigurations( pw, ca, pidFilter, optionalMetaType, locale );
+            pw.println( "</td>" );
+            pw.println( "</tr>" );
+        }
+
+        pw.println( "</table>" );
+
+        // if a configuration is addressed, display it immediately
+        Configuration config;
+        if ( request.getParameter( "create" ) != null && pid != null )
+        {
+            config = new PlaceholderConfiguration( pid );
+            pid = config.getPid();
+        }
+        else
+        {
+            config = getConfiguration( getConfigurationAdmin(), pid );
+        }
+
+        if ( config != null )
+        {
+            Util.startScript( pw );
+
+            pw.println( "var configuration=" );
+            printConfigurationJson( pw, config.getPid(), config, pidFilter, getLocale( request ) );
+            pw.println( ";" );
+
+            pw.println( "displayConfigForm(configuration);" );
+
+            Util.endScript( pw );
+        }
+    }
+
+
+    private Configuration getConfiguration( ConfigurationAdmin ca, String pid )
+    {
+        if ( ca != null && pid != null )
+        {
+            try
+            {
+                // we use listConfigurations to not create configuration
+                // objects persistently without the user providing actual
+                // configuration
+                String filter = "(" + Constants.SERVICE_PID + "=" + pid + ")";
+                Configuration[] configs = ca.listConfigurations( filter );
+                if ( configs != null && configs.length > 0 )
+                {
+                    return configs[0];
+                }
+            }
+            catch ( InvalidSyntaxException ise )
+            {
+                // should print message
+            }
+            catch ( IOException ioe )
+            {
+                // should print message
+            }
+        }
+
+        // fallback to no configuration at all
+        return null;
+    }
+
+
+    private void listConfigurations( PrintWriter pw, ConfigurationAdmin ca, String pidFilter, boolean optionalMetaType, String locale )
+    {
+        try
+        {
+            // start with ManagedService instances
+            SortedMap optionsPlain = getServices( ManagedService.class.getName(), pidFilter, optionalMetaType, locale );
+
+            // add in existing configuration (not duplicating ManagedServices)
+            Configuration[] cfgs = ca.listConfigurations( pidFilter );
+            for ( int i = 0; cfgs != null && i < cfgs.length; i++ )
+            {
+
+                // ignore configuration object if an entry already exists in the
+                // map
+                String pid = cfgs[i].getPid();
+                if ( optionsPlain.containsKey( pid ) )
+                {
+                    continue;
+                }
+
+                // insert and entry for the pid
+                ObjectClassDefinition ocd = this.getObjectClassDefinition( cfgs[i], locale );
+                String name;
+                if ( ocd != null )
+                {
+                    name = ocd.getName() + " (";
+                    name += pid + ")";
+                }
+                else
+                {
+                    name = pid;
+                }
+
+                if ( ocd != null || optionalMetaType )
+                {
+                    optionsPlain.put( pid, name );
+                }
+            }
+
+            printOptionsForm( pw, optionsPlain, "configSelection_pid", "configure", "Configure" );
+        }
+        catch ( Exception e )
+        {
+            // write a message or ignore
+        }
+    }
+
+
+    private void listFactoryConfigurations( PrintWriter pw, ConfigurationAdmin ca, String pidFilter, boolean optionalMetaType,
+        String locale )
+    {
+        try
+        {
+            SortedMap optionsFactory = getServices( ManagedServiceFactory.class.getName(), pidFilter, optionalMetaType, locale );
+            printOptionsForm( pw, optionsFactory, "configSelection_factory", "create", "Create" );
+        }
+        catch ( Exception e )
+        {
+            // write a message or ignore
+        }
+    }
+
+
+    private SortedMap getServices( String serviceClass, String serviceFilter, boolean optionalMetaType, String locale )
+        throws InvalidSyntaxException
+    {
+        // sorted map of options
+        SortedMap optionsFactory = new TreeMap( String.CASE_INSENSITIVE_ORDER );
+
+        // find all ManagedServiceFactories to get the factoryPIDs
+        ServiceReference[] refs = this.getBundleContext().getServiceReferences( serviceClass, serviceFilter );
+        for ( int i = 0; refs != null && i < refs.length; i++ )
+        {
+            Object pidObject = refs[i].getProperty( Constants.SERVICE_PID );
+            if ( pidObject instanceof String )
+            {
+                String pid = ( String ) pidObject;
+                String name;
+                ObjectClassDefinition ocd = this.getObjectClassDefinition( refs[i].getBundle(), pid, locale );
+                if ( ocd != null )
+                {
+                    name = ocd.getName() + " (";
+                    name += pid + ")";
+                }
+                else
+                {
+                    name = pid;
+                }
+
+                if ( ocd != null || optionalMetaType )
+                {
+                    optionsFactory.put( pid, name );
+                }
+            }
+        }
+
+        return optionsFactory;
+    }
+
+
+    private void printOptionsForm( PrintWriter pw, SortedMap options, String formId, String submitMethod,
+        String submitLabel )
+    {
+        SortedSet set = new TreeSet();
+        for ( Iterator ei = options.entrySet().iterator(); ei.hasNext(); )
+        {
+            Entry entry = ( Entry ) ei.next();
+            set.add(entry.getValue().toString() + Character.MAX_VALUE + entry.getKey().toString());
+        }
+
+        pw.println( "<select class='select' name='pid' id='" + formId + "' onChange='" + submitMethod + "();'>" );
+        for ( Iterator ei = set.iterator(); ei.hasNext(); )
+        {
+            String entry = ( String ) ei.next();
+            int sep = entry.indexOf( Character.MAX_VALUE );
+            String value = entry.substring( 0, sep );
+            String key = entry.substring( sep + 1 );
+            pw.print( "<option value='" + key + "'>" );
+            pw.print( value );
+            pw.println( "</option>" );
+        }
+        pw.println( "</select>" );
+        pw.println( "&nbsp;&nbsp;" );
+        pw.println( "<input class='submit' type='button' value='" + submitLabel + "' onClick='" + submitMethod
+            + "();' />" );
+
+    }
+
+
+    private void printConfigurationJson( PrintWriter pw, String pid, Configuration config, String pidFilter,
+        Locale locale )
+    {
+
+        JSONWriter result = new JSONWriter( pw );
+
+        if ( pid != null )
+        {
+            try
+            {
+                result.object();
+                this.configForm( result, pid, config, pidFilter, locale );
+                result.endObject();
+            }
+            catch ( Exception e )
+            {
+                // add message
+            }
+        }
+
+    }
+
+
+    private void configForm( JSONWriter json, String pid, Configuration config, String pidFilter, Locale loc )
+        throws JSONException
+    {
+        String locale = ( loc == null ) ? null : loc.toString();
+
+        json.key( ConfigManager.PID );
+        json.value( pid );
+
+        if ( pidFilter != null )
+        {
+            json.key( PID_FILTER );
+            json.value( pidFilter );
+        }
+
+        Dictionary props = null;
+        ObjectClassDefinition ocd;
+        if ( config != null )
+        {
+            props = config.getProperties();
+            ocd = this.getObjectClassDefinition( config, locale );
+        }
+        else
+        {
+            ocd = this.getObjectClassDefinition( pid, locale );
+        }
+
+        props = this.mergeWithMetaType( props, ocd, json );
+
+        if ( props != null )
+        {
+
+            json.key( "title" );
+            json.value( pid );
+            json.key( "description" );
+            json
+                .value( "Please enter configuration properties for this configuration in the field below. This configuration has no associated description" );
+
+            json.key( "propertylist" );
+            json.value( "properties" );
+
+            json.key( "properties" );
+            json.object();
+            for ( Enumeration pe = props.keys(); pe.hasMoreElements(); )
+            {
+                Object key = pe.nextElement();
+
+                // ignore well known special properties
+                if ( !key.equals( Constants.SERVICE_PID ) && !key.equals( Constants.SERVICE_DESCRIPTION )
+                    && !key.equals( Constants.SERVICE_ID ) && !key.equals( Constants.SERVICE_RANKING )
+                    && !key.equals( Constants.SERVICE_VENDOR )
+                    && !key.equals( ConfigurationAdmin.SERVICE_BUNDLELOCATION )
+                    && !key.equals( ConfigurationAdmin.SERVICE_FACTORYPID ) )
+                {
+                    json.key( String.valueOf( key ) );
+                    json.value( props.get( key ) );
+                }
+            }
+            json.endObject();
+
+        }
+
+        if ( config != null )
+        {
+            this.addConfigurationInfo( config, json, locale );
+        }
+    }
+
+
+    private Dictionary mergeWithMetaType( Dictionary props, ObjectClassDefinition ocd, JSONWriter json )
+        throws JSONException
+    {
+
+        if ( props == null )
+        {
+            props = new Hashtable();
+        }
+
+        if ( ocd != null )
+        {
+
+            json.key( "title" );
+            json.value( ocd.getName() );
+
+            if ( ocd.getDescription() != null )
+            {
+                json.key( "description" );
+                json.value( ocd.getDescription() );
+            }
+
+            AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
+            if ( ad != null )
+            {
+
+                JSONArray propertyList = new JSONArray();
+
+                for ( int i = 0; i < ad.length; i++ )
+                {
+                    json.key( ad[i].getID() );
+                    json.object();
+
+                    Object value = props.get( ad[i].getID() );
+                    if ( value == null )
+                    {
+                        value = ad[i].getDefaultValue();
+                        if ( value == null )
+                        {
+                            if ( ad[i].getCardinality() == 0 )
+                            {
+                                value = "";
+                            }
+                            else
+                            {
+                                value = new String[0];
+                            }
+                        }
+                    }
+
+                    json.key( "name" );
+                    json.value( ad[i].getName() );
+
+                    json.key( "type" );
+                    if ( ad[i].getOptionLabels() != null && ad[i].getOptionLabels().length > 0 )
+                    {
+                        json.object();
+                        json.key( "labels" );
+                        json.value( Arrays.asList( ad[i].getOptionLabels() ) );
+                        json.key( "values" );
+                        json.value( Arrays.asList( ad[i].getOptionValues() ) );
+                        json.endObject();
+                    }
+                    else
+                    {
+                        json.value( ad[i].getType() );
+                    }
+
+                    if ( ad[i].getCardinality() == 0 )
+                    {
+                        // scalar
+                        if ( value instanceof Vector )
+                        {
+                            value = ( ( Vector ) value ).get( 0 );
+                        }
+                        else if ( value.getClass().isArray() )
+                        {
+                            value = Array.get( value, 0 );
+                        }
+                        json.key( "value" );
+                        json.value( value );
+                    }
+                    else
+                    {
+                        if ( value instanceof Vector )
+                        {
+                            value = new JSONArray( ( Vector ) value );
+                        }
+                        else if ( value.getClass().isArray() )
+                        {
+                            value = new JSONArray( Arrays.asList( ( Object[] ) value ) );
+                        }
+                        else
+                        {
+                            JSONArray tmp = new JSONArray();
+                            tmp.put( value );
+                            value = tmp;
+                        }
+                        json.key( "values" );
+                        json.value( value );
+                    }
+
+                    if ( ad[i].getDescription() != null )
+                    {
+                        json.key( "description" );
+                        json.value( ad[i].getDescription() );
+                    }
+
+                    json.endObject();
+                    propertyList.put( ad[i].getID() );
+                }
+
+                json.key( "propertylist" );
+                json.value( propertyList );
+            }
+
+            // nothing more to display
+            props = null;
+        }
+
+        return props;
+    }
+
+
+    private void addConfigurationInfo( Configuration config, JSONWriter json, String locale ) throws JSONException
+    {
+
+        if ( config.getFactoryPid() != null )
+        {
+            json.key( factoryPID );
+            json.value( config.getFactoryPid() );
+        }
+
+        String location;
+        if ( config.getBundleLocation() == null )
+        {
+            location = "None";
+        }
+        else
+        {
+            Bundle bundle = this.getBundle( config.getBundleLocation() );
+
+            Dictionary headers = bundle.getHeaders( locale );
+            String name = ( String ) headers.get( Constants.BUNDLE_NAME );
+            if ( name == null )
+            {
+                location = bundle.getSymbolicName();
+            }
+            else
+            {
+                location = name + " (" + bundle.getSymbolicName() + ")";
+            }
+
+            Version v = Version.parseVersion( ( String ) headers.get( Constants.BUNDLE_VERSION ) );
+            location += ", Version " + v.toString();
+        }
+        json.key( "bundleLocation" );
+        json.value( location );
+    }
+
+
+    private String applyConfiguration( HttpServletRequest request, ConfigurationAdmin ca, String pid )
+        throws IOException
+    {
+        if ( request.getParameter( "delete" ) != null )
+        {
+            // only delete if the PID is not our place holder
+            if ( !PLACEHOLDER_PID.equals( pid ) )
+            {
+                // TODO: should log this here !!
+                Configuration config = ca.getConfiguration( pid, null );
+                config.delete();
+            }
+            return request.getHeader( "Referer" );
+        }
+
+        String factoryPid = request.getParameter( ConfigManager.factoryPID );
+        Configuration config = null;
+
+        String propertyList = request.getParameter( "propertylist" );
+        if ( propertyList == null )
+        {
+            String propertiesString = request.getParameter( "properties" );
+
+            if ( propertiesString != null )
+            {
+                byte[] propBytes = propertiesString.getBytes( "ISO-8859-1" );
+                ByteArrayInputStream bin = new ByteArrayInputStream( propBytes );
+                Properties props = new Properties();
+                props.load( bin );
+
+                config = getConfiguration( ca, pid, factoryPid );
+                config.update( props );
+            }
+        }
+        else
+        {
+            config = getConfiguration( ca, pid, factoryPid );
+
+            Dictionary props = config.getProperties();
+            if ( props == null )
+            {
+                props = new Hashtable();
+            }
+
+            Map adMap = this.getAttributeDefinitionMap( config, null );
+            if ( adMap != null )
+            {
+                StringTokenizer propTokens = new StringTokenizer( propertyList, "," );
+                while ( propTokens.hasMoreTokens() )
+                {
+                    String propName = propTokens.nextToken();
+                    AttributeDefinition ad = ( AttributeDefinition ) adMap.get( propName );
+                    if ( ad == null || ( ad.getCardinality() == 0 && ad.getType() == AttributeDefinition.STRING ) )
+                    {
+                        String prop = request.getParameter( propName );
+                        if ( prop != null )
+                        {
+                            props.put( propName, prop );
+                        }
+                    }
+                    else if ( ad.getCardinality() == 0 )
+                    {
+                        // scalar of non-string
+                        String prop = request.getParameter( propName );
+                        if ( prop != null )
+                        {
+                            try
+                            {
+                                props.put( propName, this.toType( ad.getType(), prop ) );
+                            }
+                            catch ( NumberFormatException nfe )
+                            {
+                                // don't care
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // array or vector of any type
+                        Vector vec = new Vector();
+
+                        String[] properties = request.getParameterValues( propName );
+                        if ( properties != null )
+                        {
+                            for ( int i = 0; i < properties.length; i++ )
+                            {
+                                try
+                                {
+                                    vec.add( this.toType( ad.getType(), properties[i] ) );
+                                }
+                                catch ( NumberFormatException nfe )
+                                {
+                                    // don't care
+                                }
+                            }
+                        }
+
+                        // but ensure size
+                        int maxSize = Math.abs( ad.getCardinality() );
+                        if ( vec.size() > maxSize )
+                        {
+                            vec.setSize( maxSize );
+                        }
+
+                        if ( ad.getCardinality() < 0 )
+                        {
+                            // keep the vector
+                            props.put( propName, vec );
+                        }
+                        else
+                        {
+                            // convert to an array
+                            props.put( propName, this.toArray( ad.getType(), vec ) );
+                        }
+                    }
+                }
+            }
+
+            config.update( props );
+        }
+
+        // redirect to the new configuration (if existing)
+        return (config != null) ? config.getPid() : "";
+    }
+
+
+    private Configuration getConfiguration( ConfigurationAdmin ca, String pid, String factoryPid ) throws IOException
+    {
+        if ( factoryPid != null )
+        {
+            return ca.createFactoryConfiguration( factoryPid, null );
+        }
+
+        return ca.getConfiguration( pid, null );
+    }
+
+
+    /**
+     * @throws NumberFormatException If the value cannot be converted to
+     *      a number and type indicates a numeric type
+     */
+    private Object toType( int type, String value )
+    {
+        switch ( type )
+        {
+            case AttributeDefinition.BOOLEAN:
+                return Boolean.valueOf( value );
+            case AttributeDefinition.BYTE:
+                return Byte.valueOf( value );
+            case AttributeDefinition.CHARACTER:
+                char c = ( value.length() > 0 ) ? value.charAt( 0 ) : 0;
+                return new Character( c );
+            case AttributeDefinition.DOUBLE:
+                return Double.valueOf( value );
+            case AttributeDefinition.FLOAT:
+                return Float.valueOf( value );
+            case AttributeDefinition.LONG:
+                return Long.valueOf( value );
+            case AttributeDefinition.INTEGER:
+                return Integer.valueOf( value );
+            case AttributeDefinition.SHORT:
+                return Short.valueOf( value );
+
+            default:
+                // includes AttributeDefinition.STRING
+                return value;
+        }
+    }
+
+
+    private Object toArray( int type, Vector values )
+    {
+        int size = values.size();
+
+        // short cut for string array
+        if ( type == AttributeDefinition.STRING )
+        {
+            return values.toArray( new String[size] );
+        }
+
+        Object array;
+        switch ( type )
+        {
+            case AttributeDefinition.BOOLEAN:
+                array = new boolean[size];
+            case AttributeDefinition.BYTE:
+                array = new byte[size];
+            case AttributeDefinition.CHARACTER:
+                array = new char[size];
+            case AttributeDefinition.DOUBLE:
+                array = new double[size];
+            case AttributeDefinition.FLOAT:
+                array = new float[size];
+            case AttributeDefinition.LONG:
+                array = new long[size];
+            case AttributeDefinition.INTEGER:
+                array = new int[size];
+            case AttributeDefinition.SHORT:
+                array = new short[size];
+            default:
+                // unexpected, but assume string
+                array = new String[size];
+        }
+
+        for ( int i = 0; i < size; i++ )
+        {
+            Array.set( array, i, values.get( i ) );
+        }
+
+        return array;
+    }
+
+    private static class PlaceholderConfiguration implements Configuration
+    {
+
+        private final String factoryPid;
+        private String bundleLocation;
+
+
+        PlaceholderConfiguration( String factoryPid )
+        {
+            this.factoryPid = factoryPid;
+        }
+
+
+        public String getPid()
+        {
+            return PLACEHOLDER_PID;
+        }
+
+
+        public String getFactoryPid()
+        {
+            return factoryPid;
+        }
+
+
+        public void setBundleLocation( String bundleLocation )
+        {
+            this.bundleLocation = bundleLocation;
+        }
+
+
+        public String getBundleLocation()
+        {
+            return bundleLocation;
+        }
+
+
+        public Dictionary getProperties()
+        {
+            // dummy configuration has no properties
+            return null;
+        }
+
+
+        public void update()
+        {
+            // dummy configuration cannot be updated
+        }
+
+
+        public void update( Dictionary properties )
+        {
+            // dummy configuration cannot be updated
+        }
+
+
+        public void delete()
+        {
+            // dummy configuration cannot be deleted
+        }
+
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,224 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.MetaTypeInformation;
+import org.osgi.service.metatype.MetaTypeService;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+
+/**
+ * The <code>ConfigManagerBase</code> TODO
+ * 
+ */
+abstract class ConfigManagerBase extends BaseWebConsolePlugin
+{
+    private static final String CONFIGURATION_ADMIN_NAME = ConfigurationAdmin.class.getName();
+
+    private static final String META_TYPE_NAME = MetaTypeService.class.getName();
+
+
+    protected ConfigurationAdmin getConfigurationAdmin()
+    {
+        return ( ConfigurationAdmin ) getService( CONFIGURATION_ADMIN_NAME );
+    }
+
+
+    protected MetaTypeService getMetaTypeService()
+    {
+        //TODO: 
+        return ( MetaTypeService ) getService( META_TYPE_NAME );
+    }
+
+
+    protected Map getMetadataPids()
+    {
+        Map pids = new HashMap();
+        MetaTypeService mts = this.getMetaTypeService();
+        if ( mts != null )
+        {
+            Bundle[] bundles = this.getBundleContext().getBundles();
+            for ( int i = 0; i < bundles.length; i++ )
+            {
+                MetaTypeInformation mti = mts.getMetaTypeInformation( bundles[i] );
+                if ( mti != null )
+                {
+                    String[] pidList = mti.getPids();
+                    for ( int j = 0; pidList != null && j < pidList.length; j++ )
+                    {
+                        pids.put( pidList[j], bundles[i] );
+                    }
+                }
+            }
+        }
+        return pids;
+    }
+
+
+    protected ObjectClassDefinition getObjectClassDefinition( Configuration config, String locale )
+    {
+
+        // if the configuration is not bound, search in the bundles
+        if ( config.getBundleLocation() == null )
+        {
+            // if the configuration is a factory one, use the factory PID
+            if ( config.getFactoryPid() != null )
+            {
+                return this.getObjectClassDefinition( config.getFactoryPid(), locale );
+            }
+
+            // otherwise use the configuration PID
+            return this.getObjectClassDefinition( config.getPid(), locale );
+        }
+
+        MetaTypeService mts = this.getMetaTypeService();
+        if ( mts != null )
+        {
+            Bundle bundle = this.getBundle( config.getBundleLocation() );
+            if ( bundle != null )
+            {
+                MetaTypeInformation mti = mts.getMetaTypeInformation( bundle );
+                if ( mti != null )
+                {
+                    // check by factory PID
+                    if ( config.getFactoryPid() != null )
+                    {
+                        return mti.getObjectClassDefinition( config.getFactoryPid(), locale );
+                    }
+
+                    // otherwise check by configuration PID
+                    return mti.getObjectClassDefinition( config.getPid(), locale );
+                }
+            }
+        }
+
+        // fallback to nothing found
+        return null;
+    }
+
+
+    protected ObjectClassDefinition getObjectClassDefinition( Bundle bundle, String pid, String locale )
+    {
+        if ( bundle != null )
+        {
+            MetaTypeService mts = this.getMetaTypeService();
+            if ( mts != null )
+            {
+                MetaTypeInformation mti = mts.getMetaTypeInformation( bundle );
+                if ( mti != null )
+                {
+                    return mti.getObjectClassDefinition( pid, locale );
+                }
+            }
+        }
+
+        // fallback to nothing found
+        return null;
+    }
+
+
+    protected ObjectClassDefinition getObjectClassDefinition( String pid, String locale )
+    {
+        Bundle[] bundles = this.getBundleContext().getBundles();
+        for ( int i = 0; i < bundles.length; i++ )
+        {
+            try
+            {
+                ObjectClassDefinition ocd = this.getObjectClassDefinition( bundles[i], pid, locale );
+                if ( ocd != null )
+                {
+                    return ocd;
+                }
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                // don't care
+            }
+        }
+        return null;
+    }
+
+
+    protected Map getAttributeDefinitionMap( Configuration config, String locale )
+    {
+        ObjectClassDefinition ocd = this.getObjectClassDefinition( config, locale );
+        if ( ocd != null )
+        {
+            AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
+            if ( ad != null )
+            {
+                Map adMap = new HashMap();
+                for ( int i = 0; i < ad.length; i++ )
+                {
+                    adMap.put( ad[i].getID(), ad[i] );
+                }
+                return adMap;
+            }
+        }
+
+        // fallback to nothing found
+        return null;
+    }
+
+
+    protected Bundle getBundle( String bundleLocation )
+    {
+        if ( bundleLocation == null )
+        {
+            return null;
+        }
+
+        Bundle[] bundles = this.getBundleContext().getBundles();
+        for ( int i = 0; i < bundles.length; i++ )
+        {
+            if ( bundleLocation.equals( bundles[i].getLocation() ) )
+            {
+                return bundles[i];
+            }
+        }
+
+        return null;
+    }
+
+
+    protected Locale getLocale( HttpServletRequest request )
+    {
+        try
+        {
+            return request.getLocale();
+        }
+        catch ( Throwable t )
+        {
+            // expected in standard OSGi Servlet 2.1 environments
+            // fallback to using the default locale
+            return Locale.getDefault();
+        }
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundleAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundleAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundleAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,48 @@
+/*
+ * 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.felix.webconsole.internal.core;
+
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.felix.webconsole.Action;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+
+
+abstract class BundleAction extends BaseManagementPlugin implements Action
+{
+
+    protected long getBundleId( HttpServletRequest request )
+    {
+        String bundleIdPar = request.getParameter( BundlesServlet.BUNDLE_ID );
+        if ( bundleIdPar != null )
+        {
+            try
+            {
+                return Long.parseLong( bundleIdPar );
+            }
+            catch ( NumberFormatException nfe )
+            {
+                // TODO: log
+            }
+        }
+
+        // no bundleId or wrong format
+        return -1;
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,983 @@
+/*
+ * 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.felix.webconsole.internal.core;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.bundlerepository.*;
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.obr.DeployerThread;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.*;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.log.LogService;
+import org.osgi.service.obr.*;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+
+
+/**
+ * The <code>BundlesServlet</code> TODO
+ */
+public class BundlesServlet extends BaseWebConsolePlugin
+{
+
+    public static final String NAME = "bundles";
+
+    public static final String LABEL = "Bundles";
+
+    public static final String BUNDLE_ID = "bundleId";
+
+    private static final String REPOSITORY_ADMIN_NAME = RepositoryAdmin.class.getName();
+
+    // bootdelegation property entries. wildcards are converted to package
+    // name prefixes. whether an entry is a wildcard or not is set as a flag
+    // in the bootPkgWildcards array.
+    // see #activate and #isBootDelegated
+    private String[] bootPkgs;
+
+    // a flag for each entry in bootPkgs indicating whether the respective
+    // entry was declared as a wildcard or not
+    // see #activate and #isBootDelegated
+    private boolean[] bootPkgWildcards;
+
+
+    public void activate( BundleContext bundleContext )
+    {
+        super.activate( bundleContext );
+
+        // bootdelegation property parsing from Apache Felix R4SearchPolicyCore
+        String bootDelegation = bundleContext.getProperty( Constants.FRAMEWORK_BOOTDELEGATION );
+        bootDelegation = ( bootDelegation == null ) ? "java.*" : bootDelegation + ",java.*";
+        StringTokenizer st = new StringTokenizer( bootDelegation, " ," );
+        bootPkgs = new String[st.countTokens()];
+        bootPkgWildcards = new boolean[bootPkgs.length];
+        for ( int i = 0; i < bootPkgs.length; i++ )
+        {
+            bootDelegation = st.nextToken();
+            if ( bootDelegation.endsWith( "*" ) )
+            {
+                bootPkgWildcards[i] = true;
+                bootDelegation = bootDelegation.substring( 0, bootDelegation.length() - 1 );
+            }
+            bootPkgs[i] = bootDelegation;
+        }
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    public String getTitle()
+    {
+        return LABEL;
+    }
+
+
+    protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+
+        String info = request.getPathInfo();
+        if ( info.endsWith( ".json" ) )
+        {
+            info = info.substring( 0, info.length() - 5 );
+            if ( getLabel().equals( info.substring( 1 ) ) )
+            {
+                // should return info on all bundles
+            }
+            else
+            {
+                Bundle bundle = getBundle( info );
+                if ( bundle != null )
+                {
+                    // bundle properties
+
+                    response.setContentType( "text/javascript" );
+                    response.setCharacterEncoding( "UTF-8" );
+
+                    PrintWriter pw = response.getWriter();
+                    JSONWriter jw = new JSONWriter( pw );
+                    try
+                    {
+                        performAction( jw, bundle );
+                    }
+                    catch ( JSONException je )
+                    {
+                        throw new IOException( je.toString() );
+                    }
+                }
+            }
+
+            // nothing more to do
+            return;
+        }
+
+        super.doGet( request, response );
+    }
+
+
+    protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
+    {
+        String action = req.getParameter( "action" );
+        if ( "refreshPackages".equals( action ) )
+        {
+            getPackageAdmin().refreshPackages( null );
+        }
+
+        boolean success = false;
+        Bundle bundle = getBundle( req.getPathInfo() );
+        long bundleId = -1;
+
+        if ( bundle != null )
+        {
+            bundleId = bundle.getBundleId();
+            if ( action == null )
+            {
+                success = true;
+            }
+            else if ( "start".equals( action ) )
+            {
+                // start bundle
+                success = true;
+                try
+                {
+                    bundle.start();
+                }
+                catch ( BundleException be )
+                {
+                    getLog().log( LogService.LOG_ERROR, "Cannot start", be );
+                }
+            }
+            else if ( "stop".equals( action ) )
+            {
+                // stop bundle
+                success = true;
+                try
+                {
+                    bundle.stop();
+                }
+                catch ( BundleException be )
+                {
+                    getLog().log( LogService.LOG_ERROR, "Cannot stop", be );
+                }
+            }
+            else if ( "refresh".equals( action ) )
+            {
+                // refresh bundle wiring
+                refresh( bundle );
+                success = true;
+            }
+            else if ( "uninstall".equals( action ) )
+            {
+                // uninstall bundle
+                success = true;
+                try
+                {
+                    bundle.uninstall();
+                    bundle = null; // bundle has gone !
+                }
+                catch ( BundleException be )
+                {
+                    getLog().log( LogService.LOG_ERROR, "Cannot uninstall", be );
+                }
+            }
+        }
+
+        if ( "refreshPackages".equals( action ) )
+        {
+            success = true;
+            getPackageAdmin().refreshPackages( null );
+
+            // refresh completely
+            bundle = null;
+            bundleId = -1;
+        }
+
+        if ( success )
+        {
+            // redirect or 200
+            resp.setStatus( HttpServletResponse.SC_OK );
+            JSONWriter jw = new JSONWriter( resp.getWriter() );
+            try
+            {
+                if ( bundle != null )
+                {
+                    bundleInfo( jw, bundle, true );
+                }
+                else if ( bundleId >= 0 )
+                {
+                    jw.object();
+                    jw.key( "bundleId" );
+                    jw.value( bundleId );
+                    jw.endObject();
+                }
+                else
+                {
+                    jw.object();
+                    jw.key( "reload" );
+                    jw.value( true );
+                    jw.endObject();
+                }
+            }
+            catch ( JSONException je )
+            {
+                throw new IOException( je.toString() );
+            }
+        }
+        else
+        {
+            super.doPost( req, resp );
+        }
+    }
+
+
+    private Bundle getBundle( String pathInfo )
+    {
+        // only use last part of the pathInfo
+        pathInfo = pathInfo.substring( pathInfo.lastIndexOf( '/' ) + 1 );
+
+        // assume bundle Id
+        long bundleId;
+        try
+        {
+            bundleId = Long.parseLong( pathInfo );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            bundleId = -1;
+        }
+
+        if ( bundleId >= 0 )
+        {
+            return getBundleContext().getBundle( bundleId );
+        }
+
+        return null;
+    }
+
+
+    private void renderBundleInfoCount( final PrintWriter pw, String msg, int count )
+    {
+        pw.print( "<td class='content'>" );
+        pw.print( msg );
+        pw.print( " : " );
+        pw.print( count );
+        pw.print( " Bundle" );
+        if ( count != 1 )
+            pw.print( 's' );
+        pw.println( "</td>" );
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+        Bundle bundle = getBundle( request.getPathInfo() );
+        Bundle[] bundles = ( bundle != null ) ? new Bundle[]
+            { bundle } : this.getBundles();
+
+        PrintWriter pw = response.getWriter();
+
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<script src='" + appRoot + "/res/ui/datatable.js' language='JavaScript'></script>" );
+        pw.println( "<script src='" + appRoot + "/res/ui/bundles.js' language='JavaScript'></script>" );
+
+        if ( bundles != null )
+        {
+            int active = 0, installed = 0, resolved = 0;
+            for ( int i = 0; i < bundles.length; i++ )
+            {
+                switch ( bundles[i].getState() )
+                {
+                    case Bundle.ACTIVE:
+                        active++;
+                        break;
+                    case Bundle.INSTALLED:
+                        installed++;
+                        break;
+                    case Bundle.RESOLVED:
+                        resolved++;
+                        break;
+                }
+            }
+
+            pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'><tbody>" );
+            pw.println( "<tr class='content'>" );
+            renderBundleInfoCount( pw, "Total", bundles.length );
+            renderBundleInfoCount( pw, "Active", active );
+            renderBundleInfoCount( pw, "Resolved", resolved );
+            renderBundleInfoCount( pw, "Installed", installed );
+            pw.println( "</tr></tbody></table>" );
+        }
+
+        Util.startScript( pw );
+        pw.println( "var bundleListData = " );
+        JSONWriter jw = new JSONWriter( pw );
+        try
+        {
+            jw.object();
+
+            jw.key( "startLevel" );
+            jw.value( getStartLevel().getInitialBundleStartLevel() );
+
+            jw.key( "numActions" );
+            jw.value( 4 );
+
+            boolean details = ( bundle != null );
+
+            if ( bundles != null && bundles.length > 0 )
+            {
+                Util.sort( bundles );
+
+                jw.key( "data" );
+
+                jw.array();
+
+                for ( int i = 0; i < bundles.length; i++ )
+                {
+                    bundleInfo( jw, bundles[i], details );
+                }
+
+                jw.endArray();
+
+            }
+            else
+            {
+                jw.key( "error" );
+                jw.value( "No Bundles installed currently" );
+            }
+
+            jw.endObject();
+
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+
+        pw.println( ";" );
+        pw.println( "renderBundle( bundleListData );" );
+        Util.endScript( pw );
+    }
+
+
+    private void bundleInfo( JSONWriter jw, Bundle bundle, boolean details ) throws JSONException
+    {
+        jw.object();
+        jw.key( "id" );
+        jw.value( bundle.getBundleId() );
+        jw.key( "name" );
+        jw.value( Util.getName( bundle ) );
+        jw.key( "state" );
+        jw.value( toStateString( bundle.getState() ) );
+
+        jw.key( "actions" );
+        jw.array();
+
+        if ( bundle.getBundleId() == 0 )
+        {
+            jw.value( false );
+            jw.value( false );
+            jw.value( false );
+            jw.value( false );
+        }
+        else
+        {
+            action( jw, hasStart( bundle ), "start", "Start", null );
+            action( jw, hasStop( bundle ), "stop", "Stop", null );
+            action( jw, true, "refresh", "Refresh", "Refresh Package Imports" );
+            action( jw, hasUninstall( bundle ), "uninstall", "Uninstall", null );
+        }
+        jw.endArray();
+
+        if ( details )
+        {
+            bundleDetails( jw, bundle );
+        }
+
+        jw.endObject();
+    }
+
+
+    protected Bundle[] getBundles()
+    {
+        return getBundleContext().getBundles();
+    }
+
+
+    private String toStateString( int bundleState )
+    {
+        switch ( bundleState )
+        {
+            case Bundle.INSTALLED:
+                return "Installed";
+            case Bundle.RESOLVED:
+                return "Resolved";
+            case Bundle.STARTING:
+                return "Starting";
+            case Bundle.ACTIVE:
+                return "Active";
+            case Bundle.STOPPING:
+                return "Stopping";
+            case Bundle.UNINSTALLED:
+                return "Uninstalled";
+            default:
+                return "Unknown: " + bundleState;
+        }
+    }
+
+
+    private void action( JSONWriter jw, boolean enabled, String op, String opLabel, String title ) throws JSONException
+    {
+        jw.object();
+        jw.key( "enabled" ).value( enabled );
+        jw.key( "name" ).value( opLabel );
+        jw.key( "link" ).value( op );
+        if (title != null) {
+            jw.key( "title" ).value( title );
+        }
+        jw.endObject();
+    }
+
+
+    private boolean hasStart( Bundle bundle )
+    {
+        return bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.RESOLVED;
+    }
+
+
+    private boolean hasStop( Bundle bundle )
+    {
+        return bundle.getState() == Bundle.ACTIVE;
+    }
+
+
+    private boolean hasUninstall( Bundle bundle )
+    {
+        return bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.RESOLVED
+            || bundle.getState() == Bundle.ACTIVE;
+
+    }
+
+
+    private void performAction( JSONWriter jw, Bundle bundle ) throws JSONException
+    {
+        jw.object();
+        jw.key( BUNDLE_ID );
+        jw.value( bundle.getBundleId() );
+
+        bundleDetails( jw, bundle );
+
+        jw.endObject();
+    }
+
+
+    private void bundleDetails( JSONWriter jw, Bundle bundle ) throws JSONException
+    {
+        Dictionary headers = bundle.getHeaders();
+
+        jw.key( "props" );
+        jw.array();
+        keyVal( jw, "Symbolic Name", bundle.getSymbolicName() );
+        keyVal( jw, "Version", headers.get( Constants.BUNDLE_VERSION ) );
+        keyVal( jw, "Location", bundle.getLocation() );
+        keyVal( jw, "Last Modification", new Date( bundle.getLastModified() ) );
+
+        String docUrl = ( String ) headers.get( Constants.BUNDLE_DOCURL );
+        if ( docUrl != null )
+        {
+            docUrl = "<a href=\"" + docUrl + "\" target=\"_blank\">" + docUrl + "</a>";
+            keyVal( jw, "Bundle Documentation", docUrl );
+        }
+
+        keyVal( jw, "Vendor", headers.get( Constants.BUNDLE_VENDOR ) );
+        keyVal( jw, "Copyright", headers.get( Constants.BUNDLE_COPYRIGHT ) );
+        keyVal( jw, "Description", headers.get( Constants.BUNDLE_DESCRIPTION ) );
+
+        keyVal( jw, "Start Level", getStartLevel( bundle ) );
+
+        keyVal( jw, "Bundle Classpath", headers.get( Constants.BUNDLE_CLASSPATH ) );
+
+        if ( bundle.getState() == Bundle.INSTALLED )
+        {
+            listImportExportsUnresolved( jw, bundle );
+        }
+        else
+        {
+            listImportExport( jw, bundle );
+        }
+
+        listServices( jw, bundle );
+
+        jw.endArray();
+    }
+
+
+    private Integer getStartLevel( Bundle bundle )
+    {
+        StartLevel sl = getStartLevel();
+        return ( sl != null ) ? new Integer( sl.getBundleStartLevel( bundle ) ) : null;
+    }
+
+
+    private void listImportExport( JSONWriter jw, Bundle bundle ) throws JSONException
+    {
+        PackageAdmin packageAdmin = getPackageAdmin();
+        if ( packageAdmin == null )
+        {
+            return;
+        }
+
+        Map usingBundles = new TreeMap();
+
+        ExportedPackage[] exports = packageAdmin.getExportedPackages( bundle );
+        if ( exports != null && exports.length > 0 )
+        {
+            // do alphabetical sort
+            Arrays.sort( exports, new Comparator()
+            {
+                public int compare( ExportedPackage p1, ExportedPackage p2 )
+                {
+                    return p1.getName().compareTo( p2.getName() );
+                }
+
+
+                public int compare( Object o1, Object o2 )
+                {
+                    return compare( ( ExportedPackage ) o1, ( ExportedPackage ) o2 );
+                }
+            } );
+
+            StringBuffer val = new StringBuffer();
+            for ( int j = 0; j < exports.length; j++ )
+            {
+                ExportedPackage export = exports[j];
+                printExport( val, export.getName(), export.getVersion() );
+                Bundle[] ubList = export.getImportingBundles();
+                if ( ubList != null )
+                {
+                    for ( int i = 0; i < ubList.length; i++ )
+                    {
+                        Bundle ub = ubList[i];
+                        usingBundles.put( ub.getSymbolicName(), ub );
+                    }
+                }
+            }
+            keyVal( jw, "Exported Packages", val.toString() );
+        }
+        else
+        {
+            keyVal( jw, "Exported Packages", "None" );
+        }
+
+        exports = packageAdmin.getExportedPackages( ( Bundle ) null );
+        if ( exports != null && exports.length > 0 )
+        {
+            // collect import packages first
+            final List imports = new ArrayList();
+            for ( int i = 0; i < exports.length; i++ )
+            {
+                final ExportedPackage ep = exports[i];
+                final Bundle[] importers = ep.getImportingBundles();
+                for ( int j = 0; importers != null && j < importers.length; j++ )
+                {
+                    if ( importers[j].getBundleId() == bundle.getBundleId() )
+                    {
+                        imports.add( ep );
+
+                        break;
+                    }
+                }
+            }
+            // now sort
+            StringBuffer val = new StringBuffer();
+            if ( imports.size() > 0 )
+            {
+                final ExportedPackage[] packages = ( ExportedPackage[] ) imports.toArray( new ExportedPackage[imports
+                    .size()] );
+                Arrays.sort( packages, new Comparator()
+                {
+                    public int compare( ExportedPackage p1, ExportedPackage p2 )
+                    {
+                        return p1.getName().compareTo( p2.getName() );
+                    }
+
+
+                    public int compare( Object o1, Object o2 )
+                    {
+                        return compare( ( ExportedPackage ) o1, ( ExportedPackage ) o2 );
+                    }
+                } );
+                // and finally print out
+                for ( int i = 0; i < packages.length; i++ )
+                {
+                    ExportedPackage ep = packages[i];
+                    printImport( val, ep.getName(), ep.getVersion(), false, ep );
+                }
+            }
+            else
+            {
+                // add description if there are no imports
+                val.append( "None" );
+            }
+
+            keyVal( jw, "Imported Packages", val.toString() );
+        }
+
+        if ( !usingBundles.isEmpty() )
+        {
+            StringBuffer val = new StringBuffer();
+            for ( Iterator ui = usingBundles.values().iterator(); ui.hasNext(); )
+            {
+                Bundle usingBundle = ( Bundle ) ui.next();
+                val.append( getBundleDescriptor( usingBundle ) );
+                val.append( "<br />" );
+            }
+            keyVal( jw, "Importing Bundles", val.toString() );
+        }
+    }
+
+
+    private void listImportExportsUnresolved( JSONWriter jw, Bundle bundle ) throws JSONException
+    {
+        Dictionary dict = bundle.getHeaders();
+
+        String target = ( String ) dict.get( Constants.EXPORT_PACKAGE );
+        if ( target != null )
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader( target );
+            if ( pkgs != null && pkgs.length > 0 )
+            {
+                // do alphabetical sort
+                Arrays.sort( pkgs, new Comparator()
+                {
+                    public int compare( R4Package p1, R4Package p2 )
+                    {
+                        return p1.getName().compareTo( p2.getName() );
+                    }
+
+
+                    public int compare( Object o1, Object o2 )
+                    {
+                        return compare( ( R4Package ) o1, ( R4Package ) o2 );
+                    }
+                } );
+
+                StringBuffer val = new StringBuffer();
+                for ( int i = 0; i < pkgs.length; i++ )
+                {
+                    R4Export export = new R4Export( pkgs[i] );
+                    printExport( val, export.getName(), export.getVersion() );
+                }
+                keyVal( jw, "Exported Packages", val.toString() );
+            }
+            else
+            {
+                keyVal( jw, "Exported Packages", "None" );
+            }
+        }
+
+        target = ( String ) dict.get( Constants.IMPORT_PACKAGE );
+        if ( target != null )
+        {
+            R4Package[] pkgs = R4Package.parseImportOrExportHeader( target );
+            if ( pkgs != null && pkgs.length > 0 )
+            {
+                Map imports = new TreeMap();
+                for ( int i = 0; i < pkgs.length; i++ )
+                {
+                    R4Package pkg = pkgs[i];
+                    imports.put( pkg.getName(), new R4Import( pkg ) );
+                }
+
+                // collect import packages first
+                final Map candidates = new HashMap();
+                PackageAdmin packageAdmin = getPackageAdmin();
+                if ( packageAdmin != null )
+                {
+                    ExportedPackage[] exports = packageAdmin.getExportedPackages( ( Bundle ) null );
+                    if ( exports != null && exports.length > 0 )
+                    {
+
+                        for ( int i = 0; i < exports.length; i++ )
+                        {
+                            final ExportedPackage ep = exports[i];
+
+                            R4Import imp = ( R4Import ) imports.get( ep.getName() );
+                            if ( imp != null && imp.isSatisfied( toR4Export( ep ) ) )
+                            {
+                                candidates.put( ep.getName(), ep );
+                            }
+                        }
+                    }
+                }
+
+                // now sort
+                StringBuffer val = new StringBuffer();
+                if ( imports.size() > 0 )
+                {
+                    for ( Iterator ii = imports.values().iterator(); ii.hasNext(); )
+                    {
+                        R4Import r4Import = ( R4Import ) ii.next();
+                        ExportedPackage ep = ( ExportedPackage ) candidates.get( r4Import.getName() );
+
+                        // if there is no matching export, check whether this
+                        // bundle has the package, ignore the entry in this case
+                        if ( ep == null )
+                        {
+                            String path = r4Import.getName().replace( '.', '/' );
+                            if ( bundle.getResource( path ) != null )
+                            {
+                                continue;
+                            }
+                        }
+
+                        printImport( val, r4Import.getName(), r4Import.getVersion(), r4Import.isOptional(), ep );
+                    }
+                }
+                else
+                {
+                    // add description if there are no imports
+                    val.append( "None" );
+                }
+
+                keyVal( jw, "Imported Packages", val.toString() );
+            }
+        }
+    }
+
+
+    private void listServices( JSONWriter jw, Bundle bundle ) throws JSONException
+    {
+        ServiceReference[] refs = bundle.getRegisteredServices();
+        if ( refs == null || refs.length == 0 )
+        {
+            return;
+        }
+
+        for ( int i = 0; i < refs.length; i++ )
+        {
+            String key = "Service ID " + refs[i].getProperty( Constants.SERVICE_ID );
+
+            StringBuffer val = new StringBuffer();
+
+            appendProperty( val, refs[i], Constants.OBJECTCLASS, "Types" );
+            appendProperty( val, refs[i], Constants.SERVICE_PID, "PID" );
+            appendProperty( val, refs[i], ConfigurationAdmin.SERVICE_FACTORYPID, "Factory PID" );
+            appendProperty( val, refs[i], ComponentConstants.COMPONENT_NAME, "Component Name" );
+            appendProperty( val, refs[i], ComponentConstants.COMPONENT_ID, "Component ID" );
+            appendProperty( val, refs[i], ComponentConstants.COMPONENT_FACTORY, "Component Factory" );
+            appendProperty( val, refs[i], Constants.SERVICE_DESCRIPTION, "Description" );
+            appendProperty( val, refs[i], Constants.SERVICE_VENDOR, "Vendor" );
+
+            keyVal( jw, key, val.toString() );
+        }
+    }
+
+
+    private void appendProperty( StringBuffer dest, ServiceReference ref, String name, String label )
+    {
+        Object value = ref.getProperty( name );
+        if ( value instanceof Object[] )
+        {
+            Object[] values = ( Object[] ) value;
+            dest.append( label ).append( ": " );
+            for ( int j = 0; j < values.length; j++ )
+            {
+                if ( j > 0 )
+                    dest.append( ", " );
+                dest.append( values[j] );
+            }
+            dest.append( "<br />" ); // assume HTML use of result
+        }
+        else if ( value != null )
+        {
+            dest.append( label ).append( ": " ).append( value ).append( "<br />" );
+        }
+    }
+
+
+    private void keyVal( JSONWriter jw, String key, Object value ) throws JSONException
+    {
+        if ( key != null && value != null )
+        {
+            jw.object();
+            jw.key( "key" );
+            jw.value( key );
+            jw.key( "value" );
+            jw.value( value );
+            jw.endObject();
+        }
+    }
+
+
+    private void printExport( StringBuffer val, String name, Version version )
+    {
+        boolean bootDel = isBootDelegated( name );
+        if ( bootDel )
+        {
+            val.append( "!! " );
+        }
+
+        val.append( name );
+        val.append( ",version=" );
+        val.append( version );
+
+        if ( bootDel )
+        {
+            val.append( " -- Overwritten by Boot Delegation" );
+        }
+
+        val.append( "<br />" );
+    }
+
+
+    private void printImport( StringBuffer val, String name, Version version, boolean optional, ExportedPackage export )
+    {
+        boolean bootDel = isBootDelegated( name );
+        boolean isSpan = bootDel || export == null;
+
+        if ( isSpan )
+        {
+            val.append( "!! " );
+        }
+
+        val.append( name );
+        val.append( ",version=" ).append( version );
+        val.append( " from " );
+
+        if ( export != null )
+        {
+            val.append( getBundleDescriptor( export.getExportingBundle() ) );
+
+            if ( bootDel )
+            {
+                val.append( " -- Overwritten by Boot Delegation" );
+            }
+        }
+        else
+        {
+            val.append( " -- Cannot be resolved" );
+
+            if ( optional )
+            {
+                val.append( " but is not required" );
+            }
+
+            if ( bootDel )
+            {
+                val.append( " and overwritten by Boot Delegation" );
+            }
+        }
+
+        val.append( "<br />" );
+    }
+
+
+    // returns true if the package is listed in the bootdelegation property
+    private boolean isBootDelegated( String pkgName )
+    {
+
+        // bootdelegation analysis from Apache Felix R4SearchPolicyCore
+
+        // Only consider delegation if we have a package name, since
+        // we don't want to promote the default package. The spec does
+        // not take a stand on this issue.
+        if ( pkgName.length() > 0 )
+        {
+
+            // Delegate any packages listed in the boot delegation
+            // property to the parent class loader.
+            for ( int i = 0; i < bootPkgs.length; i++ )
+            {
+
+                // A wildcarded boot delegation package will be in the form of
+                // "foo.", so if the package is wildcarded do a startsWith() or
+                // a regionMatches() to ignore the trailing "." to determine if
+                // the request should be delegated to the parent class loader.
+                // If the package is not wildcarded, then simply do an equals()
+                // test to see if the request should be delegated to the parent
+                // class loader.
+                if ( ( bootPkgWildcards[i] && ( pkgName.startsWith( bootPkgs[i] ) || bootPkgs[i].regionMatches( 0,
+                    pkgName, 0, pkgName.length() ) ) )
+                    || ( !bootPkgWildcards[i] && bootPkgs[i].equals( pkgName ) ) )
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    private R4Export toR4Export( ExportedPackage export )
+    {
+        R4Attribute version = new R4Attribute( Constants.VERSION_ATTRIBUTE, export.getVersion().toString(), false );
+        return new R4Export( export.getName(), null, new R4Attribute[]
+            { version } );
+    }
+
+
+    private String getBundleDescriptor( Bundle bundle )
+    {
+        StringBuffer val = new StringBuffer();
+        if ( bundle.getSymbolicName() != null )
+        {
+            // list the bundle name if not null
+            val.append( bundle.getSymbolicName() );
+            val.append( " (" ).append( bundle.getBundleId() );
+            val.append( ")" );
+        }
+        else if ( bundle.getLocation() != null )
+        {
+            // otherwise try the location
+            val.append( bundle.getLocation() );
+            val.append( " (" ).append( bundle.getBundleId() );
+            val.append( ")" );
+        }
+        else
+        {
+            // fallback to just the bundle id
+            // only append the bundle
+            val.append( bundle.getBundleId() );
+        }
+        return val.toString();
+    }
+
+
+    private void refresh( final Bundle bundle )
+    {
+        getPackageAdmin().refreshPackages( new Bundle[]
+            { bundle } );
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,384 @@
+/*
+ * 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.felix.webconsole.internal.core;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.service.log.LogService;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.startlevel.StartLevel;
+
+
+/**
+ * The <code>InstallAction</code> TODO
+ */
+public class InstallAction extends BundleAction
+{
+
+    public static final String NAME = "install";
+
+    public static final String LABEL = "Install or Update";
+
+    public static final String FIELD_STARTLEVEL = "bundlestartlevel";
+
+    public static final String FIELD_START = "bundlestart";
+
+    public static final String FIELD_BUNDLEFILE = "bundlefile";
+
+    // set to ask for PackageAdmin.refreshPackages() after install/update
+    public static final String FIELD_REFRESH_PACKAGES = "refreshPackages";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+
+        // get the uploaded data
+        Map params = ( Map ) request.getAttribute( AbstractWebConsolePlugin.ATTR_FILEUPLOAD );
+        if ( params == null )
+        {
+            return true;
+        }
+
+        FileItem startItem = getFileItem( params, FIELD_START, true );
+        FileItem startLevelItem = getFileItem( params, FIELD_STARTLEVEL, true );
+        FileItem bundleItem = getFileItem( params, FIELD_BUNDLEFILE, false );
+        FileItem refreshPackagesItem = getFileItem( params, FIELD_REFRESH_PACKAGES, true );
+
+        // don't care any more if not bundle item
+        if ( bundleItem == null || bundleItem.getSize() <= 0 )
+        {
+            return true;
+        }
+
+        // default values
+        // it exists
+        int startLevel = -1;
+        String bundleLocation = "inputstream:";
+
+        // convert the start level value
+        if ( startLevelItem != null )
+        {
+            try
+            {
+                startLevel = Integer.parseInt( startLevelItem.getString() );
+            }
+            catch ( NumberFormatException nfe )
+            {
+                getLog().log( LogService.LOG_INFO,
+                    "Cannot parse start level parameter " + startLevelItem + " to a number, not setting start level" );
+            }
+        }
+
+        // write the bundle data to a temporary file to ease processing
+        File tmpFile = null;
+        try
+        {
+            // copy the data to a file for better processing
+            tmpFile = File.createTempFile( "install", ".tmp" );
+            bundleItem.write( tmpFile );
+        }
+        catch ( Exception e )
+        {
+            getLog().log( LogService.LOG_ERROR, "Problem accessing uploaded bundle file", e );
+
+            // remove the tmporary file
+            if ( tmpFile != null )
+            {
+                tmpFile.delete();
+                tmpFile = null;
+            }
+        }
+
+        // install or update the bundle now
+        if ( tmpFile != null )
+        {
+            // start, refreshPackages just needs to exist, don't care for value
+            boolean start = startItem != null;
+            boolean refreshPackages = refreshPackagesItem != null;
+
+            bundleLocation = "inputstream:" + bundleItem.getName();
+            installBundle( bundleLocation, tmpFile, startLevel, start, refreshPackages );
+        }
+
+        return true;
+    }
+
+
+    private FileItem getFileItem( Map params, String name, boolean isFormField )
+    {
+        FileItem[] items = ( FileItem[] ) params.get( name );
+        if ( items != null )
+        {
+            for ( int i = 0; i < items.length; i++ )
+            {
+                if ( items[i].isFormField() == isFormField )
+                {
+                    return items[i];
+                }
+            }
+        }
+
+        // nothing found, fail
+        return null;
+    }
+
+
+    private void installBundle( String location, File bundleFile, int startLevel, boolean start, boolean refreshPackages )
+    {
+        if ( bundleFile != null )
+        {
+
+            // try to get the bundle name, fail if none
+            String symbolicName = getSymbolicName( bundleFile );
+            if ( symbolicName == null )
+            {
+                bundleFile.delete();
+                return;
+            }
+
+            // check for existing bundle first
+            Bundle updateBundle = null;
+            Bundle[] bundles = getBundleContext().getBundles();
+            for ( int i = 0; i < bundles.length; i++ )
+            {
+                if ( ( bundles[i].getLocation() != null && bundles[i].getLocation().equals( location ) )
+                    || ( bundles[i].getSymbolicName() != null && bundles[i].getSymbolicName().equals( symbolicName ) ) )
+                {
+                    updateBundle = bundles[i];
+                    break;
+                }
+            }
+
+            if ( updateBundle != null )
+            {
+
+                updateBackground( updateBundle, bundleFile, refreshPackages );
+
+            }
+            else
+            {
+
+                installBackground( bundleFile, location, startLevel, start, refreshPackages );
+
+            }
+        }
+    }
+
+
+    private String getSymbolicName( File bundleFile )
+    {
+        JarFile jar = null;
+        try
+        {
+            jar = new JarFile( bundleFile );
+            Manifest m = jar.getManifest();
+            if ( m != null )
+            {
+                return m.getMainAttributes().getValue( Constants.BUNDLE_SYMBOLICNAME );
+            }
+        }
+        catch ( IOException ioe )
+        {
+            getLog().log( LogService.LOG_WARNING, "Cannot extract symbolic name of bundle file " + bundleFile, ioe );
+        }
+        finally
+        {
+            if ( jar != null )
+            {
+                try
+                {
+                    jar.close();
+                }
+                catch ( IOException ioe )
+                {
+                    // ignore
+                }
+            }
+        }
+
+        // fall back to "not found"
+        return null;
+    }
+
+
+    private void installBackground( final File bundleFile, final String location, final int startlevel,
+        final boolean doStart, final boolean refreshPackages )
+    {
+
+        Thread t = new InstallHelper( this, "Background Install " + bundleFile, bundleFile, refreshPackages )
+        {
+
+            protected Bundle doRun( InputStream bundleStream ) throws BundleException
+            {
+                Bundle bundle = getBundleContext().installBundle( location, bundleStream );
+
+                if ( startlevel > 0 )
+                {
+                    StartLevel sl = getStartLevel();
+                    if ( sl != null )
+                    {
+                        sl.setBundleStartLevel( bundle, startlevel );
+                    }
+                }
+
+                if ( doStart )
+                {
+                    bundle.start();
+                }
+                
+                return bundle;
+            }
+        };
+
+        t.start();
+    }
+
+
+    private void updateBackground( final Bundle bundle, final File bundleFile, final boolean refreshPackages )
+    {
+        Thread t = new InstallHelper( this, "Background Update" + bundle.getSymbolicName() + " ("
+            + bundle.getBundleId() + ")", bundleFile, refreshPackages )
+        {
+
+            protected Bundle doRun( InputStream bundleStream ) throws BundleException
+            {
+                bundle.update( bundleStream );
+                return bundle;
+            }
+        };
+
+        t.start();
+    }
+
+    private static abstract class InstallHelper extends Thread
+    {
+
+        private final InstallAction installAction;
+
+        private final File bundleFile;
+
+        private final boolean refreshPackages;
+
+
+        InstallHelper( InstallAction installAction, String name, File bundleFile, boolean refreshPackages )
+        {
+            super( name );
+            setDaemon( true );
+
+            this.installAction = installAction;
+            this.bundleFile = bundleFile;
+            this.refreshPackages = refreshPackages;
+        }
+
+
+        protected abstract Bundle doRun( InputStream bundleStream ) throws BundleException;
+
+
+        public void run()
+        {
+            // wait some time for the request to settle
+            sleepSilently( 500L );
+
+            // now deploy the resolved bundles
+            InputStream bundleStream = null;
+            try
+            {
+                // we need the package admin before we call the bundle
+                // installation or update, since we might be updating
+                // our selves in which case the bundle context will be
+                // invalid by the time we want to call the update
+                PackageAdmin pa = ( refreshPackages ) ? installAction.getPackageAdmin() : null;
+
+                bundleStream = new FileInputStream( bundleFile );
+                Bundle bundle = doRun( bundleStream );
+
+                if ( pa != null )
+                {
+                    // wait for asynchronous bundle start tasks to finish
+                    sleepSilently( 2000L );
+
+                    pa.refreshPackages( new Bundle[]
+                        { bundle } );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                installAction.getLog().log( LogService.LOG_ERROR, "Cannot install or update bundle from " + bundleFile,
+                    ioe );
+            }
+            catch ( BundleException be )
+            {
+                installAction.getLog().log( LogService.LOG_ERROR, "Cannot install or update bundle from " + bundleFile,
+                    be );
+            }
+            finally
+            {
+                if ( bundleStream != null )
+                {
+                    try
+                    {
+                        bundleStream.close();
+                    }
+                    catch ( IOException ignore )
+                    {
+                    }
+                }
+                bundleFile.delete();
+            }
+        }
+
+
+        protected void sleepSilently( long msecs )
+        {
+            try
+            {
+                sleep( msecs );
+            }
+            catch ( InterruptedException ie )
+            {
+                // don't care
+            }
+        }
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/SetStartLevelAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/SetStartLevelAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/SetStartLevelAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,88 @@
+/*
+ * 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.felix.webconsole.internal.core;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Action;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.osgi.service.startlevel.StartLevel;
+
+
+/**
+ * The <code>SetStartLevelAction</code> TODO
+ */
+public class SetStartLevelAction extends BaseManagementPlugin implements Action
+{
+
+    public static final String NAME = "setStartLevel";
+
+    public static final String LABEL = "Set Start Level";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+
+        StartLevel sl = getStartLevel();
+        if ( sl != null )
+        {
+            int bundleSL = this.getParameterInt( request, "bundleStartLevel" );
+            if ( bundleSL > 0 && bundleSL != sl.getInitialBundleStartLevel() )
+            {
+                sl.setInitialBundleStartLevel( bundleSL );
+            }
+
+            int systemSL = this.getParameterInt( request, "systemStartLevel" );
+            if ( systemSL > 0 && systemSL != sl.getStartLevel() )
+            {
+                sl.setStartLevel( systemSL );
+            }
+        }
+
+        return true;
+    }
+
+
+    private int getParameterInt( HttpServletRequest request, String name )
+    {
+        try
+        {
+            return Integer.parseInt( request.getParameter( name ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            // don't care
+        }
+
+        return -1;
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,266 @@
+/*
+ * 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.felix.webconsole.internal.deppack;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.deploymentadmin.DeploymentAdmin;
+import org.osgi.service.deploymentadmin.DeploymentException;
+import org.osgi.service.deploymentadmin.DeploymentPackage;
+
+
+public class DepPackServlet extends BaseWebConsolePlugin
+{
+
+    public static final String LABEL = "deppack";
+
+    public static final String TITLE = "Deployment Packages";
+
+    private static final String ACTION_DEPLOY = "deploydp";
+
+    private static final String ACTION_UNINSTALL = "uninstalldp";
+
+    private static final String PARAMETER_PCK_FILE = "pckfile";
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public String getTitle()
+    {
+        return TITLE;
+    }
+
+
+    protected void activate( ComponentContext context )
+    {
+        this.activate( context.getBundleContext() );
+    }
+
+
+    protected void deactivate( ComponentContext context )
+    {
+        this.deactivate();
+    }
+
+
+    protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
+    {
+        // get the uploaded data
+        final String action = getParameter( req, Util.PARAM_ACTION );
+        if ( ACTION_DEPLOY.equals( action ) )
+        {
+            Map params = ( Map ) req.getAttribute( AbstractWebConsolePlugin.ATTR_FILEUPLOAD );
+            if ( params != null )
+            {
+                final FileItem pck = getFileItem( params, PARAMETER_PCK_FILE, false );
+                final DeploymentAdmin admin = ( DeploymentAdmin ) this.getService( DeploymentAdmin.class.getName() );
+                if ( admin != null )
+                {
+                    try
+                    {
+                        admin.installDeploymentPackage( pck.getInputStream() );
+
+                        final String uri = req.getRequestURI();
+                        resp.sendRedirect( uri );
+                        return;
+                    }
+                    catch ( DeploymentException e )
+                    {
+                        throw new ServletException( "Unable to deploy package.", e );
+                    }
+                }
+            }
+            throw new ServletException( "Upload file or deployment admin missing." );
+        }
+        else if ( ACTION_UNINSTALL.equals( action ) )
+        {
+            final String pckId = req.getPathInfo().substring( req.getPathInfo().lastIndexOf( '/' ) + 1 );
+            if ( pckId != null && pckId.length() > 0 )
+            {
+                final DeploymentAdmin admin = ( DeploymentAdmin ) this.getService( DeploymentAdmin.class.getName() );
+                if ( admin != null )
+                {
+                    try
+                    {
+                        final DeploymentPackage pck = admin.getDeploymentPackage( pckId );
+                        if ( pck != null )
+                        {
+                            pck.uninstall();
+                        }
+                    }
+                    catch ( DeploymentException e )
+                    {
+                        throw new ServletException( "Unable to undeploy package.", e );
+                    }
+                }
+
+            }
+
+            final PrintWriter pw = resp.getWriter();
+            pw.println( "{ \"reload\":true }" );
+            return;
+        }
+        throw new ServletException( "Unknown action: " + action );
+    }
+
+
+    private FileItem getFileItem( Map params, String name, boolean isFormField )
+    {
+        FileItem[] items = ( FileItem[] ) params.get( name );
+        if ( items != null )
+        {
+            for ( int i = 0; i < items.length; i++ )
+            {
+                if ( items[i].isFormField() == isFormField )
+                {
+                    return items[i];
+                }
+            }
+        }
+
+        // nothing found, fail
+        return null;
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+
+        PrintWriter pw = response.getWriter();
+
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<script src='" + appRoot + "/res/ui/packages.js' language='JavaScript'></script>" );
+
+        pw.println( "<h1>Deployment Admin</h1>" );
+        final DeploymentAdmin admin = ( DeploymentAdmin ) this.getService( DeploymentAdmin.class.getName() );
+        if ( admin == null )
+        {
+            pw.println( "<p><em>Deployment Admin is not installed.</em></p>" );
+            return;
+        }
+        final DeploymentPackage[] packages = admin.listDeploymentPackages();
+
+        Util.startScript( pw );
+        pw.println( "var packageListData = " );
+        JSONWriter jw = new JSONWriter( pw );
+        try
+        {
+            jw.object();
+
+            jw.key( "data" );
+
+            jw.array();
+
+            for ( int i = 0; i < packages.length; i++ )
+            {
+                packageInfoJson( jw, packages[i] );
+            }
+
+            jw.endArray();
+
+            jw.endObject();
+
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+
+        pw.println( ";" );
+        pw.println( "renderPackage( packageListData );" );
+        Util.endScript( pw );
+    }
+
+
+    private void packageInfoJson( JSONWriter jw, DeploymentPackage pack ) throws JSONException
+    {
+        jw.object();
+        jw.key( "id" );
+        jw.value( pack.getName() );
+        jw.key( "name" );
+        jw.value( pack.getName() );
+        jw.key( "state" );
+        jw.value( pack.getVersion() );
+
+        jw.key( "actions" );
+        jw.array();
+
+        jw.object();
+        jw.key( "enabled" );
+        jw.value( true );
+        jw.key( "name" );
+        jw.value( "Uninstall" );
+        jw.key( "link" );
+        jw.value( ACTION_UNINSTALL );
+        jw.endObject();
+
+        jw.endArray();
+
+        jw.key( "props" );
+        jw.array();
+        keyVal( jw, "Package Name", pack.getName() );
+        keyVal( jw, "Version", pack.getVersion() );
+
+        final StringBuffer buffer = new StringBuffer();
+        for ( int i = 0; i < pack.getBundleInfos().length; i++ )
+        {
+            buffer.append( pack.getBundleInfos()[i].getSymbolicName() );
+            buffer.append( " - " );
+            buffer.append( pack.getBundleInfos()[i].getVersion() );
+            buffer.append( "<br/>" );
+        }
+        keyVal( jw, "Bundles", buffer.toString() );
+
+        jw.endArray();
+
+        jw.endObject();
+    }
+
+
+    private void keyVal( JSONWriter jw, String key, Object value ) throws JSONException
+    {
+        if ( key != null && value != null )
+        {
+            jw.object();
+            jw.key( "key" );
+            jw.value( key );
+            jw.key( "value" );
+            jw.value( value );
+            jw.endObject();
+        }
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/AssemblyListRender.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/AssemblyListRender.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/AssemblyListRender.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,59 @@
+/*
+ * 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.felix.webconsole.internal.misc;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.webconsole.internal.core.BundlesServlet;
+import org.osgi.framework.Bundle;
+
+
+public class AssemblyListRender extends BundlesServlet
+{
+
+    public static final String NAME = "assemblyList";
+    public static final String LABEL = "Assemblies";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    protected Bundle[] getBundles()
+    {
+        Bundle[] bundles = this.getBundleContext().getBundles();
+        List assList = new ArrayList();
+        for ( int i = 0; i < bundles.length; i++ )
+        {
+            if ( bundles[i].getHeaders().get( "Assembly-Bundles" ) != null )
+            {
+                assList.add( bundles[i] );
+            }
+        }
+        return ( Bundle[] ) assList.toArray( new Bundle[assList.size()] );
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,609 @@
+/*
+ * 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.felix.webconsole.internal.misc;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.Render;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class ConfigurationRender extends BaseManagementPlugin implements Render
+{
+
+    public static final String NAME = "config";
+
+    public static final String LABEL = "Configuration Status";
+
+    private ServiceTracker cfgPrinterTracker;
+
+    private int cfgPrinterTrackerCount;
+
+    private SortedMap configurationPrinters = new TreeMap();
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public void render( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+
+        PrintWriter pw = response.getWriter();
+
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content container'>Configuration Details</th>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<pre>" );
+
+        pw.println( "*** Date: "
+            + SimpleDateFormat.getDateTimeInstance( SimpleDateFormat.LONG, SimpleDateFormat.LONG, Locale.US ).format(
+                new Date() ) );
+        pw.println();
+
+        this.printSystemProperties( pw );
+        this.printBundles( pw );
+        this.printServices( pw );
+        this.printPreferences( pw );
+        this.printConfigurations( pw );
+        this.printThreads( pw );
+
+        for ( Iterator cpi = getConfigurationPrinters().iterator(); cpi.hasNext(); )
+        {
+            printConfigurationPrinter( pw, ( ConfigurationPrinter ) cpi.next() );
+        }
+
+        pw.println( "</pre>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+        pw.println( "</table>" );
+    }
+
+
+    private Collection getConfigurationPrinters()
+    {
+        if ( cfgPrinterTracker == null )
+        {
+            cfgPrinterTracker = new ServiceTracker( getBundleContext(), ConfigurationPrinter.SERVICE, null );
+            cfgPrinterTracker.open();
+            cfgPrinterTrackerCount = -1;
+        }
+
+        if ( cfgPrinterTrackerCount != cfgPrinterTracker.getTrackingCount() )
+        {
+            SortedMap cp = new TreeMap();
+            Object[] services = cfgPrinterTracker.getServices();
+            if ( services != null )
+            {
+                for ( int i = 0; i < services.length; i++ )
+                {
+                    Object srv = services[i];
+                    ConfigurationPrinter cfgPrinter = ( ConfigurationPrinter ) srv;
+                    cp.put( cfgPrinter.getTitle(), cfgPrinter );
+                }
+            }
+            configurationPrinters = cp;
+            cfgPrinterTrackerCount = cfgPrinterTracker.getTrackingCount();
+        }
+
+        return configurationPrinters.values();
+    }
+
+
+    private void printSystemProperties( PrintWriter pw )
+    {
+        pw.println( "*** System properties:" );
+
+        Properties props = System.getProperties();
+        SortedSet keys = new TreeSet( props.keySet() );
+        for ( Iterator ki = keys.iterator(); ki.hasNext(); )
+        {
+            Object key = ki.next();
+            this.infoLine( pw, null, ( String ) key, props.get( key ) );
+        }
+
+        pw.println();
+    }
+
+
+    // This is Sling stuff, we comment it out for now
+    //    private void printRawFrameworkProperties(PrintWriter pw) {
+    //        pw.println("*** Raw Framework properties:");
+    //
+    //        File file = new File(getBundleContext().getProperty("sling.home"),
+    //            "sling.properties");
+    //        if (file.exists()) {
+    //            Properties props = new Properties();
+    //            InputStream ins = null;
+    //            try {
+    //                ins = new FileInputStream(file);
+    //                props.load(ins);
+    //            } catch (IOException ioe) {
+    //                // handle or ignore
+    //            } finally {
+    //                IOUtils.closeQuietly(ins);
+    //            }
+    //
+    //            SortedSet keys = new TreeSet(props.keySet());
+    //            for (Iterator ki = keys.iterator(); ki.hasNext();) {
+    //                Object key = ki.next();
+    //                this.infoLine(pw, null, (String) key, props.get(key));
+    //            }
+    //
+    //        } else {
+    //            pw.println("  No Framework properties in " + file);
+    //        }
+    //
+    //        pw.println();
+    //    }
+
+    private void printBundles( PrintWriter pw )
+    {
+        pw.println( "*** Bundles:" );
+        // biz.junginger.freemem.FreeMem (1.3.0) "FreeMem Eclipse Memory
+        // Monitor" [Resolved]
+
+        Bundle[] bundles = getBundleContext().getBundles();
+        SortedSet keys = new TreeSet();
+        for ( int i = 0; i < bundles.length; i++ )
+        {
+            keys.add( this.getBundleString( bundles[i], true ) );
+        }
+
+        for ( Iterator ki = keys.iterator(); ki.hasNext(); )
+        {
+            this.infoLine( pw, null, null, ki.next() );
+        }
+
+        pw.println();
+    }
+
+
+    private void printServices( PrintWriter pw )
+    {
+        pw.println( "*** Services:" );
+
+        // get the list of services sorted by service ID (ascending)
+        SortedMap srMap = new TreeMap();
+        try
+        {
+            ServiceReference[] srs = getBundleContext().getAllServiceReferences( null, null );
+            for ( int i = 0; i < srs.length; i++ )
+            {
+                srMap.put( srs[i].getProperty( Constants.SERVICE_ID ), srs[i] );
+            }
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            // should handle, for now just print nothing, actually this is not
+            // expected
+        }
+
+        for ( Iterator si = srMap.values().iterator(); si.hasNext(); )
+        {
+            ServiceReference sr = ( ServiceReference ) si.next();
+
+            this.infoLine( pw, null, String.valueOf( sr.getProperty( Constants.SERVICE_ID ) ), sr
+                .getProperty( Constants.OBJECTCLASS ) );
+            this.infoLine( pw, "  ", "Bundle", this.getBundleString( sr.getBundle(), false ) );
+
+            Bundle[] users = sr.getUsingBundles();
+            if ( users != null && users.length > 0 )
+            {
+                List userString = new ArrayList();
+                for ( int i = 0; i < users.length; i++ )
+                {
+                    userString.add( this.getBundleString( users[i], false ) );
+                }
+                this.infoLine( pw, "  ", "Using Bundles", userString );
+            }
+
+            String[] keys = sr.getPropertyKeys();
+            Arrays.sort( keys );
+            for ( int i = 0; i < keys.length; i++ )
+            {
+                if ( !Constants.SERVICE_ID.equals( keys[i] ) && !Constants.OBJECTCLASS.equals( keys[i] ) )
+                {
+                    this.infoLine( pw, "  ", keys[i], sr.getProperty( keys[i] ) );
+                }
+            }
+
+            pw.println();
+        }
+    }
+
+
+    private void printPreferences( PrintWriter pw )
+    {
+        pw.println( "*** System Preferences:" );
+
+        ServiceReference sr = getBundleContext().getServiceReference( PreferencesService.class.getName() );
+        if ( sr == null )
+        {
+            pw.println( "  Preferences Service not registered" );
+            pw.println();
+            return;
+        }
+
+        PreferencesService ps = ( PreferencesService ) getBundleContext().getService( sr );
+        try
+        {
+            this.printPreferences( pw, ps.getSystemPreferences() );
+
+            String[] users = ps.getUsers();
+            for ( int i = 0; users != null && i < users.length; i++ )
+            {
+                pw.println( "*** User Preferences " + users[i] + ":" );
+                this.printPreferences( pw, ps.getUserPreferences( users[i] ) );
+            }
+        }
+        catch ( BackingStoreException bse )
+        {
+            // todo or not :-)
+        }
+        finally
+        {
+            getBundleContext().ungetService( sr );
+        }
+    }
+
+
+    private void printPreferences( PrintWriter pw, Preferences prefs ) throws BackingStoreException
+    {
+
+        String[] children = prefs.childrenNames();
+        for ( int i = 0; i < children.length; i++ )
+        {
+            this.printPreferences( pw, prefs.node( children[i] ) );
+        }
+
+        String[] keys = prefs.keys();
+        for ( int i = 0; i < keys.length; i++ )
+        {
+            this.infoLine( pw, null, prefs.absolutePath() + "/" + keys[i], prefs.get( keys[i], null ) );
+        }
+
+        pw.println();
+    }
+
+
+    private void printConfigurations( PrintWriter pw )
+    {
+        pw.println( "*** Configurations:" );
+
+        ServiceReference sr = getBundleContext().getServiceReference( ConfigurationAdmin.class.getName() );
+        if ( sr == null )
+        {
+            pw.println( "  Configuration Admin Service not registered" );
+        }
+        else
+        {
+
+            ConfigurationAdmin ca = ( ConfigurationAdmin ) getBundleContext().getService( sr );
+            try
+            {
+                Configuration[] configs = ca.listConfigurations( null );
+                if ( configs != null && configs.length > 0 )
+                {
+                    SortedMap sm = new TreeMap();
+                    for ( int i = 0; i < configs.length; i++ )
+                    {
+                        sm.put( configs[i].getPid(), configs[i] );
+                    }
+
+                    for ( Iterator mi = sm.values().iterator(); mi.hasNext(); )
+                    {
+                        this.printConfiguration( pw, ( Configuration ) mi.next() );
+                    }
+                }
+                else
+                {
+                    pw.println( "  No Configurations available" );
+                }
+            }
+            catch ( Exception e )
+            {
+                // todo or not :-)
+            }
+            finally
+            {
+                getBundleContext().ungetService( sr );
+            }
+        }
+
+        pw.println();
+    }
+
+
+    private void printConfigurationPrinter( PrintWriter pw, ConfigurationPrinter cp )
+    {
+        pw.println( "*** " + cp.getTitle() + ":" );
+        cp.printConfiguration( pw );
+        pw.println();
+    }
+
+
+    private void printConfiguration( PrintWriter pw, Configuration config )
+    {
+        this.infoLine( pw, "", "PID", config.getPid() );
+
+        if ( config.getFactoryPid() != null )
+        {
+            this.infoLine( pw, "  ", "Factory PID", config.getFactoryPid() );
+        }
+
+        String loc = ( config.getBundleLocation() != null ) ? config.getBundleLocation() : "Unbound";
+        this.infoLine( pw, "  ", "BundleLocation", loc );
+
+        Dictionary props = config.getProperties();
+        if ( props != null )
+        {
+            SortedSet keys = new TreeSet();
+            for ( Enumeration ke = props.keys(); ke.hasMoreElements(); )
+            {
+                keys.add( ke.nextElement() );
+            }
+
+            for ( Iterator ki = keys.iterator(); ki.hasNext(); )
+            {
+                String key = ( String ) ki.next();
+                this.infoLine( pw, "  ", key, props.get( key ) );
+            }
+        }
+
+        pw.println();
+    }
+
+
+    private void infoLine( PrintWriter pw, String indent, String label, Object value )
+    {
+        if ( indent != null )
+        {
+            pw.print( indent );
+        }
+
+        if ( label != null )
+        {
+            pw.print( label );
+            pw.print( '=' );
+        }
+
+        this.printObject( pw, value );
+
+        pw.println();
+    }
+
+
+    private void printObject( PrintWriter pw, Object value )
+    {
+        if ( value == null )
+        {
+            pw.print( "null" );
+        }
+        else if ( value.getClass().isArray() )
+        {
+            this.printArray( pw, ( Object[] ) value );
+        }
+        else
+        {
+            pw.print( value );
+        }
+    }
+
+
+    private void printArray( PrintWriter pw, Object[] values )
+    {
+        pw.print( '[' );
+        if ( values != null && values.length > 0 )
+        {
+            for ( int i = 0; i < values.length; i++ )
+            {
+                if ( i > 0 )
+                {
+                    pw.print( ", " );
+                }
+                this.printObject( pw, values[i] );
+            }
+        }
+        pw.print( ']' );
+    }
+
+
+    private String getBundleString( Bundle bundle, boolean withState )
+    {
+        StringBuffer buf = new StringBuffer();
+
+        if ( bundle.getSymbolicName() != null )
+        {
+            buf.append( bundle.getSymbolicName() );
+        }
+        else if ( bundle.getLocation() != null )
+        {
+            buf.append( bundle.getLocation() );
+        }
+        else
+        {
+            buf.append( bundle.getBundleId() );
+        }
+
+        Dictionary headers = bundle.getHeaders();
+        if ( headers.get( Constants.BUNDLE_VERSION ) != null )
+        {
+            buf.append( " (" ).append( headers.get( Constants.BUNDLE_VERSION ) ).append( ')' );
+        }
+
+        if ( headers.get( Constants.BUNDLE_NAME ) != null )
+        {
+            buf.append( " \"" ).append( headers.get( Constants.BUNDLE_NAME ) ).append( '"' );
+        }
+
+        if ( withState )
+        {
+            buf.append( " [" );
+            switch ( bundle.getState() )
+            {
+                case Bundle.INSTALLED:
+                    buf.append( "Installed" );
+                    break;
+                case Bundle.RESOLVED:
+                    buf.append( "Resolved" );
+                    break;
+                case Bundle.STARTING:
+                    buf.append( "Starting" );
+                    break;
+                case Bundle.ACTIVE:
+                    buf.append( "Active" );
+                    break;
+                case Bundle.STOPPING:
+                    buf.append( "Stopping" );
+                    break;
+                case Bundle.UNINSTALLED:
+                    buf.append( "Uninstalled" );
+                    break;
+            }
+            buf.append( ']' );
+        }
+
+        return buf.toString();
+    }
+
+
+    private void printThreads( PrintWriter pw )
+    {
+        // first get the root thread group
+        ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
+        while ( rootGroup.getParent() != null )
+        {
+            rootGroup = rootGroup.getParent();
+        }
+
+        pw.println( "*** Threads:" );
+
+        printThreadGroup( pw, rootGroup );
+        
+        int numGroups = rootGroup.activeGroupCount();
+        ThreadGroup[] groups = new ThreadGroup[2 * numGroups];
+        rootGroup.enumerate( groups );
+        for ( int i = 0; i < groups.length; i++ )
+        {
+            printThreadGroup( pw, groups[i] );
+        }
+
+        pw.println();
+    }
+
+
+    private void printThreadGroup( PrintWriter pw, ThreadGroup group )
+    {
+        if ( group != null )
+        {
+            StringBuffer info = new StringBuffer();
+            info.append("ThreadGroup ").append(group.getName());
+            info.append( " [" );
+            info.append( "maxprio=" ).append( group.getMaxPriority() );
+
+            info.append( ", parent=" );
+            if ( group.getParent() != null )
+            {
+                info.append( group.getParent().getName() );
+            }
+            else
+            {
+                info.append( '-' );
+            }
+
+            info.append( ", isDaemon=" ).append( group.isDaemon() );
+            info.append( ", isDestroyed=" ).append( group.isDestroyed() );
+            info.append( ']' );
+
+            infoLine( pw, null, null, info.toString() );
+
+            int numThreads = group.activeCount();
+            Thread[] threads = new Thread[numThreads * 2];
+            group.enumerate( threads, false );
+            for ( int i = 0; i < threads.length; i++ )
+            {
+                printThread( pw, threads[i] );
+            }
+
+            pw.println();
+        }
+    }
+
+
+    private void printThread( PrintWriter pw, Thread thread )
+    {
+        if ( thread != null )
+        {
+            StringBuffer info = new StringBuffer();
+            info.append("Thread ").append( thread.getName() );
+            info.append( " [" );
+            info.append( "priority=" ).append( thread.getPriority() );
+            info.append( ", alive=" ).append( thread.isAlive() );
+            info.append( ", daemon=" ).append( thread.isDaemon() );
+            info.append( ", interrupted=" ).append( thread.isInterrupted() );
+            info.append( ", loader=" ).append( thread.getContextClassLoader() );
+            info.append( ']' );
+
+            infoLine( pw, "  ", null, info.toString() );
+        }
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/EventAdminServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/EventAdminServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/EventAdminServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,412 @@
+/*
+ * 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.felix.webconsole.internal.misc;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+
+
+public class EventAdminServlet extends BaseWebConsolePlugin implements EventHandler
+{
+
+    public static final String LABEL = "events";
+
+    public static final String TITLE = "Event Admin";
+
+    /** Number of events to be displayed. */
+    private int maxSize = 50;
+
+    private final List events = new ArrayList();
+
+    /** Custom event renderers hashed by topic. */
+    private final Map eventRenderers = new HashMap();
+
+    // the service registration of this plugin
+    private ServiceRegistration eventReceiver;
+
+
+    public EventAdminServlet()
+    {
+        eventRenderers.put( ServiceEvent.class.getName().replace( '.', '/' ) + "/", new ServiceEventInfoProvider() );
+        eventRenderers.put( BundleEvent.class.getName().replace( '.', '/' ) + "/", new BundleEventInfoProvider() );
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public String getTitle()
+    {
+        return TITLE;
+    }
+
+
+    /**
+     * Activate this component.
+     */
+    public void activate( BundleContext context )
+    {
+        super.activate( context );
+
+        this.events.clear();
+
+        // register as EventHandler service to receive events
+        Dictionary props = new Hashtable();
+        props.put( Constants.SERVICE_DESCRIPTION, "EventAdmin plugin for the Felix Web Console" );
+        props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
+        props.put( "event.topics", "*" );
+        eventReceiver = context.registerService( EventHandler.class.getName(), this, props );
+    }
+
+
+    /**
+     * Deactivate this component.
+     */
+    public void deactivate()
+    {
+        if ( eventReceiver != null )
+        {
+            eventReceiver.unregister();
+            eventReceiver = null;
+        }
+
+        this.events.clear();
+
+        super.deactivate();
+    }
+
+
+    /**
+     * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
+     */
+    public void handleEvent( Event event )
+    {
+        // we add everything which is not a log event
+        if ( !event.getTopic().startsWith( "org/osgi/service/log" ) )
+        {
+            synchronized ( this.events )
+            {
+                this.events.add( new EventInfo( event ) );
+                if ( events.size() > this.maxSize )
+                {
+                    events.remove( 0 );
+                }
+            }
+        }
+    }
+
+
+    protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
+    {
+        final String action = getParameter( req, "action" );
+        // for now we only have the clear action
+        if ( "clear".equals( action ) )
+        {
+            synchronized ( this.events )
+            {
+                this.events.clear();
+            }
+        }
+        // we always send back the json data
+        resp.setContentType( "application/json" );
+        resp.setCharacterEncoding( "utf-8" );
+
+        renderJSON( resp.getWriter() );
+    }
+
+
+    private void renderJSON( final PrintWriter pw ) throws IOException
+    {
+        List copiedEvents;
+        synchronized ( this.events )
+        {
+            copiedEvents = new ArrayList( this.events );
+        }
+        // create status line
+        final EventAdmin admin = ( EventAdmin ) this.getService( EventAdmin.class.getName() );
+        StringBuffer statusLine = new StringBuffer();
+        if ( admin == null )
+        {
+            statusLine.append( "Event Admin is not installed/running." );
+        }
+        else
+        {
+            statusLine.append( "Event Admin is running." );
+        }
+        statusLine.append( " " );
+        statusLine.append( copiedEvents.size() );
+        statusLine.append( " Events received" );
+        if ( !copiedEvents.isEmpty() )
+        {
+            statusLine.append( " since " );
+            Date d = new Date();
+            d.setTime( ( ( EventInfo ) copiedEvents.get( 0 ) ).received );
+            statusLine.append( d );
+        }
+        statusLine.append( "." );
+
+        JSONWriter jw = new JSONWriter( pw );
+        try
+        {
+            jw.object();
+
+            jw.key( "status" );
+            jw.value( statusLine );
+
+            jw.key( "data" );
+
+            jw.array();
+
+            // display list in reverse order
+            for ( int index = copiedEvents.size() - 1; index >= 0; index-- )
+            {
+                eventJson( jw, ( EventInfo ) copiedEvents.get( index ), index );
+            }
+
+            jw.endArray();
+
+            jw.endObject();
+
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+
+    }
+
+
+    protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+
+        final String info = request.getPathInfo();
+        if ( info.endsWith( ".json" ) )
+        {
+            response.setContentType( "text/javascript" );
+            response.setCharacterEncoding( "UTF-8" );
+
+            PrintWriter pw = response.getWriter();
+            this.renderJSON( pw );
+
+            // nothing more to do
+            return;
+        }
+
+        super.doGet( request, response );
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+        final PrintWriter pw = response.getWriter();
+
+        String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+        pw.println( "<script src='" + appRoot + "/res/ui/jquery-1.2.6.min.js' language='JavaScript'></script>" );
+        pw.println( "<script src='" + appRoot
+            + "/res/ui/jquery.tablesorter-2.0.3.min.js' language='JavaScript'></script>" );
+        pw.println( "<script src='" + appRoot + "/res/ui/events.js' language='JavaScript'></script>" );
+
+        Util.startScript( pw );
+        pw.println( "renderEvents( );" );
+        Util.endScript( pw );
+    }
+
+
+    private void eventJson( JSONWriter jw, EventInfo info, int index ) throws JSONException
+    {
+        final Event e = info.event;
+
+        // check if we have an info provider
+        final Iterator iter = this.eventRenderers.entrySet().iterator();
+        String infoText = null;
+        while ( infoText == null && iter.hasNext() )
+        {
+            final Map.Entry entry = ( Map.Entry ) iter.next();
+            if ( e.getTopic().startsWith( entry.getKey().toString() ) )
+            {
+                infoText = ( ( EventInfoProvider ) entry.getValue() ).getInfo( e );
+            }
+        }
+
+        jw.object();
+        jw.key( "id" );
+        jw.value( String.valueOf( index ) );
+        jw.key( "received" );
+        jw.value( info.received );
+        jw.key( "topic" );
+        jw.value( e.getTopic() );
+        if ( infoText != null )
+        {
+            jw.key( "info" );
+            jw.value( infoText );
+        }
+        jw.key( "properties" );
+        jw.object();
+        final String[] names = e.getPropertyNames();
+        if ( names != null && names.length > 0 )
+        {
+            for ( int i = 0; i < names.length; i++ )
+            {
+                jw.key( names[i] );
+                jw.value( e.getProperty( names[i] ).toString() );
+            }
+        }
+        jw.endObject();
+
+        jw.endObject();
+    }
+
+    private static final class EventInfo
+    {
+
+        public final Event event;
+        public final long received;
+
+
+        public EventInfo( final Event e )
+        {
+            this.event = e;
+            this.received = System.currentTimeMillis();
+        }
+    }
+
+    private static interface EventInfoProvider
+    {
+        String getInfo( Event event );
+    }
+
+    private static final class ServiceEventInfoProvider implements EventInfoProvider
+    {
+
+        /**
+         * @see org.apache.felix.webconsole.internal.misc.EventAdminServlet.EventInfoProvider#getInfo(org.osgi.service.event.Event)
+         */
+        public String getInfo( Event event )
+        {
+            final ServiceEvent serviceEvent = ( ServiceEvent ) event.getProperty( EventConstants.EVENT );
+            if ( serviceEvent == null )
+            {
+                return null;
+            }
+            final StringBuffer buffer = new StringBuffer( "Service " );
+            buffer.append( serviceEvent.getServiceReference().getProperty( Constants.SERVICE_ID ) );
+            buffer.append( ' ' );
+            switch ( serviceEvent.getType() )
+            {
+                case ServiceEvent.REGISTERED:
+                    buffer.append( "registered" );
+                    break;
+                case ServiceEvent.MODIFIED:
+                    buffer.append( "modified" );
+                    break;
+                case ServiceEvent.UNREGISTERING:
+                    buffer.append( "unregistering" );
+                    break;
+                default:
+                    return null; // IGNOREE
+            }
+
+            return buffer.toString();
+        }
+    }
+
+    private static final class BundleEventInfoProvider implements EventInfoProvider
+    {
+
+        /**
+         * @see org.apache.felix.webconsole.internal.misc.EventAdminServlet.EventInfoProvider#getInfo(org.osgi.service.event.Event)
+         */
+        public String getInfo( Event event )
+        {
+            final BundleEvent bundleEvent = ( BundleEvent ) event.getProperty( EventConstants.EVENT );
+            if ( bundleEvent == null )
+            {
+                return null;
+            }
+            final StringBuffer buffer = new StringBuffer( "Bundle " );
+            buffer.append( bundleEvent.getBundle().getSymbolicName() );
+            buffer.append( ' ' );
+            switch ( bundleEvent.getType() )
+            {
+                case BundleEvent.INSTALLED:
+                    buffer.append( "installed" );
+                    break;
+                case BundleEvent.RESOLVED:
+                    buffer.append( "resolved" );
+                    break;
+                case BundleEvent.STARTED:
+                    buffer.append( "started" );
+                    break;
+                case BundleEvent.STARTING:
+                    buffer.append( "starting" );
+                    break;
+                case BundleEvent.STOPPED:
+                    buffer.append( "stopped" );
+                    break;
+                case BundleEvent.STOPPING:
+                    buffer.append( "stopping" );
+                    break;
+                case BundleEvent.UNINSTALLED:
+                    buffer.append( "uninstalled" );
+                    break;
+                case BundleEvent.UNRESOLVED:
+                    buffer.append( "unresolved" );
+                    break;
+                case BundleEvent.UPDATED:
+                    buffer.append( "updated" );
+                    break;
+                default:
+                    return null; // IGNOREE
+            }
+
+            return buffer.toString();
+        }
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/LicenseServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/LicenseServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/LicenseServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,290 @@
+/*
+ * 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.felix.webconsole.internal.misc;
+
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.service.component.ComponentContext;
+
+
+/**
+ * The <code>LicenseServlet</code> TODO
+ */
+public class LicenseServlet extends AbstractWebConsolePlugin implements OsgiManagerPlugin
+{
+
+    public String getLabel()
+    {
+        return "licenses";
+    }
+
+
+    public String getTitle()
+    {
+        return "Licenses";
+    }
+
+
+    protected void renderContent( HttpServletRequest req, HttpServletResponse res ) throws IOException
+    {
+        PrintWriter pw = res.getWriter();
+
+        String appRoot = req.getContextPath() + req.getServletPath();
+        pw.println( "<link href='" + appRoot + "/res/ui/license.css' rel='stylesheet' type='text/css'>" );
+        pw.println( "<script src='" + appRoot + "/res/ui/license.js' language='JavaScript'></script>" );
+
+        Bundle[] bundles = getBundleContext().getBundles();
+        Util.sort( bundles );
+
+        Util.startScript( pw );
+        pw.print( "bundleData = " );
+        JSONWriter jw = new JSONWriter( pw );
+        try
+        {
+            jw.object();
+            for ( int i = 0; i < bundles.length; i++ )
+            {
+                Bundle bundle = bundles[i];
+                jw.key( String.valueOf( bundle.getBundleId() ) );
+
+                jw.object();
+
+                jw.key( "title" );
+                jw.value( Util.getName( bundle ) );
+
+                jw.key( "files" );
+                jw.object();
+                findResource( jw, bundle, new String[]
+                    { "README", "DISCLAIMER", "LICENSE", "NOTICE" } );
+                jw.endObject();
+
+                jw.endObject();
+            }
+            jw.endObject();
+            pw.println( ";" );
+        }
+        catch ( JSONException je )
+        {
+            throw new IOException( je.toString() );
+        }
+        Util.endScript( pw );
+
+        pw.println( "<div id='licenseContent'>" );
+
+        pw.println( "<div id='licenseLeft'>" );
+        for ( int i = 0; i < bundles.length; i++ )
+        {
+            Bundle bundle = bundles[i];
+            String link = "displayBundle( \"" + bundle.getBundleId() + "\" );";
+            pw.println( "<a href='javascript:" + link + "'>" + Util.getName( bundle ) + "</a><br />" );
+
+        }
+        pw.println( "</div>" );
+
+        pw.println( "<div id='licenseRight'>" );
+        pw.println( "<div id='licenseButtons' class='licenseButtons'>&nbsp;</div>" );
+        pw.println( "<br />" );
+        pw.println( "<div id='licenseDetails' class='licenseDetails'>&nbsp;</div>" );
+        pw.println( "</div>" );
+
+        pw.println( "<div id='licenseClear'>&nbsp;</div>" );
+
+        pw.println( "</div>" ); // licenseContent
+
+        Util.startScript( pw );
+        pw.println( "displayBundle( '0' );" );
+        Util.endScript( pw );
+    }
+
+
+    private String getName( String path )
+    {
+        return path.substring( path.lastIndexOf( '/' ) + 1 );
+    }
+
+
+    private void findResource( JSONWriter jw, Bundle bundle, String[] patterns ) throws IOException, JSONException
+    {
+        jw.key( "Bundle Resources" ); // aka the bundle files
+        jw.array();
+        for ( int i = 0; i < patterns.length; i++ )
+        {
+            Enumeration entries = bundle.findEntries( "/", patterns[i] + "*", true );
+            if ( entries != null )
+            {
+                while ( entries.hasMoreElements() )
+                {
+                    URL url = ( URL ) entries.nextElement();
+                    jw.object();
+                    jw.key( "url" );
+                    jw.value( getName( url.getPath() ) );
+                    jw.key( "data" );
+                    jw.value( readResource( url ) );
+                    jw.endObject();
+                }
+            }
+        }
+        jw.endArray();
+
+        Enumeration entries = bundle.findEntries( "/", "*.jar", true );
+        if ( entries != null )
+        {
+            while ( entries.hasMoreElements() )
+            {
+                URL url = ( URL ) entries.nextElement();
+
+                jw.key( "Embedded " + getName( url.getPath() ) );
+                jw.array();
+
+                for ( int i = 0; i < patterns.length; i++ )
+                {
+                    String pattern = ".*/" + patterns[i] + "[^/]*$";
+
+                    InputStream ins = null;
+                    try
+                    {
+                        ins = url.openStream();
+                        ZipInputStream zin = new ZipInputStream( ins );
+                        ZipEntry zentry = zin.getNextEntry();
+                        while ( zentry != null )
+                        {
+                            String name = zentry.getName();
+                            if ( !name.endsWith( "/" ) && "/".concat( name ).matches( pattern ) )
+                            {
+                                jw.object();
+                                jw.key( "url" );
+                                jw.value( getName( name ) );
+                                jw.key( "data" );
+                                jw.value( readResource( new FilterInputStream( zin )
+                                {
+                                    public void close()
+                                    {
+                                        // nothing for now
+                                    }
+                                } ) );
+                                jw.endObject();
+                            }
+
+                            zentry = zin.getNextEntry();
+                        }
+                    }
+                    finally
+                    {
+                        if ( ins != null )
+                        {
+                            try
+                            {
+                                ins.close();
+                            }
+                            catch ( IOException ignore )
+                            {
+                            }
+                        }
+                    }
+                }
+
+                jw.endArray();
+            }
+        }
+    }
+
+
+    private String getResource( Bundle bundle, String[] path ) throws IOException
+    {
+        for ( int i = 0; i < path.length; i++ )
+        {
+            URL resource = bundle.getResource( path[i] );
+            if ( resource != null )
+            {
+                return readResource( resource );
+            }
+        }
+
+        return null;
+    }
+
+
+    private String readResource( URL resource ) throws IOException
+    {
+        return readResource( resource.openStream() );
+    }
+
+
+    private String readResource( InputStream resource ) throws IOException
+    {
+        Reader r = null;
+        StringBuffer buffer = new StringBuffer();
+        try
+        {
+            char[] buf = new char[1024];
+            r = new InputStreamReader( resource, "ISO-8859-1" );
+            int num;
+            while ( ( num = r.read( buf ) ) >= 0 )
+            {
+                buffer.append( buf, 0, num );
+            }
+        }
+        finally
+        {
+            if ( r != null )
+            {
+                try
+                {
+                    r.close();
+                }
+                catch ( IOException ignore )
+                {
+                }
+            }
+        }
+        return buffer.toString();
+    }
+
+
+    protected void activate( ComponentContext context )
+    {
+        activate( context.getBundleContext() );
+    }
+
+
+    protected void deactivate( ComponentContext context )
+    {
+        deactivate();
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,214 @@
+/*
+ * 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.felix.webconsole.internal.misc;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.shell.ShellService;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class ShellServlet extends AbstractWebConsolePlugin implements OsgiManagerPlugin
+{
+    private ServiceTracker shellTracker;
+
+
+    public String getLabel()
+    {
+        return "shell";
+    }
+
+
+    public String getTitle()
+    {
+        return "Shell";
+    }
+
+
+    protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+        response.setCharacterEncoding( "utf-8" );
+        response.setContentType( "text/html" );
+
+        PrintWriter pw = response.getWriter();
+
+        try
+        {
+            String command = request.getParameter( "command" );
+
+            pw.print( "<span class=\"consolecommand\">-&gt; " );
+            pw.print( command == null ? "" : escapeHtml( command ) );
+            pw.println( "</span><br />" );
+
+            if ( command != null && !"".equals( command ) )
+            {
+                ShellService shellService = getShellService();
+                if ( shellService != null )
+                {
+                    ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+                    ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+
+                    shellService.executeCommand( command, new PrintStream( baosOut, true ), new PrintStream( baosErr,
+                        true ) );
+                    if ( baosOut.size() > 0 )
+                    {
+                        pw.print( escapeHtml( new String( baosOut.toByteArray() ) ) );
+                    }
+                    if ( baosErr.size() > 0 )
+                    {
+                        pw.print( "<span class=\"error\">" );
+                        pw.print( escapeHtml( new String( baosErr.toByteArray() ) ) );
+                        pw.println( "</span>" );
+                    }
+                }
+                else
+                {
+                    pw.print( "<span class=\"error\">" );
+                    pw.print( "Error: No shell service available<br />" );
+                    pw.println( "</span>" );
+                }
+            }
+        }
+        catch ( Throwable t )
+        {
+            pw.print( "<span class=\"error\">" );
+            StringWriter out = new StringWriter();
+            t.printStackTrace( new PrintWriter( out, true ) );
+            pw.print( escapeHtml( out.toString() ) );
+            pw.println( "</span>" );
+        }
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+        PrintWriter pw = response.getWriter();
+
+        String appRoot = request.getContextPath() + request.getServletPath();
+        pw.println( "<link href=\"" + appRoot + "/res/ui/shell.css\" rel=\"stylesheet\" type=\"text/css\" />" );
+        pw.println( "<script src=\"" + appRoot + "/res/ui/shell.js\" type=\"text/javascript\"></script>" );
+
+        pw.println( "<br />" );
+
+        pw.println( "<form name=\"shellCommandForm\" method=\"post\" action=\"" + appRoot
+            + "/shell\" title=\"Shell Command\" onsubmit=\"runShellCommand();return false;\">" );
+
+        pw.println( "<div class=\"consolebuttons\">" );
+        pw.println( "<input class=\"submit\" type=\"button\" value=\"Help\" onclick=\"executeCommand('help');\"/>" );
+        pw
+            .println( "&nbsp;&nbsp;<input class=\"submit\" type=\"button\" value=\"Clear\" onclick=\"clearConsole();\"/>" );
+        pw.println( "</div>" );
+
+        pw.println( "<div id=\"consoleframe\" class=\"consoleframe\" onclick=\"shellCommandFocus();\">" );
+        pw.println( "<div id=\"console\" class=\"console\" onclick=\"shellCommandFocus();\">" );
+        pw.println( "</div>" );
+
+        pw.println( "<span class=\"prompt\">" );
+        pw.println( "-&gt; <input type=\"text\" name=\"command\" value=\"\" class=\"command\" autocomplete=\"off\"/>" );
+        pw.println( "</span>" );
+
+        pw.println( "</div>" );
+
+        pw.println( "</form>" );
+
+        pw.println( "<script type=\"text/javascript\">" );
+        pw.println( "shellCommandFocus();" );
+        pw.println( "</script>" );
+    }
+
+
+    protected ShellService getShellService()
+    {
+        return ( ( ShellService ) shellTracker.getService() );
+    }
+
+
+    public void activate( BundleContext bundleContext )
+    {
+        super.activate( bundleContext );
+
+        shellTracker = new ServiceTracker( bundleContext, ShellService.class.getName(), null );
+        shellTracker.open();
+    }
+
+
+    public void deactivate()
+    {
+        if ( shellTracker != null )
+        {
+            shellTracker.close();
+            shellTracker = null;
+        }
+
+        super.deactivate();
+    }
+
+
+    protected String escapeHtml( String text )
+    {
+        StringBuffer sb = new StringBuffer();
+        for ( int i = 0; i < text.length(); i++ )
+        {
+            char ch = text.charAt( i );
+            if ( ch == '<' )
+            {
+                sb.append( "&lt;" );
+            }
+            else if ( ch == '>' )
+            {
+                sb.append( "&gt;" );
+            }
+            else if ( ch == '&' )
+            {
+                sb.append( "&amp;" );
+            }
+            else if ( ch == ' ' )
+            {
+                sb.append( "&nbsp;" );
+            }
+            else if ( ch == '\r' )
+            {
+            }
+            else if ( ch == '\n' )
+            {
+                sb.append( "<br />\r\n" );
+            }
+            else
+            {
+                sb.append( ch );
+            }
+        }
+
+        return ( sb.toString() );
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/AbstractObrPlugin.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,54 @@
+/*
+ * 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.felix.webconsole.internal.obr;
+
+
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class AbstractObrPlugin extends BaseManagementPlugin
+{
+
+    // track the optional installer service manually
+    private ServiceTracker repositoryAdmin;
+
+
+    protected RepositoryAdmin getRepositoryAdmin()
+    {
+        if ( repositoryAdmin == null )
+        {
+            try
+            {
+                repositoryAdmin = new ServiceTracker( getBundleContext(), RepositoryAdmin.class.getName(), null );
+                repositoryAdmin.open();
+            }
+            catch ( Throwable t )
+            {
+                // missing InstallerService class ??
+                return null;
+            }
+
+        }
+
+        return ( RepositoryAdmin ) repositoryAdmin.getService();
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,361 @@
+/*
+ * 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.felix.webconsole.internal.obr;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Render;
+import org.apache.felix.webconsole.internal.Util;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resource;
+
+
+public class BundleRepositoryRender extends AbstractObrPlugin implements Render
+{
+
+    public static final String NAME = "bundlerepo";
+
+    public static final String LABEL = "OSGi Repository";
+
+    public static final String PARAM_REPO_ID = "repositoryId";
+
+    public static final String PARAM_REPO_URL = "repositoryURL";
+
+    private static final String REPOSITORY_PROPERTY = "obr.repository.url";
+
+    private String[] repoURLs;
+
+
+    public void activate( BundleContext bundleContext )
+    {
+        super.activate( bundleContext );
+
+        String urlStr = bundleContext.getProperty( REPOSITORY_PROPERTY );
+        List urlList = new ArrayList();
+
+        if ( urlStr != null )
+        {
+            StringTokenizer st = new StringTokenizer( urlStr );
+            while ( st.hasMoreTokens() )
+            {
+                urlList.add( st.nextToken() );
+            }
+        }
+
+        this.repoURLs = ( String[] ) urlList.toArray( new String[urlList.size()] );
+    }
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public void render( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+
+        PrintWriter pw = response.getWriter();
+        this.header( pw );
+
+        RepositoryAdmin repoAdmin = getRepositoryAdmin();
+        Repository[] repos;
+        if ( repoAdmin != null )
+        {
+            repos = repoAdmin.listRepositories();
+        }
+        else
+        {
+            repos = null;
+        }
+
+        Set activeURLs = new HashSet();
+        if ( repos == null || repos.length == 0 )
+        {
+            pw.println( "<tr class='content'>" );
+            pw.println( "<td class='content' colspan='4'>No Active Repositories</td>" );
+            pw.println( "</tr>" );
+        }
+        else
+        {
+            for ( int i = 0; i < repos.length; i++ )
+            {
+                Repository repo = repos[i];
+
+                activeURLs.add( repo.getURL().toString() );
+
+                pw.println( "<tr class='content'>" );
+                pw.println( "<td class='content'>" + repo.getName() + "</td>" );
+
+                pw.print ( "<td class='content'>" );
+                pw.print ( "<a href='" + repo.getURL() + "' target='_blank' title='Show Repository " + repo.getURL()
+                    + "'>" + repo.getURL() + "</a>" );
+                pw.println( "</td>" );
+
+                pw.println( "<td class='content'>" + new Date( repo.getLastModified() ) + "</td>" );
+                pw.println( "<td class='content'>" );
+                pw.println( "<form>" );
+                pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME
+                    + "'>" );
+                pw.println( "<input type='hidden' name='" + RefreshRepoAction.PARAM_REPO + "' value='" + repo.getURL()
+                    + "'>" );
+                pw.println( "<input class='submit' type='submit' value='Refresh'>" );
+                pw.println( "<input class='submit' type='submit' name='remove' value='Remove'>" );
+                pw.println( "</form>" );
+                pw.println( "</td>" );
+                pw.println( "</tr>" );
+            }
+        }
+
+        // list any repositories configured but not active
+        for ( int i = 0; i < this.repoURLs.length; i++ )
+        {
+            if ( !activeURLs.contains( this.repoURLs[i] ) )
+            {
+                pw.println( "<tr class='content'>" );
+                pw.println( "<td class='content'>-</td>" );
+                pw.println( "<td class='content'>" + this.repoURLs[i] + "</td>" );
+                pw.println( "<td class='content'>[inactive, click Refresh to activate]</td>" );
+                pw.println( "<td class='content'>" );
+                pw.println( "<form>" );
+                pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME
+                    + "'>" );
+                pw.println( "<input type='hidden' name='" + RefreshRepoAction.PARAM_REPO + "' value='"
+                    + this.repoURLs[i] + "'>" );
+                pw.println( "<input class='submit' type='submit' value='Refresh'>" );
+                pw.println( "</form>" );
+                pw.println( "</td>" );
+                pw.println( "</tr>" );
+            }
+        }
+
+        // entry of a new repository
+        pw.println( "<form>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>&nbsp;</td>" );
+        pw.println( "<td class='content' colspan='2'>" );
+        pw.println( "  <input class='input' type='text' name='" + RefreshRepoAction.PARAM_REPO + "' value='' size='80'>" );
+        pw.println( "</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + RefreshRepoAction.NAME + "'>" );
+        pw.println( "<input class='submit' type='submit' value='Add'>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+        pw.println( "</form>" );
+
+        this.footer( pw );
+
+        this.listResources( pw, repos );
+    }
+
+
+    private void header( PrintWriter pw )
+    {
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content container' colspan='4'>Bundle Repositories</th>" );
+        pw.println( "</tr>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content'>Name</th>" );
+        pw.println( "<th class='content'>URL</th>" );
+        pw.println( "<th class='content'>Last Modification Time</th>" );
+        pw.println( "<th class='content'>&nbsp;</th>" );
+        pw.println( "</tr>" );
+    }
+
+
+    private void footer( PrintWriter pw )
+    {
+        pw.println( "</table>" );
+    }
+
+
+    private void resourcesHeader( PrintWriter pw, boolean doForm )
+    {
+
+        if ( doForm )
+        {
+            pw.println( "<form method='post'>" );
+            pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + InstallFromRepoAction.NAME
+                + "'>" );
+        }
+
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content container' colspan='3'>Available Resources</th>" );
+        pw.println( "</tr>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content'>Deploy</th>" );
+        pw.println( "<th class='content'>Name</th>" );
+        pw.println( "<th class='content'>Version</th>" );
+        pw.println( "</tr>" );
+    }
+
+
+    private void listResources( PrintWriter pw, Repository[] repos )
+    {
+
+        Map bundles = this.getBundles();
+
+        SortedSet resSet = new TreeSet( new Comparator()
+        {
+            public int compare( Object arg0, Object arg1 )
+            {
+                return compare( ( Resource ) arg0, ( Resource ) arg1 );
+            }
+
+
+            public int compare( Resource o1, Resource o2 )
+            {
+                if ( o1 == o2 || o1.equals( o2 ) )
+                {
+                    return 0;
+                }
+
+                if ( o1.getPresentationName().equals( o2.getPresentationName() ) )
+                {
+                    return o1.getVersion().compareTo( o2.getVersion() );
+                }
+
+                return o1.getPresentationName().compareTo( o2.getPresentationName() );
+            }
+        } );
+
+        for ( int i = 0; i < repos.length; i++ )
+        {
+            Resource[] resources = repos[i].getResources();
+            for ( int j = 0; resources != null && j < resources.length; j++ )
+            {
+                Resource res = resources[j];
+                Version ver = ( Version ) bundles.get( res.getSymbolicName() );
+                if ( ver == null || ver.compareTo( res.getVersion() ) < 0 )
+                {
+                    resSet.add( res );
+                }
+            }
+        }
+
+        this.resourcesHeader( pw, !resSet.isEmpty() );
+
+        for ( Iterator ri = resSet.iterator(); ri.hasNext(); )
+        {
+            Resource resource = ( Resource ) ri.next();
+            this.printResource( pw, resource );
+        }
+
+        this.resourcesFooter( pw, !resSet.isEmpty() );
+    }
+
+
+    private void printResource( PrintWriter pw, Resource res )
+    {
+        pw.println( "<tr class='content'>" );
+        pw
+            .println( "<td class='content' valign='top' align='center'><input class='checkradio' type='checkbox' name='bundle' value='"
+                + res.getSymbolicName() + "," + res.getVersion() + "'></td>" );
+
+        // check whether the resource is an assembly (category name)
+        String style = "";
+        String[] cat = res.getCategories();
+        for ( int i = 0; cat != null && i < cat.length; i++ )
+        {
+            if ( "assembly".equals( cat[i] ) )
+            {
+                style = "style='font-weight:bold'";
+            }
+        }
+        pw.println( "<td class='content' " + style + ">" + res.getPresentationName() + " (" + res.getSymbolicName()
+            + ")</td>" );
+        pw.println( "<td class='content' " + style + " valign='top'>" + res.getVersion() + "</td>" );
+
+        pw.println( "</tr>" );
+    }
+
+
+    private void resourcesButtons( PrintWriter pw )
+    {
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>&nbsp;</td>" );
+        pw.println( "<td class='content' colspan='2'>" );
+        pw.println( "<input class='submit' style='width:auto' type='submit' name='deploy' value='Deploy Selected'>" );
+        pw.println( "&nbsp;&nbsp;&nbsp;" );
+        pw
+            .println( "<input class='submit' style='width:auto' type='submit' name='deploystart' value='Deploy and Start Selected'>" );
+        pw.println( "</td></tr>" );
+    }
+
+
+    private void resourcesFooter( PrintWriter pw, boolean doForm )
+    {
+        if ( doForm )
+        {
+            this.resourcesButtons( pw );
+        }
+        pw.println( "</table></form>" );
+    }
+
+
+    private Map getBundles()
+    {
+        Map bundles = new HashMap();
+
+        Bundle[] installed = getBundleContext().getBundles();
+        for ( int i = 0; i < installed.length; i++ )
+        {
+            String ver = ( String ) installed[i].getHeaders().get( Constants.BUNDLE_VERSION );
+            Version bundleVersion = Version.parseVersion( ver );
+
+            // assume one bundle instance per symbolic name !!
+            // only add if there is a symbolic name !
+            if ( installed[i].getSymbolicName() != null )
+            {
+                bundles.put( installed[i].getSymbolicName(), bundleVersion );
+            }
+        }
+
+        return bundles;
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,104 @@
+/*
+ * 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.felix.webconsole.internal.obr;
+
+
+import org.apache.felix.webconsole.internal.Logger;
+import org.osgi.service.log.LogService;
+import org.osgi.service.obr.Requirement;
+import org.osgi.service.obr.Resolver;
+import org.osgi.service.obr.Resource;
+
+
+public class DeployerThread extends Thread
+{
+
+    private final Resolver obrResolver;
+
+    private final Logger logger;
+
+    private final boolean startBundles;
+
+
+    public DeployerThread( Resolver obrResolver, Logger logger, boolean startBundles )
+    {
+        this( obrResolver, logger, startBundles, "OBR Bundle Deployer" );
+    }
+
+
+    public DeployerThread( Resolver obrResolver, Logger logger, boolean startBundles, String name )
+    {
+        super( name );
+        this.obrResolver = obrResolver;
+        this.logger = logger;
+        this.startBundles = startBundles;
+    }
+
+
+    public void run()
+    {
+        try
+        {
+            if ( obrResolver.resolve() )
+            {
+
+                logResource( "Installing Requested Resources", obrResolver.getAddedResources() );
+                logResource( "Installing Required Resources", obrResolver.getRequiredResources() );
+                logResource( "Installing Optional Resources", obrResolver.getOptionalResources() );
+
+                obrResolver.deploy( startBundles );
+            }
+            else
+            {
+                logRequirements( "Cannot Install requested bundles due to unsatisfied requirements", obrResolver
+                    .getUnsatisfiedRequirements() );
+            }
+        }
+        catch ( Exception ie )
+        {
+            Throwable cause = ( ie.getCause() != null ) ? ie.getCause() : ie;
+            logger.log( LogService.LOG_ERROR, "Cannot install bundles", cause );
+        }
+    }
+
+
+    private void logResource( String message, Resource[] res )
+    {
+        if ( res != null && res.length > 0 )
+        {
+            logger.log( LogService.LOG_INFO, message );
+            for ( int i = 0; i < res.length; i++ )
+            {
+                logger.log( LogService.LOG_INFO, "  " + i + ": " + res[i].getSymbolicName() + ", "
+                    + res[i].getVersion() );
+            }
+        }
+    }
+
+
+    private void logRequirements( String message, Requirement[] req )
+    {
+        logger.log( LogService.LOG_ERROR, message );
+        for ( int i = 0; req != null && i < req.length; i++ )
+        {
+            logger.log( LogService.LOG_ERROR, "  " + i + ": " + req[i].getName() + " (" + req[i].getComment() + ")" );
+        }
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/InstallFromRepoAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,107 @@
+/*
+ * 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.felix.webconsole.internal.obr;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Action;
+import org.osgi.service.log.LogService;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resolver;
+import org.osgi.service.obr.Resource;
+
+
+public class InstallFromRepoAction extends AbstractObrPlugin implements Action
+{
+
+    public static final String NAME = "installFromOBR";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.sling.manager.web.internal.Action#performAction(javax.servlet.http.HttpServletRequest,
+     *      javax.servlet.http.HttpServletResponse)
+     */
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+
+        // check whether we have to do something
+        String[] bundles = request.getParameterValues( "bundle" );
+        if ( bundles == null || bundles.length == 0 )
+        {
+            getLog().log( LogService.LOG_INFO, "No resources to deploy" );
+            return true;
+        }
+
+        RepositoryAdmin repoAdmin = getRepositoryAdmin();
+        if ( repoAdmin != null )
+        {
+
+            Resolver resolver = repoAdmin.resolver();
+
+            // prepare the deployment
+            for ( int i = 0; i < bundles.length; i++ )
+            {
+                String bundle = bundles[i];
+                int comma = bundle.indexOf( ',' );
+                String name = ( comma > 0 ) ? bundle.substring( 0, comma ) : bundle;
+                String version = ( comma < bundle.length() - 1 ) ? bundle.substring( comma + 1 ) : null;
+
+                if ( name.length() > 0 )
+                {
+                    // no name, ignore this one
+                    if ( version == null )
+                    {
+                        version = "*";
+                    }
+
+                    String filter = "(&(symbolicname=" + name + ")(version=" + version + "))";
+                    Resource[] resources = repoAdmin.discoverResources( filter );
+                    if ( resources != null && resources.length > 0 )
+                    {
+                        resolver.add( resources[0] );
+                    }
+                }
+
+            }
+
+            // check whether the "deploystart" button was clicked
+            boolean start = request.getParameter( "deploystart" ) != null;
+
+            DeployerThread dt = new DeployerThread( resolver, getLog(), start );
+            dt.start();
+        }
+
+        // redirect to bundle list
+        return true;
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/RefreshRepoAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,130 @@
+/*
+ * 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.felix.webconsole.internal.obr;
+
+
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Action;
+import org.osgi.service.obr.Repository;
+import org.osgi.service.obr.RepositoryAdmin;
+
+
+public class RefreshRepoAction extends AbstractObrPlugin implements Action
+{
+
+    public static final String NAME = "refreshOBR";
+
+    public static final String PARAM_REPO = "repository";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+
+        RepositoryAdmin repoAdmin = getRepositoryAdmin();
+        if ( repoAdmin != null )
+        {
+            String repositoryURL = request.getParameter( "repository" );
+            Repository[] repos = repoAdmin.listRepositories();
+            Repository repo = this.getRepository( repos, repositoryURL );
+
+            URL repoURL = null;
+            if ( repo != null )
+            {
+                repoURL = repo.getURL();
+            }
+            else
+            {
+                try
+                {
+                    repoURL = new URL( repositoryURL );
+                }
+                catch ( Throwable t )
+                {
+                    // don't care, just ignore
+                }
+            }
+
+            // log.log(LogService.LOG_DEBUG, "Refreshing " + repo.getURL());
+            if ( repoURL != null )
+            {
+                if ( request.getParameter( "remove" ) != null )
+                {
+                    try
+                    {
+                        repoAdmin.removeRepository( repoURL );
+                    }
+                    catch ( Exception e )
+                    {
+                        // TODO: log.log(LogService.LOG_ERROR, "Cannot refresh
+                        // Repository " + repo.getURL());
+                    }
+                }
+                else
+                {
+                    try
+                    {
+                        repoAdmin.addRepository( repoURL );
+                    }
+                    catch ( Exception e )
+                    {
+                        // TODO: log.log(LogService.LOG_ERROR, "Cannot refresh
+                        // Repository " + repo.getURL());
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    // ---------- internal -----------------------------------------------------
+
+    private Repository getRepository( Repository[] repos, String repositoryUrl )
+    {
+        if ( repositoryUrl == null || repositoryUrl.length() == 0 )
+        {
+            return null;
+        }
+
+        for ( int i = 0; i < repos.length; i++ )
+        {
+            if ( repositoryUrl.equals( repos[i].getURL().toString() ) )
+            {
+                return repos[i];
+            }
+        }
+
+        return null;
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,59 @@
+/*
+ * 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.felix.webconsole.internal.servlet;
+
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+
+
+class ConfigurationListener implements ManagedService
+{
+
+    private final OsgiManager osgiManager;
+
+
+    static ServiceRegistration create( OsgiManager osgiManager )
+    {
+        ConfigurationListener cl = new ConfigurationListener( osgiManager );
+
+        Dictionary props = new Hashtable();
+        props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
+        props.put( Constants.SERVICE_DESCRIPTION, "OSGi Management Console Configuration Receiver" );
+        props.put( Constants.SERVICE_PID, osgiManager.getClass().getName() );
+
+        return osgiManager.getBundleContext().registerService( ManagedService.class.getName(), cl, props );
+    }
+
+
+    private ConfigurationListener( OsgiManager osgiManager )
+    {
+        this.osgiManager = osgiManager;
+    }
+
+
+    public void updated( Dictionary config )
+    {
+        osgiManager.updateConfiguration( config );
+    }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,764 @@
+/*
+ * 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.felix.webconsole.internal.servlet;
+
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.GenericServlet;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.Action;
+import org.apache.felix.webconsole.Render;
+import org.apache.felix.webconsole.WebConsoleConstants;
+import org.apache.felix.webconsole.internal.Logger;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.core.BundlesServlet;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+/**
+ * The <code>OSGi Manager</code> TODO
+ *
+ * @scr.component ds="no" label="%manager.name"
+ *                description="%manager.description"
+ */
+public class OsgiManager extends GenericServlet
+{
+
+    /** Pseudo class version ID to keep the IDE quite. */
+    private static final long serialVersionUID = 1L;
+
+    public static final String ATTR_LABEL_MAP = OsgiManager.class.getName() + ".labelMap";
+
+    public static final String ATTR_APP_ROOT = OsgiManager.class.getName() + ".appRoot";
+
+    /**
+     * The name and value of a parameter which will prevent redirection to a
+     * render after the action has been executed (value is "_noredir_"). This
+     * may be used by programmatic action submissions.
+     */
+    public static final String PARAM_NO_REDIRECT_AFTER_ACTION = "_noredir_";
+
+    /**
+     * @scr.property valueRef="DEFAULT_MANAGER_ROOT"
+     */
+    private static final String PROP_MANAGER_ROOT = "manager.root";
+
+    /**
+     * @scr.property valueRef="DEFAULT_PAGE"
+     */
+    private static final String PROP_DEFAULT_RENDER = "default.render";
+
+    /**
+     * @scr.property valueRef="DEFAULT_REALM"
+     */
+    private static final String PROP_REALM = "realm";
+
+    /**
+     * @scr.property valueRef="DEFAULT_USER_NAME"
+     */
+    private static final String PROP_USER_NAME = "username";
+
+    /**
+     * @scr.property valueRef="DEFAULT_PASSWORD"
+     */
+    private static final String PROP_PASSWORD = "password";
+
+    private static final String DEFAULT_PAGE = BundlesServlet.NAME;
+
+    private static final String DEFAULT_REALM = "OSGi Management Console";
+
+    private static final String DEFAULT_USER_NAME = "admin";
+
+    private static final String DEFAULT_PASSWORD = "admin";
+
+    /**
+     * The default value for the {@link #PROP_MANAGER_ROOT} configuration
+     * property (value is "/system/console").
+     */
+    private static final String DEFAULT_MANAGER_ROOT = "/jboss-osgi";
+
+    private static final String[] PLUGIN_CLASSES =
+        { "org.apache.felix.webconsole.internal.compendium.ComponentConfigurationPrinter",
+            "org.apache.felix.webconsole.internal.compendium.ComponentsServlet",
+            "org.apache.felix.webconsole.internal.compendium.ConfigManager",
+            "org.apache.felix.webconsole.internal.core.BundlesServlet",
+            "org.apache.felix.webconsole.internal.core.InstallAction",
+            "org.apache.felix.webconsole.internal.core.SetStartLevelAction",
+            "org.apache.felix.webconsole.internal.deppack.DepPackServlet",
+            "org.apache.felix.webconsole.internal.misc.EventAdminServlet",
+            "org.apache.felix.webconsole.internal.misc.LicenseServlet",
+            "org.apache.felix.webconsole.internal.misc.ConfigurationRender",
+            "org.apache.felix.webconsole.internal.misc.ShellServlet",
+            "org.apache.felix.webconsole.internal.obr.BundleRepositoryRender",
+            "org.apache.felix.webconsole.internal.obr.InstallFromRepoAction",
+            "org.apache.felix.webconsole.internal.obr.RefreshRepoAction",
+            "org.apache.felix.webconsole.internal.system.GCAction",
+            "org.apache.felix.webconsole.internal.system.ShutdownAction",
+            "org.apache.felix.webconsole.internal.system.ShutdownRender",
+            "org.apache.felix.webconsole.internal.system.VMStatRender", };
+
+    private BundleContext bundleContext;
+
+    private Logger log;
+
+    private ServiceTracker httpServiceTracker;
+
+    private HttpService httpService;
+
+    private ServiceTracker operationsTracker;
+
+    private ServiceTracker rendersTracker;
+
+    private ServiceTracker pluginsTracker;
+
+    private ServiceRegistration configurationListener;
+
+    private Map plugins = new HashMap();
+
+    private Map labelMap = new HashMap();
+
+    private Map operations = new HashMap();
+
+    private Servlet defaultRender;
+
+    private String defaultRenderName;
+
+    private String webManagerRoot;
+
+    private Dictionary configuration;
+
+
+    public OsgiManager( BundleContext bundleContext )
+    {
+
+        this.bundleContext = bundleContext;
+        this.log = new Logger( bundleContext );
+
+        updateConfiguration( null );
+
+        try
+        {
+            this.configurationListener = ConfigurationListener.create( this );
+        }
+        catch ( Throwable t )
+        {
+            // might be caused by CM not available
+        }
+
+        // get at the HttpService first, this should initialize
+        // the OSGi Manager and start the initial setup
+        httpServiceTracker = new HttpServiceTracker( this );
+        httpServiceTracker.open();
+    }
+
+    
+    public void dispose()
+    {
+        // now drop the HttpService and continue with further destroyals
+        if ( httpServiceTracker != null )
+        {
+            httpServiceTracker.close();
+            httpServiceTracker = null;
+        }
+
+        // stop listening for configuration
+        if ( configurationListener != null )
+        {
+            configurationListener.unregister();
+            configurationListener = null;
+        }
+
+        if ( log != null )
+        {
+            log.dispose();
+        }
+
+        this.defaultRender = null;
+        this.bundleContext = null;
+    }
+
+
+    //---------- Servlet API
+    
+    public void init()
+    {
+        // base class initialization not needed, since the GenericServlet.init
+        // is an empty method
+
+        // setup the included plugins
+        ClassLoader classLoader = getClass().getClassLoader();
+        for ( int i = 0; i < PLUGIN_CLASSES.length; i++ )
+        {
+            String pluginClassName = PLUGIN_CLASSES[i];
+            try
+            {
+                Class pluginClass = classLoader.loadClass( pluginClassName );
+                Object plugin = pluginClass.newInstance();
+                if ( plugin instanceof OsgiManagerPlugin )
+                {
+                    ( ( OsgiManagerPlugin ) plugin ).activate( bundleContext );
+                }
+                if ( plugin instanceof AbstractWebConsolePlugin )
+                {
+                    AbstractWebConsolePlugin amp = ( AbstractWebConsolePlugin ) plugin;
+                    bindServlet( amp.getLabel(), amp );
+                }
+                else
+                {
+                    if ( plugin instanceof Action )
+                    {
+                        bindOperation( ( Action ) plugin );
+                    }
+                    if ( plugin instanceof Render )
+                    {
+                        bindRender( ( Render ) plugin );
+                    }
+                }
+            }
+            catch ( Throwable t )
+            {
+                log( "Failed to instantiate plugin " + pluginClassName + ". Reason: " + t );
+            }
+        }
+
+        // start tracking external plugins after setting up our own plugins
+        operationsTracker = new OperationServiceTracker( this );
+        operationsTracker.open();
+        rendersTracker = new RenderServiceTracker( this );
+        rendersTracker.open();
+        pluginsTracker = new PluginServiceTracker( this );
+        pluginsTracker.open();
+    }
+    
+    public void service( ServletRequest req, ServletResponse res ) throws ServletException, IOException
+    {
+
+        HttpServletRequest request = ( HttpServletRequest ) req;
+        HttpServletResponse response = ( HttpServletResponse ) res;
+
+        // handle the request action, terminate if done
+        if ( this.handleAction( request, response ) )
+        {
+            return;
+        }
+
+        // check whether we are not at .../{webManagerRoot}
+        if ( request.getPathInfo() == null || request.getPathInfo().equals( "/" ) )
+        {
+            String path = request.getRequestURI();
+            if ( !path.endsWith( "/" ) )
+            {
+                path = path.concat( "/" );
+            }
+            path = path.concat( defaultRenderName );
+            response.sendRedirect( path );
+            return;
+        }
+
+        String label = request.getPathInfo();
+        int slash = label.indexOf( "/", 1 );
+        if ( slash < 2 )
+        {
+            slash = label.length();
+        }
+
+        label = label.substring( 1, slash );
+        Servlet plugin = ( Servlet ) plugins.get( label );
+        if ( plugin != null )
+        {
+            req.setAttribute( ATTR_LABEL_MAP, labelMap );
+            req.setAttribute( ATTR_APP_ROOT, request.getContextPath() + request.getServletPath() );
+
+            plugin.service( req, res );
+        }
+        else
+        {
+            response.sendError( HttpServletResponse.SC_NOT_FOUND );
+            return;
+        }
+
+    }
+    
+    public void destroy()
+    {
+        // base class destroy not needed, since the GenericServlet.destroy
+        // is an empty method
+        
+        // stop listening for plugins
+        if ( operationsTracker != null )
+        {
+            operationsTracker.close();
+            operationsTracker = null;
+        }
+        if ( rendersTracker != null )
+        {
+            rendersTracker.close();
+            rendersTracker = null;
+        }
+        if ( pluginsTracker != null )
+        {
+            pluginsTracker.close();
+            pluginsTracker = null;
+        }
+
+        // deactivate any remaining plugins
+        for ( Iterator pi = plugins.values().iterator(); pi.hasNext(); )
+        {
+            Object plugin = pi.next();
+            if ( plugin instanceof OsgiManagerPlugin )
+            {
+                ( ( OsgiManagerPlugin ) plugin ).deactivate();
+            }
+        }
+
+        // simply remove all operations, we should not be used anymore
+        this.plugins.clear();
+        this.labelMap.clear();
+        this.operations.clear();
+    }
+
+    //---------- internal
+
+    protected boolean handleAction( HttpServletRequest req, HttpServletResponse resp ) throws IOException
+    {
+        // check action
+        String actionName = AbstractWebConsolePlugin.getParameter( req, Util.PARAM_ACTION );
+        if ( actionName != null )
+        {
+            Action action = ( Action ) this.operations.get( actionName );
+            if ( action != null )
+            {
+                boolean redirect = true;
+                try
+                {
+                    redirect = action.performAction( req, resp );
+                }
+                catch ( IOException ioe )
+                {
+                    this.log( ioe.getMessage(), ioe );
+                }
+                catch ( ServletException se )
+                {
+                    this.log( se.getMessage(), se.getRootCause() );
+                }
+
+                // maybe overwrite redirect
+                if ( PARAM_NO_REDIRECT_AFTER_ACTION.equals( AbstractWebConsolePlugin.getParameter( req,
+                    PARAM_NO_REDIRECT_AFTER_ACTION ) ) )
+                {
+                    resp.setStatus( HttpServletResponse.SC_OK );
+                    resp.setContentType( "text/html" );
+                    resp.getWriter().println( "Ok" );
+                    return true;
+                }
+
+                if ( redirect )
+                {
+                    String uri = req.getRequestURI();
+                    // Object pars =
+                    // req.getAttribute(Action.ATTR_REDIRECT_PARAMETERS);
+                    // if (pars instanceof String) {
+                    // uri += "?" + pars;
+                    // }
+                    resp.sendRedirect( uri );
+                }
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    BundleContext getBundleContext()
+    {
+        return bundleContext;
+    }
+
+    private static class HttpServiceTracker extends ServiceTracker
+    {
+
+        private final OsgiManager osgiManager;
+
+
+        HttpServiceTracker( OsgiManager osgiManager )
+        {
+            super( osgiManager.getBundleContext(), HttpService.class.getName(), null );
+            this.osgiManager = osgiManager;
+        }
+
+
+        public Object addingService( ServiceReference reference )
+        {
+            Object operation = super.addingService( reference );
+            if ( operation instanceof HttpService )
+            {
+                osgiManager.bindHttpService( ( HttpService ) operation );
+            }
+            return operation;
+        }
+
+
+        public void removedService( ServiceReference reference, Object service )
+        {
+            if ( service instanceof HttpService )
+            {
+                osgiManager.unbindHttpService( ( HttpService ) service );
+            }
+
+            super.removedService( reference, service );
+        }
+    }
+
+    private static class OperationServiceTracker extends ServiceTracker
+    {
+
+        private final OsgiManager osgiManager;
+
+
+        OperationServiceTracker( OsgiManager osgiManager )
+        {
+            super( osgiManager.getBundleContext(), Action.SERVICE, null );
+            this.osgiManager = osgiManager;
+        }
+
+
+        public Object addingService( ServiceReference reference )
+        {
+            Object operation = super.addingService( reference );
+            if ( operation instanceof Action )
+            {
+                osgiManager.bindOperation( ( Action ) operation );
+            }
+            return operation;
+        }
+
+
+        public void removedService( ServiceReference reference, Object service )
+        {
+            if ( service instanceof Action )
+            {
+                osgiManager.bindOperation( ( Action ) service );
+            }
+
+            super.removedService( reference, service );
+        }
+    }
+
+    private static class RenderServiceTracker extends ServiceTracker
+    {
+
+        private final OsgiManager osgiManager;
+
+
+        RenderServiceTracker( OsgiManager osgiManager )
+        {
+            super( osgiManager.getBundleContext(), Render.SERVICE, null );
+            this.osgiManager = osgiManager;
+        }
+
+
+        public Object addingService( ServiceReference reference )
+        {
+            Object operation = super.addingService( reference );
+            if ( operation instanceof Render )
+            {
+                osgiManager.bindRender( ( Render ) operation );
+            }
+            return operation;
+        }
+
+
+        public void removedService( ServiceReference reference, Object service )
+        {
+            if ( service instanceof Render )
+            {
+                osgiManager.bindRender( ( Render ) service );
+            }
+
+            super.removedService( reference, service );
+        }
+    }
+
+    private static class PluginServiceTracker extends ServiceTracker
+    {
+
+        private final OsgiManager osgiManager;
+
+
+        PluginServiceTracker( OsgiManager osgiManager )
+        {
+            super( osgiManager.getBundleContext(), WebConsoleConstants.SERVICE_NAME, null );
+            this.osgiManager = osgiManager;
+        }
+
+
+        public Object addingService( ServiceReference reference )
+        {
+            Object label = reference.getProperty( WebConsoleConstants.PLUGIN_LABEL );
+            if ( label instanceof String )
+            {
+                Object operation = super.addingService( reference );
+                if ( operation instanceof Servlet )
+                {
+                    // TODO: check reference properties !!
+                    osgiManager.bindServlet( ( String ) label, ( Servlet ) operation );
+                }
+                return operation;
+            }
+
+            return null;
+        }
+
+
+        public void removedService( ServiceReference reference, Object service )
+        {
+            Object label = reference.getProperty( WebConsoleConstants.PLUGIN_LABEL );
+            if ( label instanceof String )
+            {
+                // TODO: check reference properties !!
+                osgiManager.unbindServlet( ( String ) label );
+            }
+
+            super.removedService( reference, service );
+        }
+    }
+
+
+    protected synchronized void bindHttpService( HttpService httpService )
+    {
+        Dictionary config = getConfiguration();
+
+        // get authentication details
+        String realm = this.getProperty( config, PROP_REALM, DEFAULT_REALM );
+        String userId = this.getProperty( config, PROP_USER_NAME, DEFAULT_USER_NAME );
+        String password = this.getProperty( config, PROP_PASSWORD, DEFAULT_PASSWORD );
+
+        // register the servlet and resources
+        try
+        {
+            HttpContext httpContext = new OsgiManagerHttpContext( httpService, realm, userId, password );
+
+            Dictionary servletConfig = toStringConfig( config );
+
+            httpService.registerServlet( this.webManagerRoot, this, servletConfig, httpContext );
+            httpService.registerResources( this.webManagerRoot + "/res", "/res", httpContext );
+
+        }
+        catch ( Exception e )
+        {
+            log.log( LogService.LOG_ERROR, "Problem setting up", e );
+        }
+
+        this.httpService = httpService;
+    }
+
+
+    protected synchronized void unbindHttpService( HttpService httpService )
+    {
+        httpService.unregister( this.webManagerRoot + "/res" );
+        httpService.unregister( this.webManagerRoot );
+
+        if ( this.httpService == httpService )
+        {
+            this.httpService = null;
+        }
+    }
+
+
+    protected void bindServlet( String label, Servlet servlet )
+    {
+        try
+        {
+            servlet.init( getServletConfig() );
+            plugins.put( label, servlet );
+
+            if ( servlet instanceof GenericServlet )
+            {
+                String title = ( ( GenericServlet ) servlet ).getServletName();
+                if ( title != null )
+                {
+                    labelMap.put( label, title );
+                }
+            }
+
+            if ( this.defaultRender == null )
+            {
+                this.defaultRender = servlet;
+            }
+            else if ( label.equals( this.defaultRenderName ) )
+            {
+                this.defaultRender = servlet;
+            }
+        }
+        catch ( ServletException se )
+        {
+            // TODO: log
+        }
+    }
+
+
+    protected void unbindServlet( String label )
+    {
+        Servlet servlet = ( Servlet ) plugins.remove( label );
+        if ( servlet != null )
+        {
+            labelMap.remove( label );
+
+            if ( this.defaultRender == servlet )
+            {
+                if ( this.plugins.isEmpty() )
+                {
+                    this.defaultRender = null;
+                }
+                else
+                {
+                    this.defaultRender = ( Servlet ) plugins.values().iterator().next();
+                }
+            }
+
+            servlet.destroy();
+        }
+    }
+
+
+    protected void bindOperation( Action operation )
+    {
+        operations.put( operation.getName(), operation );
+    }
+
+
+    protected void unbindOperation( Action operation )
+    {
+        operations.remove( operation.getName() );
+    }
+
+
+    protected void bindRender( Render render )
+    {
+        RenderBridge bridge = new RenderBridge( render );
+        bridge.activate( getBundleContext() );
+        bindServlet( render.getName(), bridge );
+    }
+
+
+    protected void unbindRender( Render render )
+    {
+        unbindServlet( render.getName() );
+    }
+
+
+    private Dictionary getConfiguration()
+    {
+        return configuration;
+    }
+
+
+    void updateConfiguration( Dictionary config )
+    {
+        if ( config == null )
+        {
+            config = new Hashtable();
+        }
+
+        configuration = config;
+
+        defaultRenderName = getProperty( config, PROP_DEFAULT_RENDER, DEFAULT_PAGE );
+        if ( defaultRenderName != null && plugins.get( defaultRenderName ) != null )
+        {
+            defaultRender = ( Servlet ) plugins.get( defaultRenderName );
+        }
+
+        // get the web manager root path
+        webManagerRoot = this.getProperty( config, PROP_MANAGER_ROOT, DEFAULT_MANAGER_ROOT );
+        if ( !webManagerRoot.startsWith( "/" ) )
+        {
+            webManagerRoot = "/" + webManagerRoot;
+        }
+
+        // might update http service registration
+        HttpService httpService = this.httpService;
+        if ( httpService != null )
+        {
+            synchronized ( this )
+            {
+                unbindHttpService( httpService );
+                bindHttpService( httpService );
+            }
+        }
+    }
+
+
+    /**
+     * Returns the named property from the configuration. If the property does
+     * not exist, the default value <code>def</code> is returned.
+     *
+     * @param config The properties from which to returned the named one
+     * @param name The name of the property to return
+     * @param def The default value if the named property does not exist
+     * @return The value of the named property as a string or <code>def</code>
+     *         if the property does not exist
+     */
+    private String getProperty( Dictionary config, String name, String def )
+    {
+        Object value = config.get( name );
+        if ( value instanceof String )
+        {
+            return ( String ) value;
+        }
+
+        if ( value == null )
+        {
+            return def;
+        }
+
+        return String.valueOf( value );
+    }
+
+
+    private Dictionary toStringConfig( Dictionary config )
+    {
+        Dictionary stringConfig = new Hashtable();
+        for ( Enumeration ke = config.keys(); ke.hasMoreElements(); )
+        {
+            Object key = ke.nextElement();
+            stringConfig.put( key.toString(), String.valueOf( config.get( key ) ) );
+        }
+        return stringConfig;
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,260 @@
+/*
+ * 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.felix.webconsole.internal.servlet;
+
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+
+
+final class OsgiManagerHttpContext implements HttpContext
+{
+
+    private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+    private static final String HEADER_AUTHORIZATION = "Authorization";
+
+    private static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
+
+    /**
+     * The encoding table which causes BaseFlex encoding/deconding to work like
+     * Base64 encoding/deconding.
+     */
+    private static final String base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+    /**
+     * The pad character used in Base64 encoding/deconding.
+     */
+    private static final char base64Pad = '=';
+
+    String realm;
+
+    String userId;
+    String user;
+
+    private final HttpContext base;
+
+
+    OsgiManagerHttpContext( HttpService httpService, String realm, String userId, String password )
+    {
+        this.base = httpService.createDefaultHttpContext();
+        this.realm = realm;
+        this.userId = userId;
+        this.user = encode( userId, password );
+    }
+
+
+    public String getMimeType( String name )
+    {
+        return this.base.getMimeType( name );
+    }
+
+
+    public URL getResource( String name )
+    {
+        URL url = this.base.getResource( name );
+        if ( url == null && name.endsWith( "/" ) )
+        {
+            return this.base.getResource( name.substring( 0, name.length() - 1 ) );
+        }
+        return url;
+    }
+
+
+    /**
+     * Checks the <code>Authorization</code> header of the request for Basic
+     * authentication user name and password. If contained, the credentials are
+     * compared to the user name and password set for the OSGi Console.
+     * <p>
+     * If no user name is set, the <code>Authorization</code> header is
+     * ignored and the client is assumed to be authenticated.
+     *
+     * @param request The HTTP request used to get the
+     *            <code>Authorization</code> header.
+     * @param response The HTTP response used to send the authentication request
+     *            if authentication is required but not satisfied.
+     * @return <code>true</code> if authentication is required and not
+     *         satisfied by the request.
+     */
+    public boolean handleSecurity( HttpServletRequest request, HttpServletResponse response )
+    {
+
+        // don't care for authentication if no user name is configured
+        if ( this.user == null )
+        {
+            return true;
+        }
+
+        // Return immediately if the header is missing
+        String authHeader = request.getHeader( HEADER_AUTHORIZATION );
+        if ( authHeader != null && authHeader.length() > 0 )
+        {
+
+            // Get the authType (Basic, Digest) and authInfo (user/password)
+            // from
+            // the header
+            authHeader = authHeader.trim();
+            int blank = authHeader.indexOf( ' ' );
+            if ( blank > 0 )
+            {
+                String authType = authHeader.substring( 0, blank );
+                String authInfo = authHeader.substring( blank ).trim();
+
+                // Check whether authorization type matches
+                if ( authType.equalsIgnoreCase( AUTHENTICATION_SCHEME_BASIC ) && this.user.equals( authInfo ) )
+                {
+
+                    // as per the spec, set attributes
+                    request.setAttribute( HttpContext.AUTHENTICATION_TYPE, "" );
+                    request.setAttribute( HttpContext.REMOTE_USER, this.userId );
+
+                    // succeed
+                    return true;
+                }
+            }
+        }
+
+        // request authentication
+        response.setHeader( HEADER_WWW_AUTHENTICATE, AUTHENTICATION_SCHEME_BASIC + " realm=\"" + this.realm + "\"" );
+        try
+        {
+            response.sendError( HttpServletResponse.SC_UNAUTHORIZED );
+        }
+        catch ( IOException ioe )
+        {
+            // failed sending the error, fall back to setting the status
+            response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
+        }
+
+        // inform HttpService that authentication failed
+        return false;
+    }
+
+
+    /**
+     * Base64 encodes the user name and password for comparison to the value of
+     * a Basic encoded HTTP header authentication.
+     *
+     * @param user The name of the user in the username/password pair
+     * @param password The password in the username/password pair
+     * @return The Base64 encoded username/password pair or <code>null</code>
+     *         if <code>user</code> is <code>null</code> or empty.
+     */
+    public static String encode( String user, String password )
+    {
+
+        /* check arguments */
+        if ( user == null || user.length() == 0 )
+            return null;
+
+        String srcString = user + ":";
+        if ( password != null && password.length() > 0 )
+        {
+            srcString += password;
+        }
+
+        // need bytes
+        byte[] src;
+        try
+        {
+            src = srcString.getBytes( "ISO-8859-1" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // we do not expect this, the API presribes ISO-8859-1 to be present
+            // anyway, fallback to platform default
+            src = srcString.getBytes();
+        }
+
+        int srcsize = src.length;
+        int tbllen = base64Table.length();
+
+        StringBuffer result = new StringBuffer( srcsize );
+
+        /* encode */
+        int tblpos = 0;
+        int bitpos = 0;
+        int bitsread = -1;
+        int inpos = 0;
+        int pos = 0;
+
+        while ( inpos <= srcsize )
+        {
+
+            if ( bitsread < 0 )
+            {
+                if ( inpos < srcsize )
+                {
+                    pos = src[inpos++];
+                }
+                else
+                {
+                    // inpos++;
+                    // pos = 0;
+                    break;
+                }
+                bitsread = 7;
+            }
+
+            tblpos = 0;
+            bitpos = tbllen / 2;
+            while ( bitpos > 0 )
+            {
+                if ( bitsread < 0 )
+                {
+                    pos = ( inpos < srcsize ) ? src[inpos] : '\0';
+                    inpos++;
+                    bitsread = 7;
+                }
+
+                /* test if bit at pos <bitpos> in <pos> is set.. */
+                if ( ( ( 1 << bitsread ) & pos ) != 0 )
+                    tblpos += bitpos;
+
+                bitpos /= 2;
+                bitsread--;
+            }
+
+            // got one
+            result.append( base64Table.charAt( tblpos ) );
+        }
+
+        /* add the padding bytes */
+        while ( bitsread != -1 )
+        {
+            bitpos = tbllen / 2;
+            while ( bitpos > 0 )
+            {
+                if ( bitsread < 0 )
+                    bitsread = 7;
+                bitpos /= 2;
+                bitsread--;
+            }
+
+            result.append( base64Pad );
+        }
+
+        return result.toString();
+    }
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/RenderBridge.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/RenderBridge.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/RenderBridge.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,69 @@
+/*
+ * 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.felix.webconsole.internal.servlet;
+
+
+import java.io.IOException;
+
+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.Render;
+
+
+public class RenderBridge extends AbstractWebConsolePlugin
+{
+
+    /** Pseudo class version ID to keep the IDE quite. */
+    private static final long serialVersionUID = 1L;
+
+    private final Render render;
+
+
+    RenderBridge( Render render )
+    {
+        this.render = render;
+    }
+
+
+    public Render getRender()
+    {
+        return render;
+    }
+
+
+    public String getTitle()
+    {
+        return render.getLabel();
+    }
+
+
+    public String getLabel()
+    {
+        return render.getName();
+    }
+
+
+    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+        IOException
+    {
+        render.render( request, response );
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/GCAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/GCAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/GCAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,51 @@
+/*
+ * 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.felix.webconsole.internal.system;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Action;
+
+
+public class GCAction implements Action
+{
+
+    public static final String NAME = "gc";
+    public static final String LABEL = "Collect Garbage";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+        System.gc();
+        return false;
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownAction.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownAction.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownAction.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,81 @@
+/*
+ * 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.felix.webconsole.internal.system;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Action;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.osgi.framework.BundleException;
+import org.osgi.service.log.LogService;
+
+
+public class ShutdownAction extends BaseManagementPlugin implements Action
+{
+
+    public static final String NAME = "shutdown";
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return NAME;
+    }
+
+
+    public boolean performAction( HttpServletRequest request, HttpServletResponse response )
+    {
+        // simply terminate VM in case of shutdown :-)
+        Thread t = new Thread( "Stopper" )
+        {
+            public void run()
+            {
+                try
+                {
+                    Thread.sleep( 2000L );
+                }
+                catch ( InterruptedException ie )
+                {
+                    // ignore
+                }
+
+                getLog().log( LogService.LOG_INFO, "Shutting down server now!" );
+
+                // stopping bundle 0 (system bundle) stops the framework
+                try
+                {
+                    getBundleContext().getBundle( 0 ).stop();
+                }
+                catch ( BundleException be )
+                {
+                    getLog().log( LogService.LOG_ERROR, "Problem stopping Framework", be );
+                }
+            }
+        };
+        t.start();
+
+        return true;
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownRender.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownRender.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/ShutdownRender.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,64 @@
+/*
+ * 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.felix.webconsole.internal.system;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Render;
+
+
+public class ShutdownRender implements Render
+{
+
+    public static final String NAME = "shutdown";
+    public static final String LABEL = null; // hide from navigation
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public void render( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+
+        PrintWriter pw = response.getWriter();
+
+        pw.println( "<tr>" );
+        pw.println( "<td colspan='2' class='techcontentcell'>" );
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th class='content important'>Server terminated</th>" );
+        pw.println( "</tr>" );
+        pw.println( "</table>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/VMStatRender.java
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/VMStatRender.java	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/java/org/apache/felix/webconsole/internal/system/VMStatRender.java	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,186 @@
+/*
+ * 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.felix.webconsole.internal.system;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.Render;
+import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.core.SetStartLevelAction;
+
+
+public class VMStatRender extends BaseManagementPlugin implements Render
+{
+
+    public static final String NAME = "vmstat";
+
+    public static final String LABEL = "System Information";
+
+    private static final long startDate = ( new Date() ).getTime();
+
+
+    public String getName()
+    {
+        return NAME;
+    }
+
+
+    public String getLabel()
+    {
+        return LABEL;
+    }
+
+
+    public void render( HttpServletRequest request, HttpServletResponse response ) throws IOException
+    {
+
+        PrintWriter pw = response.getWriter();
+
+        pw.println( "" );
+        boolean shutdown = false;
+
+        String target = request.getRequestURI();
+        if ( request.getParameter( Util.PARAM_SHUTDOWN ) != null )
+        {
+            target = ShutdownRender.NAME;
+            shutdown = true;
+        }
+
+        pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th colspan='2' class='content container'>Start Level Information:</th>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>System Start Level</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<form method='post'>" );
+        pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + SetStartLevelAction.NAME + "'>" );
+        pw.println( "<input class='input' type='text' size='3' name='systemStartLevel' value='"
+            + getStartLevel().getStartLevel() + "'/>" );
+        pw.println( "&nbsp;&nbsp;<input class='submit' type='submit' name='" + SetStartLevelAction.LABEL
+            + "' value='Change'>" );
+        pw.println( "</form>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>Default Bundle Start Level</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<form method='post'>" );
+        pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + SetStartLevelAction.NAME + "'>" );
+        pw.println( "<input class='input' type='text' size='3' name='bundleStartLevel' value='"
+            + getStartLevel().getInitialBundleStartLevel() + "'/>" );
+        pw.println( "&nbsp;&nbsp;<input class='submit' type='submit' name='" + SetStartLevelAction.LABEL
+            + "' value='Change'>" );
+        pw.println( "</form>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td colspan='2' class='content'>&nbsp;</th>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th colspan='2' class='content container'>Server Information:</th>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>Last Started</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<script language='JavaScript'>" );
+        pw.println( "localDate(" + startDate /* <%= Server.getStartTime() %> */
+            + ")" );
+        pw.println( "</script>" );
+        pw.println( "</td>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<form name='shutdownform' method='post' action='" + target + "'>" );
+        pw.println( "<td class='content'>Server</td>" );
+        pw.println( "<td class='content'>" );
+
+        if ( !shutdown )
+        {
+            pw.println( "<input type='hidden' name='" + Util.PARAM_SHUTDOWN + "' value='" + Util.VALUE_SHUTDOWN + "'>" );
+            pw
+                .println( "<input class='submit important' type='submit' value='Stop' onclick=\"return confirm('This will terminate all running applications. Do you want to stop the server?')\">" );
+        }
+        else
+        {
+            pw.println( "<input class='submit important' type='button' value='Abort' onclick=\"abort('"
+                + request.getRequestURI() + "')\">&nbsp;" );
+            pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + ShutdownAction.NAME + "'>" );
+            pw.println( "Shutdown in <span id='countdowncell'>&nbsp;</span>" );
+            pw.println( "<script language='JavaScript'>" );
+            pw.println( "shutdown(3, 'shutdownform', 'countdowncell');" );
+            pw.println( "</script>" );
+        }
+
+        pw.println( "</td>" );
+        pw.println( "</form>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td colspan='2' class='content'>&nbsp;</th>" );
+        pw.println( "</tr>" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<th colspan='2' class='content container'>Java Information:</th>" );
+        pw.println( "</tr>" );
+
+        long freeMem = Runtime.getRuntime().freeMemory() / 1024;
+        long totalMem = Runtime.getRuntime().totalMemory() / 1024;
+        long usedMem = totalMem - freeMem;
+
+        this.infoLine( pw, "Java Runtime", System.getProperty( "java.runtime.name" ) + "(build "
+            + System.getProperty( "java.runtime.version" ) + ")" );
+        this.infoLine( pw, "Java Virtual Machine", System.getProperty( "java.vm.name" ) + "(build "
+            + System.getProperty( "java.vm.version" ) + ", " + System.getProperty( "java.vm.info" ) + ")" );
+        this.infoLine( pw, "Total Memory", totalMem + " KB" );
+        this.infoLine( pw, "Used Memory", usedMem + " KB" );
+        this.infoLine( pw, "Free Memory", freeMem + " KB" );
+
+        pw.println( "<tr class='content'>" );
+        pw.println( "<form method='post'>" );
+        pw.println( "<td class='content'>Garbage Collection</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( "<input type='hidden' name='" + Util.PARAM_ACTION + "' value='" + GCAction.NAME + "'>" );
+        pw.println( "<input class='submit' type='submit' name='" + GCAction.LABEL + "' value='Run'>" );
+        pw.println( "</form></td></tr>" );
+
+        pw.println( "</table>" );
+    }
+
+
+    private void infoLine( PrintWriter pw, String label, String value )
+    {
+        pw.println( "<tr class='content'>" );
+        pw.println( "<td class='content'>" + label + "</td>" );
+        pw.println( "<td class='content'>" );
+        pw.println( value );
+        pw.println( "</td></tr>" );
+    }
+
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/OSGI-INF/metatype/metatype.properties	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,44 @@
+#
+#  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.
+#
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the Felix SCR plugin
+
+manager.name = OSGi Management Console
+manager.description = Configuration of the OSGi Management Console.
+
+manager.root.name = Root URI
+manager.root.description = The root path to the OSGi Management Console.
+
+realm.name = Realm
+realm.description = The name of the HTTP Authentication Realm.
+
+username.name = User Name
+username.description = The name of the user allowed to access the OSGi \
+ Management Console. To disable authentication clear this value.
+
+password.name = Password
+password.description = The password for the user allowed to access the OSGi \
+ Management Console.
+ 
+default.render.name = Default Page
+default.render.description = The name of the default configuration page \
+ when invoking the OSGi Management console.
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/asc.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/asc.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/asc.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,2 @@
+GIF89a
+Œ èÏÚ›gÑk$-
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/bg.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/bg.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/bg.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1 @@
+GIF89a
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/desc.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/desc.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/desc.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,2 @@
+GIF89a
+ŒÉ­°œƒT2ŠY
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/down.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/down.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/down.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,3 @@
+GIF89a
+
+-v6îÔy^[)~hJ­ìä¾YŒÅÚcß\.W|øéHB“¯hB•7fÓù+
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_add.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_add.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_add.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,8 @@
+‰PNG
+
+
+IHDR
+*¤èb6
+ð
+ðB¬4˜
+±±ccJA±¶„› æÙy܇߽3³ÜqÕÕJ<Ã7gfîÌwÎùιü·ÞÄo>oeö׈NLCŠ>±½f²“%‡)xCoµE¼rj#|i•PEºjS
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_delete.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_delete.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_delete.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,10 @@
+‰PNG
+
+
+IHDR
+*¤èb6
+ð
+ðB¬4˜
+£¨À/Še³$	%²’Š0:hŠt²dQ7wtÜ9|óõÎìd²­’—E/<ó.3ß÷<ïqÿöÏ›°È÷ÿ3¢MMg!
+‡ ¿¾ÙÞƒ‡=ÇÛä9ã0"×1|êúN°æÒÉ¿	ùÉcUY¶ aB³Ñ¢:‡jpL[t.À„[” úd°™Þµ„éfá!al!7j[aÑŒ-bš¢ŒR“—Jˆq	ŒÈ9 Ú2%A™Xºs¯”ð2Q@œ- çîïšòByJ·1IQ;(]•‰ÂœTDG at ttH01…åV%• %–Ý%
+¹	mTEj–Ïmœ>¦¡ùµ8xdlü}¸¤Æ<òI$n²i°‚œlª”a §sŸ%\"Eó6–¥|	[•É5uuuKC¡P„ÎðÈ’Yò(>ɃjÞ9Ê®šéíÍ#aõ
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_run.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_run.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_run.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,14 @@
+‰PNG
+
+
+IHDR
+)=á3Œ
+ð
+ðB¬4˜
+À
+×–¦n?ÀÔÂ;0íÏÐP›G!p᮫%Z¹ì²"}nÎ9>2üfÍÒ$å:Ò (˽ø9}tG5âÏÅ·ðÒ®QÄBšØj0ª°QP@^	ä”D†XtîJê-¹]ø˜y<š
+=owÃq>AìðµÚöÎv“.÷YÙÇ…CýmöÊ鈧K(ñY•GÊŽS²%öe¯lÃý¶Ec¤îþûG:£»çv÷
+\˜ã§v0º²Z€|X
+–­˜¡‚
+`o<åqØmV–FÎ#~ËöššŽuï«I·Î}0¼gø"ÞäÔ²•WàÃJ|såÓKïq¾Kf}cu»;L¯¹³ŽÌ²ºU„L”¡ˆÀ‘7öbõUû•¯íÄøïÒßt¥DñÏ{yÿ…(NƦ]þ¢þ㆓J8µ¾fCj
+¡‰pX‡i˜ˆ†ÃÌ#èÓú4½N«ƒTñÀLÇî©1öuœÔuš„4‰hÄ@$A,Æãw06ò×,ú1ºÝAs‹‡e¥ÚØ)ÃÓL›:|Ã@],†G‰,úGóêºú?#C¡g¹u,H¶êIÞìG¥	ݐˆÔË;QÀÀØ-ÌÞXgÖ3H"Î=7Éodd·P5(%*´Ô¿žÿ_þ4œÄw¸Šqdùn†Œ“»$ÌãzF;
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_stop.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_stop.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/element_stop.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,13 @@
+‰PNG
+
+
+IHDR
+(Jæ
+ð
+ðB¬4˜
+
+U7FÍMК¡B;”@‰Tj†ŽÄó±øäÅUž|O{CÛNù*$By©D›^6è¤C¿š4_iH®è€LuÁHâ ‹ö$íãßâ­ …G‡ž× ê3ö¸9~˜äJJFš×qŒÒñ‹¥É‰¹‘.^oÚU<àFL—ÍphõHÀgZ‚¯Þ™Åo	q«‰4HBù¾õôÈ¡i
+˜6uòJe~†þ¢6€ „Ÿ
+,gM^£„ˆáZ^Å˨¸/‰¶ÐOň˜žu`frðT§÷ÐòÚ$-á÷oPå%ȍ2ìêOè5 q;Jµ$Œ0Ò	Ú‡žO£ÇA˜"bº:™"Sè*‚îlÀh­£ØX…lW
+°.&	¬FFVà¤m'PªŸß}6A´­w®ûŽ])Y±ož#L߁Œ){“ûF‰eJ#AQCÁlnö˜è`ýþç·´S´bï£Ékä¹£Sfä•dêñNص€‚A2-'°í-!
+êƒz·a2MkÛe\ÔĔ̺Z#ˆ)r@”L`Äì¬:lC%ˆ»ÍòkPì,."‚ò—§g„ÿGY‡¢Îa(ÁV=ú‡°³Óc€öXi6[=ÍÓ4Æg–Éi›çÕ0‚¤µÅÏóeå_JÚŽÐc2aŠuÊE‚ƒd£Í¯ørñíz¤]@Gç6úßÈ™çY}¡½ÞAVæÙ»GûÃjÌj{!
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/favicon.ico
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/favicon.ico	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/favicon.ico	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,3 @@
+
+o†9|=¨„e·•¶`;ME:>L¹€£’
+oY"<,RÀÄÄÄÄ¿zOK\0sÄÄÄÄÄÄ…dŸ¡¤¥k*¯ÄÄÄÄÄÄÁT/ru7šÄÄÄÄÄÄÄÄâ2#b°ÄÄÄÄÄ
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/felix_logo.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/felix_logo.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/felix_logo.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,95 @@
+‰PNG
+
+
+IHDR
+%
+0
+tÞÄŠ¾­­%üÛX
+
+â‡%º¤ðÒ2¹²/ätC”.ìkRUYQcQߥ!¡©¤¥ª­¡£¡«ª§¤/k a(dÄgÌiÂlŠ1ýµÕlÞü‹Å¸åˆÕõK›^Ûn».ûN‡NÇN§.çn—×þnoÜGNxÌx.x­yƒ#‘Ãw7IÒOÅß À†ìœ’ZVEyÞE}19µƒeˆKOT=¬{Ä8Éü¨Í1ûãNÉÎ).©.'œÓOÚ§ÛfX2?mšixF/K;[ó¬ZŽj®Ê9åóÊy*TóÕ/jè\2¸l\hvŲÈöªã5×닽J|Jýno—…•‡WDÞŠªŒ©Š½Ww'®&öntmä½ðºÐzò}bƒG£ó«‡†Mêdš³¶@Ë·Öá'mmíYáOí:åºp]SÏšº³Ÿûö(÷Òõôõ¾Pz±ùòÉ«´óA–Á¾×§‡Ìß0¼i{dXmxé]Å{Ÿ¾‘W£>ü«ù0N;‘5i:I›ªÿ2-2=òùü›ÜLçד³–sœsßîÏ™ZðZ´[²üa³ìþWÈJÚê͵ޟk›Ž[¿Úi4
+V™áŽŽé"‹þ
+k»Ç×a.Þ>1þ‹»0»=ïhB¦Â©{[E6ÄdÅ=%2%¤>Ê e…ä4å­<}•öù)RqV5USQÔ`И×к¯] “¨ë©§«¿Ç
+i[iŸí}Úßù¸«êYAwêsJk¯^Ÿh?Sÿü‹W/k_åPí^Ë
+±;yööæpê;Ò{“‰Qüè_ÆÆz>6WO”N^™*ø”?}ñó¥/E3%_+fk濵~ïž\ø°øuiuóçŠÈªêšùÏCë1g6olµü¥Ñ
+<ݼC;ßñ½ãèÛÕ¶»^°ŒpaOŠP˜°Ë^-‘]"¢ƒbåâq&’xÉ—Rg¥­e°2eÃär½òq
+"
+=Š‘JüJ-ûHÊ8åÛ**+ªj:jãê)âÏ5ôصê´]µ×u
+uõt'õNèKè÷„r6™Œï™x™âLïï'™qšµ™GXˆXY¦[iY-X—Ø°ÅÛ¶Û%Ø+ÚÏ8\stsbwêqNuÑuùéZ{ ÄMÜm½ð «‡GŸg†—É!Ô¡fïuŸUboI™´ê×è8À€Ì@îÌò	–	^éÍ
+ó¦ÈSháýÔ«á‘Q\QŸ£Äœ‰õ‰SgŽOhHÌ:L:¢•Ä™4w´ãXáñ˜dÛÉTLꇍiçO†§[eHžb85}º=³øLr–o¶ÉYñ¦œ…Ü×çšÎ睾è¢eÆ%ñË<……WŠ>_¿6z}¤x¬dªtîÆZ¶œ·Bú–a¥{UôíÜêš;¯j~ÔrßÓ¨óªO»_Ý0ü
+·0w;/Ž·z§ÓÎM¾R~[þ
+ò].»±»ƒ»	ƒ{2„„6„ëö†‹ÈˆÌŠVˆŠK‹ÏKÜ“Œ—Ò—ÆIÊ\•
+•Ó–Çˏ+Ô)žR"îÓVÞ©¼¦òVõZ‘zšEó –…¶–Ž¼®¨ž >Ÿ¯!¯¿1ÁDÌT~¿¦Ù~sËX«SÖWmêlŸÛMÚo8r:É:›»ø¹¦¸îÖæ>åõ”ö²?ï]ìÓOÜ$Iú¹ûg´’Wƒä‚É!¥¡“ápµ"b1J3:-f(N,>1aà°Ì‘Œ¤Ùc6Ç痢æ¤ÑŸLJß:u4w¦ [álnäyBÞ@þ™›Ë¼…_Š_+,>VrÓ»Üý–GU at u\ÍÙÚ;u¯à\“Os~Ë«6|‡UgÖ³Á¾€÷^»¾)ž‘øpàcüDúÔ‰iêë¯ü³ÃßNÍ+-¼Z"ÿøùWÊ*n-w{ãÜÖŽ_'~Ï%°… HƒkÐC°ˆ0#¢ˆ>âÄ!yH-òYD±¡QN¨8Tê)j͇6EÇ ËУŒ%&
+ÓN‡¡3¡Ë {A¿“Þ—þ°vØRì&ƒ3C-#'c,ã8Î
+×̤ÄTÉ,É\É¢ÄòoÝAeű–²²M²§qHs¼æLâ’âæNçÑàùÆ{u§_+œ€¢ÀÜ®²Ý$Á½‚Ÿe{B„ö	ýîÞ›/ ª)¶ClZ¼Eâ’d¬”‹´ªÌN™
+Ù1¹vù
+…lÅ%¯}û•UTUWÔ>©iti>Òº§]¥S¦[ªwC¿Ì Ê°Î¨Ùø¹É;ÓÙý¿Ì9,¤,¬<­ãmòmëí†ìWw:i:{¹¤¸Vxéöó °‡µg‚Wù¡aQÇ7‚tËo*€@ö,%‡ÕPÖ©ÆÙ‘£Ñ’11±ñì	^‰•‡×’ŒŽž=6š,™›Ú™Æs20½ù×éÐÌçYRÙYgWs‰çòL/´\Ô.h¾lTØWtðê÷ë©%„Ò–›¾å,*ƒoUÖÖz×IÔ/7´=8×ä߬ÙÂÚ:ÙVבÒiûŒ§û}OAŸã¦—Í¡¯ù‡ž¾¥¼ã}ß:JcûØ8á3Åü©î³×Ãך9·ïÈ|Ù¢ÍÒòrþŠæêØÏä
+ÑÍÎ_~4
+c‚ÉÁŒÓí£Ë ›¢×§¿†¥Ãcß0˜2<dÜÇX‹Sõ3¹0-1ŸcÑeYÂWîcUgcb›dÂqƒ3›+‰;‚'˜7pg0_ÿQ³»nînü¸¶ØK¹$Ú.ö]‚Or¿TŒt™Ìˆ›¼™B²âc¥-e•£ªêÌ.šÅZ?tŒu/éý0°6¬4f6	50S7¿f‰³Š°µ5µ«qàwLqúîâêúÄMÆý¢½g¤×”·“O§¯©Ú_$ 0+(+z‚‚	O‰ÀD¦E3ÅdÇñÄ%J¾—¤w´÷øÁäÙÔ„4–“EŠ§:2]ÏÌe'åpäÞ8¯ž×“ïuqéRJ!÷•²«ê׺ŠK&nßüQS±V]µXM¾óá®}í“:…ú¢¦Æè›ÌÝ}Ìß’ÜúµÍ¾½ñ©`牮¹n»çõ½ü}Iý/
+_]øõÚeèÖ›õaýwÇÞ7ŽÌ|`û¨1®3¡3)7%0µõixúÖçø/:3¨™Æ¯”YÂìó¹˜o¼ß¿»~_œÏX ,Ô,.,y,}ùñcmùð_È_)+˜•ÔUºÕ“k¸µÌŸ,?Ó×éד×77¢6¾múm¾Û²ÞzòKåW–I£lïK
+þËr÷¿FHpÔ߬
+õ±¶
+³°
+¡@€@
+¨@þ2øB˜ù85ä®_t~Xœ†s€ü-ùùM üf[üq$AèŸJÛî>Ÿ1¢EŒ2Æ
+Tñ"ÿGÛ»:
+ŽpÕ†=vÙ©Ù~W/>Øasn™†ªRç\!„@ÆŽ<ÁY¶ÍmKQÔ#ßµl]׈Èår!"
+DÂÔŠ
+gŽ(Èèõ'LÅÞŠýû+wO?û,¢ƒ“Èæ/¶µ4Ô;oÁíveeeŸTìóR3îØYÞÑÒ8åÌ©
+†iY–»DNÐ	nøüÖ
+óÊß<ÿῶ@V€ÐtuÚȺ{Ï/Ÿ>,†.Ø~à>ˆÄâ‚âH1 ¸*yÆúÇûæÌ<·FûÛ§¡M¤yÈé.·ÒÖ.{qõ²[§ÍM;ÚÞìhk¤šêêT~Œ=yTfŸÜX,¾ù‹­jjª÷ï1úd'Assk8ä\ÔÕÔ¤ò{÷®=j«óóúLœtŠ×ç
+Þ‰Z»vŠX»0[…Õ*¬V°Û„Ý&ìVa´‰x³6÷Q:~¡´êîœiC=špf-@ô¹”ú`ügo¬iæ‰xÔšê‘‘‘ÑÐФÅbÝîr!
+
+D„H¦Ð€t`0¸Ä…iaHÞdzô&ï]K¤ç×i"@x”M5|°ýÉKÇõîs†YWS›•™Þ¯è¤õŸ¯=PW{Òà!©	>q!š›@¯7aŠÄâõúæ¦gç~±qCScca¿þ
+…£ÑhNvzFfæáÕ
+
+ø½-M{ö1ÂI¯é·LO×ÜŸjÛ°mG2°ôÂã}ôˆß6ç—oUN7W4ð«RS8
+È€8ØÂÀè3vŠ	W?“¶u¿¢xÀ綐’d‘.ä7k'Ô<öéA.¬í0[
+õ͍y…}‡ÖÞں󫯣ÑXN^ž¦•^—<åÌ©p(³"IC ¤ªªýM­‚
+
+T”4¼
+®:e*›‚2@¢´©?•
+;ûO±OË]>?
+:èã
+££½C×4Y–ÓÒ^Ÿ
+Ó/RG”¾ûiã§å>
+ii>wÄ°-Ëöy$gnv“YËsæ‡ÎûƒüzÌ0AX q¤W
+4ìóTÑDY¢ŠöxÔ´½Çç0õz=^¯§‘1ÊÌLH’ßï¿ïðŒ~¿Ï]’XVÖ!_UQòòr»%Sd9+ûdˆž~pœðû}
+gÔd9'Œ¶¶°Þ#‰¡3”k¦}áøA'å¦'a„??s„
+B ""X(7ò\4!bûÂ<(W½z)aNGBK@Ô²Oäãÿ§ÑÒÒ
+…þ6àØó·ÃãďtSâq’ì/F;ð(·cÈ‘]'ƒÇ-w+'Í­0"ìòxÐxY¹äMåüv–ʼn!1E6S<¶„H$‰€Èj]]ݪU«¶lÙ‡‰(//oôèÑ£F0`€ªöŽÞ$„hkkÛ¾}û†
+Ö­[·qãÆ—_~ùÜsÏ=ZúššÓ4‹‹‹OÐÒüØüVI–8‡„µfºeè
+Åb±5kÖ\sÍ5ñxüð”lj£Êw0ðÙ÷潽Ʋ9ó{qgDb7ä6ërŸ¬
+3›ÃzycÐëRˆ˜d˜v]‚cž”¹QfìË–ØõíYœùài}¥÷B€›mÛ7ÞxãªU«Ž–à’K.ÉËË;þŠ8n±c&kmm}ï½÷R)ëׯ߱cÇĉ{«%Ž,ß;öÖMûÙãO½ºÜ’%æw;Dˆ(!od[ínÙ;vìčŸŒÚ8¦°>j¹’³¸×­¶GõÕ»*šC~·BŒ’²ë¨6fSԖ–1)n“ɺˆ
++î•Ûžš¾H&a“*K>·âR¤dv at 4†ÔlÌòPi¾y^QÇåC:.*M,tgºÉä2I³VJˆi.9bñÛV×=ñeËñ<m4}üñÇS)@àÍ7ßܶmÛÖ­[·mÛö駟öºHõ™™™—]vY*eÚ´i#GŽìõŠº÷ 
+;ªfÍy¦5¢‘ß
+
+Tö"DÔmô¹0+AÌZHXaa‡…;\Âíeö®_ñPC÷́æ’sC¿38™@]Ú"ùzh[ûÖ¶ïbgݵkWêå駟ž^øÿrssOèsP¾y~éºM嘙–P’	í˜5~DÖ‡&zÁÖfOÉ|©¬]ö'ø§(ö=”N,Ø1"«–;QJ":€aß_ð^	k¸µþÜ.´œÕ»øۏµ±yllnì0Øa°CÀ#ÀÉK<T%Êï—G=
+\uõ›Òè t~÷æLS ‚ˆQœÃÛ:ÞžšëbÇ6Jtvvnß¾Ý	
+®¬¬L½ÕÒÒ²víZÇ#)„=ztZÚQ‡}ûömÛ¶m÷îÝÎ2Éçó•””Œ1¢¤¤ä»¾|
+ xĶ@°[wóògÔÑ÷	Ë/)Šâ_ô±¥D4mé0ßؽaб]L›7o>û쳏xë­·Þzë­·’—«W¯ž2eÊáÉÊÊÊþû¿ÿû“O>9ÜêóùN;í´ë¯¿þòË/?fKŽˆ¿üå/óçÏ?œ~饗.^¼ØùˆË—/ÿÓŸþ”šà‚.x÷Ýw8>-Z´èÊ+¯´¬ƒ®‡Áƒ;sY‚ÿÏ_ªÇuì²€Û¦è›ëyûOó3]"fƒ0„*)Œß7dù\æŽæ~ç-ºý«æ…@XÀ-àNƒ	m:œÅ¶?ê~Þ@ˆ9Ç>WW³v[ ¶#kš±Ê »<˜UÎfƒb
+kQr
+CØ4*=>#7³›ÈU‰¾ó=‘c8LKKK—/_^VV¶bÅŠ]¤fÍšµråʲ²²²²²åË—=:yëÎ;ïÜ°aCjâÁƒ?÷Üs_~ùåŽ;vîܹcÇŽ…Nž<95ÍöíÛ|ðÁonO7Ì™3磏>Z¹råÑ”ŒT\z饷Ýv[*eÏž=·Ür‹ó¿¬¬ìÑGM½[XXøÜsÏ¥nc“¾®ª¯¨kEqøÇu>ybÎÉ%é [
+Öݪd	EÒXF‡˜H3äx£•ycíïçýÁk…’\,›UÒ6›ƒÌºFu"Hmv]ÎVF"›:?’ÎÏq×=\õ’˜$pÿÌîÛùak†p¢!	C7tXÃüß´¦ÊÊÊš1c†ó?óн?ÅÅÅÝ&EŸ~úé+¯¼’J™4iÒ’%KR‡Ó´´´^xá…W_}õÛo¿¤¿ð·ÝvÛ Aƒ¾¡I©>|øðáÃà7ÞèIú¹sç~öÙgÛ¶mKR-ZtÖYgýøÇ?¾é¦›LóàÖ;D|öÙg»­îhÇž:K3%| ð¼SrAB!¸	<‚	£¿^è†;ÈÍ´Cq#¤[&]‚ŽIûÚ*úkç¥nžÐݸ	†
+òڇeFLÁ€0i`GD±DÐäKð.׸@L‡à¢ôkÿ-ÂöJd]þŽãÒbÅ^Ó¬+æw„z:€m2¤¾T<õÔS©aœ@`Á‚ÝæN.—ëÙgŸÍÏ?¸Û4‹ýóŸÿìy“’HÕ°¾^¯÷¥—^ê6›Üwß}çwÞ¾}ûR‰sæ̹ð»e§]5Í}”€¨²	CÒÁâ
+ÍèH€Âé4\€$Ñóç;礄1ü‡•·Z-éÙæ—ž±í‘Y˜à§cÜìÕy 1¤6B–È”{-dóæÍáp8•âóùÊÊÊŽ6(ŠÒMçÚ·oŸ®ë½!sDÜ|óÍ«W¯^¸pá獵§¿ðÂn÷v*IáP<©y€€GNóHÀ-GMCÖ¢ñ=Í^&£³‡Õ°ùI™þÉér×f¾’Üô?ÍšôãyeÉQZ «´Ña‚
+‘|>€H$0jðH<’®DÁv~1·Ü90#VÞ’ŽÈÑ­H;ëÚ[úÅ}'‚¼¢†5÷Ãm¶@JƧ
+²jÍ(x‹!P¢‰h+Ê,®Y «h"
+Ë““Øæ³­%övE§GNX^9IiFçÞØà îÚdÉŽ±ÇI¦2tõÊ&Ò.tó:3ÆJJJ$IêáAVœó3fôr<ÊËËo½õÖõŠM›6Í™3çÕW_=b.©o^&
+é›Ýå„@F¨k°­*8©ÄHÎß k³GmýËç£Û4¿Ê cn†¯¯Ýóúú
+ RdÉïRº”>ˆ’÷Gñ•ƒôzÏ4`^°¢€–ÎaÎB¬K§C£˜%žÚÒèl%ô*’*±„1‡Hqió,û‘Ür€"bI»ã^EJ„5Z@ýÝèîU~w3•†QQQ1vìñn[ì]ÜÿýÝ`Ýð«_ýj„	£FêF§Q%…äRD×”	{KLØQäQ°#À#ÂŒçjÿ0å#Ýr3#aÀ£<jšGõtãs£g
+£IDATíGB¹rìö[ƒoø&€+Ì0pЀxTYß9VefrÀwX.1
+¨’ó“X2zÂj晕‹§óàWÀŠ8k1@±#ê«7T9¡;¢8Ê×Ë#çرc»i[¯½öZ/–üCý’%Kžxâ‰TJqqñìÙ³S)¡Pèú믏F£ÝòÒÈâü¢Â,Ë¿ýk‡½iMxªè·oýï;Ư>¥È’i„C·Ä­ÇbÿgìˆÌ+B[É„uícviÅ*YŽ±Åq´b”í*	ƒ®ìQí笻Ï5z0ðN°ZÀê®òwÚr,`DD‚PexJZ/ó{èСÝÄâƒ>8&Ë{®å†ñ[
+¡Á§,üÓ¸wl¤ í³QJ(ÉD™Aj¦ˆ¶—ÅC}¡ÀŠ‚­ƒ­ƒ0€kðbóe%ì’KALCw½‚›„H¤É¾°š1­~ÙýëÊL·¦Žî±z°ÚÀjEÞT¶Wvf{$ç¸#0•xi”·—ù­(ʍ7Þ˜JBüâ¿xꩧŽÈªÖÖÖ›o¾ùŽ;îèaù
+
+
+ß¹mŽC¬[	·ß~ûE]$IÒüùó»I2oÞ¼n6€ŸÎ/¹N)’ýNZóT]ç»»FQ‰	.,,~7|éÊӝ·6]ÖtPâÂC·`l
+x;K[ËÏhÙ2¥}ËÐØ>ÉÐ:
+Ð4à:pllÈ
+£¬vû7…sl:_a<á?%Š
+¼"ûôžµÆŽ»lÙ²¢¢¢žgY°`ÁΝ;»322º)üÁ`ðÒK/ýø㏿U{š››þóŸwóï=þøãcÆŒé–ò™gžéßuX ƒ5kÖ$½ò‰ÑðôÑE?;w‚ÕË*BOe_ôZæÌFhßMeÐð´|mk¡m;´ìƒö6Æ!¦ƒ¥'ðÄ0®ƒ¬Óð^ó×ïó™KÎôHpçIÅ2,lt"6„9D9è6Øpò/’¼'ÅD´­f䟇ßÚxG\*qÇè8‹WÁ?ytÓªŽæqpꩧ®^½úÊ+¯ì‰q433óÞ{ï=<”˜ˆ®¹æšnÄ={ölß¾½±›rz©ëúu×]×->îŠ+®¸é¦›oI^^ÞóÏ?ߍ8wî\'ú1%ùúk¾ª)¯o÷yÝ
+—ßظlR¤$0T2 ”8JÏùƒ0	$\‚ÕþÉI¿¹B.	`º>a"H"ÿå{èb{Æ!ª¡åü¢Àã dBÖðäp
+’$egggggcæ€ÊÊʆ†·Û=dȐ#Z×9çœó$¿SÛ¦išäœ§Ò…žl“°,+5‹iš’$u?kÙ¦½—=öO)Ér$ŒI^‰Ä_^Öô¯1±Ý4A.2@	$	$\Wúæ´ñ寧»Á;žÝd‚s0—	ÉHd k¼´íRsÉÄè¿ûDQ2pçƒÜlš o›úÌ^'¦Û¤x¥89å
+WçX-
+3A¢vWv£§àëÀà¯|#šÔ\FèFÓ‰Eëö™‡sym&ç@[‘U•)ª‹¤„ÄÚ0{\EC[(Ÿˆ¼L#‚äðÀ‘‚®*`(¢^õüï‘ÏÛû¬¼îêyík	§ùÝä°ª‹g¦¤š’ŠDFŒÙ$s&K*ZðdJb̈۠Ȓ[‘ Y"2²I±˜K0…Ȑˆˆ$â*™	t¾~ÓÅl
+‰në/ÝÒï„Ÿý?G=_±¶-ü«×W¿»¹JQd¯KɯLuœŒ9ìsb/	X"MÄ~·rÕ¨¼MMÑMQ¿KV$GøHUò’¥œ¶‘¢‚ûÙýÅòéßËõñâçiþýó]}¸mg}§,3Ka¬k>>ʇŐˆÆl$6ý¤ìßLPšçö‹_6½úukCÌr«’*K”òq"ê*
+Ñïê:˜ë’./”¯ïËÒ¤ï™Ý8öù©Ý\¼©rᦪMÕmAÝ’SY’1æˆ& q"ÐHŒrüîÓ‹2:¦pêÀCŽ~mŠšÿØÓ¾d_°"l™e™ÉŒIŒˆ1èŠmåH’ä–Ù ¿tnžrIž”§~Ïé^÷øþØWõ«÷6nÜßZÙm™q‹;_h“K÷ªyiîa9É3'öM/ðÕá¯ÛbSsl}S|K»^·;-0"1bäQX–K*òIcÒåÒyt€Ûøÿr|—ïÍq!ÚcFH3¹
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/left.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/left.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/left.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,3 @@
+GIF89a
+
+â›±ÎUóE¹ïÐ…WH>䉝(§ªGƒp<ÇL]²¸퍳Í>6âêsó u’e‚ç|
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/logo.png
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/logo.png	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/logo.png	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,60 @@
+‰PNG
+
+
+IHDR
+ûÑ–AQ¨ãü¬™ºÉù8Èßçt°èû±6ê	â¹|A}7ðÌ9*/§õãR­§ÁÏÁ¾"ÿò{âçØ‘f¼ç¡S^¡ÑÏAî…£¨~NÜĦH“7^/«‹ŽÃeŸBxÂ×ÿ\«¤LR¤	8Ò‹¨‘ò!1 Iø1q’ñÍ‹‡ÔE5pñ4ààÇįÀ˜Ì×°äNt²åâ€f­šþ¶$€žÍj}×}wÑ7¸ ›ÿ\&ðcâ'•‚Ï&D6%“	œv=9y#M}…
+_M‹‹R=>åpݏ,óŠÝ´ï~Jü3Iz:hé›>8¸ÿ¶ýy>)?Kªv*üåõÑЛÂÈe_¡“öí‰Ë°ùp5‰qÈHìSŒÈÃÓ7ú_²ä·‡;-Wæ5
+IáÕL³¹ÿžR©$ŽI††t¿ëÏéÀª)UôÅ\bq”³`‘γ=+*áû0ø%ŽS,)Ô:ëõÙþ8hMœýãÄQžŽt|¤Ê|}Ë ¾Uóß—q•ˆä5=b!|69)ø0‹¸ú§‰'z]ÀZa"~ÖäÔ³sfZ‡âX‡‰Qé—c•—µp¼Céyy'Yòâ@<urØ«ÈMYÄû»Â@ÖiŠú&žœÑÞ,áç_pÖ¬©g2%æ	
+§Ú’8Í,û3Kk²Ê‹ÖºÒó‡¸xÏiG<yAûÍnQöü}¹±¦J}€®US›â]6è~]¤TòŸž.š„U3â4—<;R¸ý½±fÑÊ'‰'j‚Ò-:#j<@TOÜüŽxÒœEÈ®"vîù°›úqô;âIë+|ð„ç;su†ZWO¼ÿ!ñ„IGx™mû¨¡J£–Ö:ªB§¼n!ší‚ºÐi©r(vsv#11>¹æ&ªñbS^·jÀWÛ{B§Ç#`‹èR_™
+v¹6ùŽöÄO:ÑY¬t-@“ÉÊÂWág@HďÝuBÊ2a1÷í!×jÛêd~MÝ¡ö—f«(G¤[ ÎS$·b6ð'µã{BÈa¤SÞßß–U±‚Úü¢
+N-b¥Ð8³Sðí¸0‘ƒF§mן
+jtº=D	Žƒ-–OÑ‰sÞÛ?íéikƒ¹
+ò4ŠZ3_›Gîò´ÜgAÓÛaƒ[wgÏ„¬î”ðÞÏÙóÍõ‚+«™eRÓð$;LÒ!uP(‡Ý¦~sàµõã)È"щí¯ã.ý€>ñ›œª­ØÞE@Ó†>EF-—Óˆ;L!”¶2Ú¨­?#ž.ʺh*zwGðìT’rpxCe/êWÄCwÁdŸm'($米Dz£¼çÕÓh5kº’K\îWb‹Íê’MZv[QÏÝ‚ŽyŠ·'ÿý/ͺ_I–ùÍO÷OøÚÙ¤êF.iôõñ'ó:C‰Jn&!èDôýˆ8À¶…ŠŸÍoE|ñrálsÙŸZ?­‡¥!NóX..ìón-œ¿BÔîA$þŽ—øKü/ñ—øKü/ñ—ø;Zç/œ/G/œïÇ/ñ/¾@|‰\ìƒüä¹³¾¿élmâäIâÑT
+´Ž5FÐ>ú"äN+ÏeóŽç¹iç‚Qx(›8+;DÆ=d
+ýbÇ~ŠùrÔ8y÷“&îA”¸êÜ_l,g
+½÷tÑ6¼ûLÜ5˜C|àH_ëÄÑîbè0qßBpºˆ§â`hé
+œÀ…¸2u93e0Dü¶Z,â¼e5Ì\‡âm2ë#]Ćñ«ŒsB‡óœÙ´0÷i§M¿#¥ZåR¶Kðžtr	ë½°3ÂÜGœÏ2jï¦5{H²–<ˆ/-?u§ø\â¯ýµPçFÂqâP#8ï¹RðìZÁ!±ŠçÄðjÉâ÷8Ñf)u[~h•×ГÁ¶j©vûaR	³­5X1frˆ{—fñ
+Ž–Œze!'³ˆ³݉O’ŠûEcª{¥¤ž<à•×^Ðgz¶"ÎõF|ò2YÊ^_K¼NÄOߊÐP9Pq½9¸
+QÔ&¾1ærÆËï/tµÅimï5Ïx횺šMJ'•H߉S'^ÕžÕàKLf†êaÒ‰÷ÌÖ*ü°ñ§­“[;Û‰‹Ó!Oy¨(â³äüÈÑÝ5ÝןŸx
+ð{8®'>Yp©Ä±½s¢Oqìm.hú0ÿÂñ[‚ŸÜÀ›jÕ	ºüF¼Û²Ft\Äkø+6<2\w?&Ù*}x‹Ø>C\Ö\ßÌÙN’Ká£J8Bq#Îô¡ÝÄAë#ñðÐp¬»â'¿[$ØÀ7IŒÙºÂ¥Ç)ÌnïD\"Ö¬ª"Ö}|jÀO!O!Â1³;߃´M$ºñIlq•:¯Ç£ œT(¨&/ò‰GvmÀÓ<(¸Å¤Lô¼1q
+|Âi”ŸDû,ä†û"3Àe…±Ó¶ !Œx{̦
+q鎛~èµÎ
+ƒû9sÒY>Xx2Ój‚®¿7m±wði'‘æâ'³×˜`"ASw]„ì2|”äs†t÷ªÞýQn\ÜáTá}­HÎ
+%|‚øY§à#ùÁDÐ\½&.JüÂSéOKÊø²Ÿ\T¹yâ,I&$ÿ3µ¬›8f±É ’öìÔfÈc¨¨¥—?@\mˆg×…Ÿ¸«
+Bj\4m¨âl8EìRåvÄ]Ñ¢ÞвcD‰ÅPkóDñ®G=3	!1Ÿ×g©¯6ªV©w³é Žœ{¨Ñ‚ÁÞÍÓu²
+K/í`PTþTf&ýèð€Üó¦-ma»+dŒ±‡¸´_=ûñ
+Ö¼?R:è-Úh0ˆ³ŽØÔÊéqÌ›íUk_¥ro6ÌðÜjˆÄ
+Ê¹Õ5là産Á¥,,ç»B&±g®¨x
+˜eÛÕ5L"˜4ômÿæaâv´
+ ›.‰‘ðâ_Ê
+»„Ñ'‰ïˆ‘>~ø¹Òjѽz^Y™@Ô8ÁT)œ:x’8ZÃW³í<ß5~•8¤DjR,Ý„tU* ”K©#ž$6{­{ºŸ7`
+‰'ˆ%^ºsˆibp	‹ûuCñ§\åjâ{$Z¹â8-O.¦U=ÓI¸%ÐR·;ß­2Mœ™ÆJñÝBãKÔnŠ\žì®!ñ¤´$S|àÔôpúfŠÉè;Ü®jâÄ÷ ØvRq2ZvM‹öŠûi5Ìæ¡™<S³)·kɃÄm[«%:‚'z
+'¿E“vëöÒ.ÏÃI–ð1urøqßú™k[q¿ä‚à·ÕøºÈÐÑîïo‰øRôΗnG<ùÊÒ¥e›ŽpSñ´û_"¾KoI<ã|Õð(õ$`¼~¼¸Mòé]bÖ–xì4£jH<½ñÓvä–ñLÀ€èé7X/À}補xLL8oF¼O—p&ä€Ñ>;Yî¿Öïú¹´Aš/@+âé]dçîK.Š¨ãøâË´q¾Eœ·³U2Ž6ƒ=hÏȯˆïºóåH:ß"nd½=®¦ˆ²Tìc„ xNþ€ø9ñ;7•Qß"ŽæL%ñ589rÌA²V™—õÒ…—öØëª'ØšµÖ!æJ,0éwˆk9š6Ä9™Ìd1ŸŒ:抡.ùñµ‰™ü+ö¸Vë¿w
+ˆ÷Y{ç^Ô©pqÝ=å¡iM!Þo1Êh­Þ3
+ÆÖ~½„
+Iĵö53¨"r>Áð0q¾½íJâ`®c;.â,EÎ3ðÉõôf‡©÷*ZcÁePXp
+‰Ïm“ÞOñ¹âté©0{C1{S5ω‰1â¼6Ï9d$?©¿Žù•ñaÃþ­<g„¸ê+] ‚¦Nh”]Êö—fõï=O§!ÓJ,פT]TKˆ/àˆ§™‡ìIâ  }ƒ$µ@±ˆ?žgÅåÞ%åO½vë|´&ËoAÀ&‡¹•4öôT¼`‚i2Òñ”VeO­Ë
+âþm-kˆ_ø.=”‚­¯Ä'í¶gZQÒòa
+#+æQâŸ÷i7¯üôv«èfNkœ‡B*’ñµ×ÖQMŽ’ÀŒ¹®…ìžÙ8kˆ“Sù™?ÍÛ$
+±Ÿ¬TÁ­ q‰fÄk	àÜuòb•ˆ6•Øîf3´U5óþAj^öa10ñ-²ž¡õF6ÜÅl5-šcZâÞ¥\¶RãýEAÖ?Jü2^£È]âr鏇cƒ©Üø¡ÀgÂØgSžß%¨W+ncoëiígTy¨‚Ž–lA&åÇ÷JàíÑQÀ²eý	p+ç«“–°?éF^}ÖmU°«­«WZ§Ï1½œŒH("ÄoÂÈ彿˜¨Ùz|µ4Õç9A¡ë‹(âµjåØ÷û‰bwßÐåºßéï¶CI(5उë§Ù{çy‘ô4·U‚ƚܲÐÑ—ê\¨g½’ÐóSŒÊEˆKgé2©3ÉÕõo]Ú0,W¼µ;—úl½^Ú«7Ç»ìe.FÇg…”–˜{Q—RiŠþ%­òô¯Ø1ë³ðšŒS
+{Oº®éÍ(r‚qaòl¯¸Œ“{\¥OŒFig Ô¸¶L­
+m™.cuÛ,žŸU›ä|[ÔÁò+‡¢œ6?LSˆ§Û€<iÓZ;¿TÕB;Ô
+œkcûj°‰;TŠ«!˜n
+qiÛmî°H†©bQÉš¿§|§)*ël¾®Ø’gShÖ˽Ã"cà£P²éÜù¬ÏäÍ“¤¶O¯îw+Æêyu^A}¹4ãÐÀ#g)Ä-‹Üx\˜d½’œýŽ'ð:ˆºüoRÒ—’⥣ü*zˆ‹$­rl±{a3èÏ?˵WÒ/­‹‡6¼Œ{GŽ­-sóìîÞ&s…ö@88IAáíWúݨÀóÕ
+`ó@?×$M^§2%aµO¶EVÖ".´—çæÕ
+;âÀÀSDF|^7¸[¤ZÛ&??ëåä9Áf‡ÉiðýEI at k¹#Lë~=‹)¥ÛnÃ)ÙJû´(°íxäšÔ[óGê¼F‘ÃœK)3ˆwIÁšS‚}6¢Œ»²—ËGô®ú÷fräÒml…YG|žÜR¼ÂÁnU/kÅâf'r>œgSœj+Ô*Adg§
+<çzòyqï¿Ï?WÑ ÓÚ]èJâsñ¯:íK„œïAÿ5p¾Ý=ºÂCeÞÚ•¹s¦}¦+´€3tù³B»Ù2Mp5©•î¤.ÅXO|R(ŸÌC3ï;漐Nù[D|Sͽæö	â¨>T®ø.U’Ï–Ê|Ÿø\ðIÇÄ-›¨ ¸bó|ÞMˆß¦éô¾zdõö͘án脵‰×·CO9큎ÛO¬NJX–²þq¤ý¥
+ÇýÊóÁm–ÔÅVÙ׬ GéUâ7Ç
+óO€Â-‹ç‡Àí•0ú5⓱¬ï3p‹ËÇ3Ì2Ç.Æî¼3ìWÿVwSÕ $°¬ìvå¶Äç]ÿî>
+Þ9U§º«§‰>µÕÄÝÁÈýÏô_ >Yµ`ósÙÇŸö::H§OA‡Ìº:ùìrœ4¼¸ÔüÙÅRl2£ÕØŒxü¸Z6ħ™Ã•
+Üÿ€l‡»-Áó÷}düÖ	…ŒjlG<ê¼p‰Ë¸2ïM~yÄñ܏ò,v„ÜŽrO¬i4/n-?:ûQ·ƒà:z—xñý3t,F”7–Ã~Š7 Ž©ï¹Œ¥ä؇8pÄ¡®“[ÿx²d¶÷Õ
+Ñ–øªMå±>ãRc¸ïü=n¢UŒû¹ìjŽm‰†üŠ	®±Ï®ã€
+ÇǶė·`ýÜm<Ï!õ’›ônsÑ·9²BØ(}7grœwXɃi:p¯,iG|Úõû‡ë”5³ÑÍ“RÁls.qL°}ËüÙ‘7-¯?(ñÉÉ[ˆã«A†¼ÅÕkmC|Þš¨tš-9¶÷âÿLó—e(®%ލÞ粍0äÖB×?„3ñK8úJ87">-ý9ù™>…¯ìõ¬EèKç€'¶r7Å’K\ù‰ÛÈy,–.z¸º!ðêÉkOâÝŽË4">öƒG!>Ø…¶ù(ÆÐÅK¸çö­}ežs·ÓØšìÌâ>2j³SN!¿ÂZ?§…¤D"c(I±åÈDpš™ÄuxÂi´Ë"œŒAÚñsP0 䀌Oÿ`<zQàe›—Í“»Êаe·‡oáA˜I…‰$+΃Ö_‡ÖS
+ˆÈ2§ø&‘·t§­T8º:
+û3ðÏB­$.#Ï…rÃYOvׂQàŒèÂñQ⻳r¾®b.³9|7´ß~wá6ÇÚÆ‹Z×±çê3ŒØisÊŠà¥×É·$~¿óK‰¸M
+øoç©@Î$Žžëœ»Âqä¤sìøß'>:kŸÀ±³À¥¢'ÀÛ‘;/àYõmb‡¶ç¼ƒQ(ŽN£ýoˆŸ¦}—”µÇ7rg1hïäE®ù~â-›8½QDþŠYY`Ǫ¾K|T›˜Sz?‡[ͶÜQßsò€ÌšDÍ'~Û<·Î'/_‚)ÊëKÙœøô¸ë1siùüýdD—úœàý»ÜÅuÝT—i©’ž+¿°@fºâÀƒ*i62ÛƒÜrtÀþmôL«±¿¥ÊÑÕÅ£®ÇÌ"Îù=mÆ&Å3`¤kÞ$—¸vX¤Z”Ÿ–'˜ÃÅ'×sóç´èDĤÔ_­Èù@AqM`ÎÚ%&C­A\ë‹û›e¸œø¸%öØEÄêgÏׯ—õyšn—¿1Ó:Ô™Ú²O®7Ç{‹«_êq§‚0[œé¡¼å£¾ÉlW†ŽOX‡WÙSZELôcëðöìfm˜/ž
+ã&P÷ÊÊ5m F\¡èˆË¤Zš‰â ŠÁp]v˜'˸¨ŸY‚c4yž‹ÄÏ£‡ªX at 1‘qâÍD º‘Rmäø§‡	™bË!ñîkÄYï‘vs§€#HÆ??¸¿DdS‚è«ÄwðžB¡ÿ+ÛÀ;ñþÄÿ»ƒ„vq¶Yb/ñ†#’£l÷6^âßPãç°ÔK¼áˆ‡5ôK¼åØ
+%¨	:e/ñvc?âO‚%-/ñvVoBñy‰7	es¥êK¼™1žè^âßñ%.úo¬ÅwýátøÇ—x»atB·5þo5lÜ_aÈK¼ÉH;…H^â{<¤6^œÖ{o­Ò~‰sv²ŽyJÝ<Ý«Í^â›™QÁ<88®¹{‰ù`Pع[ÙÀ©£
+½Db‡¾Äa‰)#¼K«›Éõñh<
+Ä^â÷rºåþÞGtºÊªcýÔ™¿ÄýŒÌ_µ$s„|NG¾ÄÃ	aƍ…ö	}÷ÓÂ/ñ‹ËÍÝ€m”¶¾9•ù¾ÄK®Ð>ÅÓzŒ/q—T2Òz½Ë—x;â:O§¼ÄÇœ; œ®MÊ¡²—xÀåÌq£Üº¹ä%^I<tàýèåôOr€2G综e|‰?Aœrí^,·6/ñ±I7àN`ç¢÷¾/ñ±WTè¤F/ñ6ĦLtÓ|‰¯aÀ6Ä—k«}½œ^âÍ\Îà+p‡z_âýCÀÏ4z ý2·¦ÃMÖK
+lÍ›€ùÿ²²yÄË‚‡R¤/ñôVGl-èĝ¶‹ÔÓ½Ä{…'iòUßs†•ÿ~´~ñ%¾›,~èøö¿Ú (^/ú?Aï¨;u/-D®ŠqžTA÷¿: FßèR™°»b.«D_âêöåfÖK at wã%£ÛÔKÜm¿Ìà|Šý$ñt"³·×K<hÃôià¨K¤
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/right.gif
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/right.gif	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/imgs/right.gif	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,2 @@
+GIF89a
+
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.css
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.css	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.css	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ */ /* CSS Document */
+#main {
+    font-family: Verdana, Arial, Helvetica, sans-serif;
+    font-size: 10px;
+    color: black;
+    background-color: white;
+    border-collapse: collapse;
+    padding: 0px;
+    margin: 30px 0 30px 30px;
+    width: 957px;
+    position: absolute;
+    text-align: left;
+    border-color: black;
+}
+
+#lead {
+    color: #00678C;
+    /* color: #ffffff; */
+    margin: 0px 0px 26px 0px;
+    padding: 0px;
+    width: 957px;
+    height: 100px;
+}
+
+#lead h1 { /*
+    background-image: url(../imgs/banner_left.jpg);
+    background-repeat: no-repeat;
+    */
+    margin: 0px;
+    padding: 5px 0 0 8px;
+    font-size: 300%;
+    font-weight: bold;
+    line-height: 120%;
+    height: 95px;
+    /* account for 5px top marging to get a total of 100px */
+    float: left;
+}
+
+#lead br {
+    line-height: 20px;
+}
+
+#lead p { /*
+    background-image: url(../imgs/banner_right.jpg);
+    background-repeat: no-repeat;
+    border-left: 1px solid;
+        */
+    margin: 0px;
+    padding: 0px;
+    height: 100px;
+    float: right;
+}
+
+#technav {
+    border-bottom: 1px solid #6181A9;
+    border-top: 1px solid #6181A9;
+    color: black;
+    font-size: 10px;
+    font-weight: bold;
+    /*
+    border-top: 1px solid black;
+    */
+    line-height: 21px;
+    padding: 0;
+    margin: 0;
+}
+
+#technav a {
+    /*
+    display: block;
+    float: left;
+    */
+    text-decoration: none;
+    padding: 3px 10px 3px 10px;
+    color: #6181A9;
+    text-decoration: none;
+}
+
+#technav a:hover {
+    background-color: black;
+}
+
+#technav .technavat {
+    /*
+    display: block;
+    float: left;
+    */
+    text-decoration: none;
+    padding: 3px 10px 3px 10px;
+    background-color: #B6CAE4;
+    color: black;
+}
+
+#claim {
+    color: white;
+    background-color: black;
+    padding: 2px 10px 2px 10px;
+}
+
+#claim p {
+    margin: 0;
+    padding: 0;
+}
+
+#claim a {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+/*
+.claimcell A:link {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:visited {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+*/
+#claim a:hover {
+    color: #99FF33;
+    border-bottom: 1px solid;
+}
+
+#claim a:active {
+    color: #FFFFFF;
+}
+
+/* old styles */
+table {
+    text-align: left;
+}
+
+table.content {
+    clear: both;
+    font-size: 10px;
+    line-height: 13px;
+    border: 0px solid #66dd44;
+    border-top: 1px solid #cccccc;
+    padding: 0px;
+    margin: 0px;
+    margin-top: 26px;
+    margin-bottom: 26px;
+    /* width: 718px; */
+    text-align: left;
+}
+
+tr {
+    border-left: 1px solid #cccccc;  
+    border-right: 1px solid #cccccc;  
+}
+
+td.content {
+    color: #333333;
+    border: 0px solid #66dd44;
+    border-bottom: 1px solid #cccccc;
+    vertical-align: middle;
+    padding: 5px;
+}
+
+td.aligntop {
+    vertical-align: top;
+}
+
+td.content img {
+    width: 10px;
+    height: 10px;
+}
+
+td.disabled {
+    color: #999999;
+}
+
+th.content {
+    color: #333333;
+    border: 0px solid #66dd44;
+    border-bottom: 1px solid #cccccc;
+    text-align: left;
+    padding: 5px;
+    padding-left: 10px;
+}
+
+.right {
+    text-align: right;
+}
+.center {
+    text-align: center;
+}
+
+th.container {
+    color: #6181A9;
+    background-color: #f0f0f0;
+}
+
+th.important {
+    color: #B81833;
+}
+
+.important {
+    color: #B81833;
+}
+
+#maintable { /* postion: absolute; */
+    font-size: 10px;
+    line-height: 13px;
+    border: 1px solid #000000;
+    padding: 0px;
+    margin: 0px;
+    width: 960px;
+}
+
+.toolcell {
+    font-size: 10px;
+    color: #999999;
+    line-height: 10px;
+    background-color: #000000;
+    height: 18px;
+    /* width: 960px; */
+    padding: 0px;
+    padding-bottom: 1px;
+    text-align: left;
+}
+
+.toolcell A:link {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+.toolcell A:visited {
+    color: #C5E2EE;
+    text-decoration: none;
+}
+
+.toolcell A:hover {
+    color: #99FF33;
+    text-decoration: none;
+    border-bottom: 1px solid;
+}
+
+.toolcell A:active {
+    color: #FFFFFF;
+    text-decoration: none;
+}
+
+.leadcell {
+    margin: 0px;
+    padding: 0px;
+    border: 0px solid #000000;
+    width: 718px;
+    height: 100px;
+    background-image: url(../imgs/banner_left.jpg);
+    vertical-align: top;
+}
+
+.leadcelltext {
+    position: absolute;
+    border: 0px solid #000000;
+    font-size: 26px;
+    line-height: 32px;
+    margin-top: 5px;
+    margin-left: 8px;
+    color: #ffffff;
+    vertical-align: top;
+}
+
+.logocell {
+    border-left: 1px solid #000000;
+    width: 239px;
+    background-image: url(../imgs/banner_right.jpg);
+}
+
+#technavcell {
+    font-size: 10px;
+    font-weight: bold;
+    border: 0px solid #000000;
+    border-top: 1px solid #000000;
+    height: 21px;
+    background-color: #6181A9;
+}
+
+/*
+#technav A:link {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border: 0px solid #000000;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+
+#technav A:visited {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+
+#technav A:hover {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #000000;
+}
+
+#technav A:active {
+	float: left;
+	display: block;
+	color: #ffffff;
+	border-right: 1px solid #000000;
+	height: 21px;
+	text-decoration: none;
+	padding: 0px 10px 0px 10px;
+	background-color: #6181A9;
+}
+*/
+.techcontentcell { /* width: 718px; */
+    border: 0px solid #000000;
+    border-top: 1px solid #000000;
+}
+
+.relatedcell {
+    border-left: 1px solid #000000;
+    border-top: 1px solid #000000;
+    width: 239px;
+    background-color: #EBF0F6;
+}
+
+/*
+.claimcell {
+	width: 715px;
+	font-size: 10px;
+	color: #ffffff;
+	line-height: 10px;
+	background-color: #000000;
+	height: 18px;
+	padding: 0px;
+	padding-bottom: 1px;
+}
+
+.claimcell A:link {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:visited {
+	color: #C5E2EE;
+	text-decoration: none;
+}
+
+.claimcell A:hover {
+	color: #99FF33;
+	text-decoration: none;
+	border-bottom: 1px solid;
+}
+
+.claimcell A:active {
+	color: #FFFFFF;
+	text-decoration: none;
+}
+*/ /* CENTRAL CONTENT AREA STYLING */
+.content {
+    position: relative;
+    margin: 25px;
+    font-size: 11px;
+    line-height: 16px;
+    color: #000000;
+}
+
+.content A:link {
+    color: #336600;
+    text-decoration: underline;
+}
+
+.content A:visited {
+    color: #666666;
+    text-decoration: underline;
+}
+
+.content A:hover {
+    color: #ffffff;
+    background-color: #336600;
+    text-decoration: none;
+}
+
+.content A:active {
+    color: #ffffff;
+    background-color: #000000;
+    text-decoration: none;
+}
+
+body {
+	background-color: white;
+}
+
+/* TEXT STYLING */ /*
+h1, h2, h3, h4, h5, h6, p
+
+	{
+	margin: 0px;
+	margin-bottom: 8px;
+	font-size: 11px;
+	line-height: 16px;
+	font-weight:bold;
+	}
+
+*/ /*
+h1
+	{
+	color: #000000;
+	margin-top: 32px;
+	clear: left;
+	}
+
+
+h2
+	{
+	color: #336699;
+	}
+
+
+h3
+	{
+	color: #336699;
+	}
+*/ /*
+p
+	{
+	font-size: 11px;
+	line-height: 16px;
+	font-weight: normal;
+	color: #000000;
+	}
+*/ /* FORMS */
+form {
+    font-size: 9px;
+    border-top: 0px solid #000000;
+    border-bottom: 0px solid #000000;
+    border-left: 0px solid #000000;
+    border-right: 0px solid #000000;
+    margin: 0;
+    padding: 0;
+    clear: left;
+}
+
+select,textarea {
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 9px;
+    font-weight: normal;
+    display: block;
+    float: left;
+    padding-top: 3px;
+    margin-bottom: 10px;
+}
+
+.input {
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 9px;
+    font-weight: normal;
+    color: #184054;
+    background-color: #f0f0f0;
+    border: 1px solid #999999;
+    border-bottom: 1px solid #cccccc;
+    border-right: 1px solid #cccccc;
+}
+
+.submit {
+    cursor: default;
+    width: 60px;
+    font-family: Verdana, Arial, Helvetica, san-serif;
+    font-size: 10px;
+    font-weight: bold;
+    background-color: #f0f0f0;
+    height: 20px;
+    padding: 0px;
+    padding-bottom: 1px;
+    margin: 0px;
+    border: 1px solid #cccccc;
+    border-bottom: 1px solid #666666;
+    border-right: 1px solid #666666;
+}
+
+input.important {
+    background-color: #B81833;
+    color: #ffffff;
+}
+
+select {
+    color: #184054;
+    background-color: #f0f0f0;
+    border: 0px solid #999999;
+}
+
+textarea {
+    color: #184054;
+    background-color: #f0f0f0;
+    width: 234px;
+    height: 100px;
+    border: 1px solid #999999;
+    border-bottom: 1px solid #cccccc;
+    border-right: 1px solid #cccccc;
+}
+
+.clearleft {
+    clear: left;
+}
+
+.clearboth {
+    clear: both;
+}
+
+.checkradio {
+    background-color: #ffffff;
+    width: 20px;
+    padding: 0px;
+    padding-bottom: 10px;
+    margin: 0px;
+    margin-top: 2px;
+    border: 0px solid #999999;
+}
+
+.checkradiotext {
+    font-size: 9px;
+    font-weight: normal;
+    line-height: 11px;
+    width: 100px;
+    color: #000000;
+    padding: 0px;
+    padding-bottom: 10px;
+    margin: 0px;
+    margin-top: 4px;
+    border: 0px solid #999999;
+}
+
+div.buttons {
+    background-color: #6181A9;
+    height: 30px;
+}
+div.button {
+	float:right;
+    margin-top: 5px;
+	margin-right: 10px;
+}
+div.fullwidth {
+    width: 100%;
+}
+div.statusline {
+    margin-top: 10px;
+    background-color: #F5F5F5;
+    padding-left: 10px;
+    border: 1px solid #CCCCCC;
+    font-size: 13px;
+    color: #222222;
+    line-height: 19px;
+    margin-bottom: 10px;
+}
+div.table {
+	margin-left: 1px;
+}
+div.tablelayout {
+}
+
+/* tables */
+table.tablelayout {
+	border-left: 1px solid #6181A9;
+    border-right: 1px solid #6181A9;
+    border-collapse: collapse;
+	font-family:arial;
+    background-color: #CDCDCD;
+    font-size: 8pt;
+    width: 100%;
+    text-align: left;
+}
+table.tablelayout tbody tr {
+    border-left: 1px solid #6181A9;
+    border-right: 1px solid #6181A9;
+}
+
+table.tablelayout thead tr th, table.tablelayout tfoot tr th {
+    background-color: #e6EEEE;
+    border-left: 1px solid #6181A9;
+    border-right: 1px solid #6181A9;
+    border-top: 1px solid #FFF;
+    border-bottom: 1px solid #FFF;
+    font-size: 8pt;
+    padding: 4px;
+}
+table.tablelayout thead tr .header {
+    background-image: url(../imgs/bg.gif);
+    background-repeat: no-repeat;
+    background-position: center right;
+    cursor: pointer;
+}
+table.tablelayout tbody td {
+    color: #3D3D3D;
+    border-top: 1px solid #6181A9;
+    border-bottom: 1px solid #6181A9;
+    padding: 4px;
+    background-color: #FFF;
+    vertical-align: top;
+}
+table.tablelayout tbody tr.odd td {
+    background-color:#F0F0F6;
+}
+table.tablelayout thead tr .headerSortUp {
+    background-image: url(../imgs/asc.gif);
+}
+table.tablelayout thead tr .headerSortDown {
+    background-image: url(../imgs/desc.gif);
+}
+table.tablelayout thead tr .headerSortDown, table.tablelayout thead tr .headerSortUp {
+background-color: #8dbdd8;
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/admin.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+
+/* shuts down server after [num] seconds */
+function shutdown(num, formname, elemid) {
+	var elem;
+	var canCount = document.getElementById;
+	if (canCount) {
+	    elem = document.getElementById(elemid);
+	    canCount = (typeof(elem) != "undefined" && typeof(elem.innerHTML) != "undefined");
+	}
+	var secs=" second";
+	var ellipsis="...";
+	if (num > 0) {
+		if (num != 1) {
+			secs+="s";
+		}
+		if (canCount) {
+		    elem.innerHTML=num+secs+ellipsis;
+		}
+		setTimeout('shutdown('+(--num)+', "'+formname+'", "'+elemid+'")',1000);
+	} else {
+	    document[formname].submit();
+	}
+}
+
+/* aborts server shutdown and redirects to [target] */
+function abort(target) {
+    top.location.href=target;
+}
+
+/* checks if values of [pass1] and [pass2] match */
+function checkPasswd(form, pass0, pass1, pass2) {
+    var check = false;
+    check = (form[pass0].value != form[pass1].value);
+    if (!check) {
+        alert("Old and new password must be different.");
+        form[pass1].value="";
+        form[pass2].value="";
+        form[pass1].focus();
+    }
+    check = (form[pass1].value == form[pass2].value);
+    if (!check) {
+        alert("Passwords did not match. Please type again.");
+        form[pass1].value="";
+        form[pass2].value="";
+        form[pass1].focus();
+    }
+    return check;
+}
+
+/* displays a date in the user's local timezone */
+function localDate(time) {
+    var date = time ? new Date(time) : new Date();
+    document.write(date.toLocaleString());
+}
+
+//-----------------------------------------------------------------------------
+// Ajax Support
+
+// request object, do not access directly, use getXmlHttp instead
+var xmlhttp = null;
+function getXmlHttp() {
+	if (xmlhttp) {
+		return xmlhttp;
+	}
+	
+	if (window.XMLHttpRequest) {
+		xmlhttp = new XMLHttpRequest();
+	} else if (window.ActiveXObject) {
+		try {
+			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
+		} catch (ex) {
+			try {
+				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+			} catch (ex) {
+			}
+		}
+	}
+	
+	return xmlhttp;
+}
+
+function sendRequest(/* String */ method, /* url */ url, /* function */ callback) {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp) {
+        return;
+    }
+    
+    if (xmlhttp.readyState < 4) {
+    	xmlhttp.abort();
+  	}
+  	
+  	if (!method) {
+  		method = 'GET';
+  	}
+  	
+  	if (!url) {
+  		url = document.location;
+  	} else if (url.charAt(0) == '?') {
+  		url = document.location + url;
+    }
+  	
+    priv_callback = callback;
+
+    xmlhttp.open(method, url);
+    
+    // set If-Modified-Since way back in the past to prevent
+    // using any content from the cache
+    xmlhttp.setRequestHeader("If-Modified-Since", new Date(0));
+    
+    xmlhttp.onreadystatechange = handleResult;
+    xmlhttp.send(null);
+  	
+}
+
+var priv_callback = null;
+
+function handleResult() {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp || xmlhttp.readyState != 4) {
+        return;
+    }
+    
+    var result = xmlhttp.responseText;
+    if (!result) {
+        return;
+    }
+
+    var theCallBack = priv_callback;
+    priv_callback = null;
+    
+	if (theCallBack) {
+	    try
+        {
+            var obj = eval('(' + result + ')');
+	       theCallBack(obj);
+        }
+        catch (e)
+        {
+            // error evaluating response, don't care ...
+        }
+	}
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/bundles.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/bundles.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/bundles.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+function renderBundle( /* Array of Data Objects */ bundleData )
+{
+
+    // number of actions plus 3 -- id, name and state
+    var columns = bundleData.numActions + 3;
+    var startLevel = bundleData.startLevel;
+    
+    header( columns );
+
+    installForm( startLevel );
+    
+    if (bundleData.error)
+    {
+        error( columns, bundleData.error );
+    }
+    else
+    {
+        data ( bundleData.data );
+    }
+
+    installForm( startLevel );
+
+    footer( columns );
+}
+
+function installForm( /* int */ startLevel )
+{
+    document.write( "<form method='post' enctype='multipart/form-data'>" );
+    document.write( "<tr class='content'>" );
+    document.write( "<td class='content'>&nbsp;</td>" );
+    document.write( "<td class='content'>" );
+    document.write( "<input type='hidden' name='action' value='install' />" );
+    document.write( "<input class='input' type='file' name='bundlefile' size='50'>" );
+    document.write( " - Start <input class='checkradio' type='checkbox' name='bundlestart' value='start'>" );
+    document.write( " - Start Level <input class='input' type='input' name='bundlestartelevel' value='" + startLevel + "' size='4'>" );
+    document.write( "</td>" );
+    document.write( "<td class='content' align='right' colspan='5' noWrap>" );
+    document.write( "<input class='submit' style='width:auto' type='submit' value='Install or Update'>" );
+    document.write( "&nbsp;" );
+    document.write( "<input class='submit' style='width:auto' type='button' value='Refresh Packages' onClick='changeDataEntryState(0, \"refreshPackages\");'>" );
+    document.write( "</td>" );
+    document.write( "</tr>" );
+    document.write( "</form>" );
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/configmanager.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/configmanager.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/configmanager.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,436 @@
+/*
+ * 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.
+ */
+
+
+function configure() {
+    var span = document.getElementById('configField');
+    if (!span) {
+        return;
+    }
+    var select = document.getElementById('configSelection_pid');
+    var pid = select.options[select.selectedIndex].value;
+    var parm = pluginRoot + '/' + pid;
+    sendRequest('POST', parm, displayConfigForm);
+}
+
+
+function create() {
+    var span = document.getElementById('configField');
+    if (!span) {
+        return;
+    }
+    var select = document.getElementById('configSelection_factory');
+    var pid = select.options[select.selectedIndex].value;
+    var parm = pluginRoot + '/' + pid + '?create=true';
+    sendRequest('POST', parm, displayConfigForm);
+}
+
+function displayConfigForm(obj) {
+    var span1 = document.getElementById('configField');
+    var span2 = document.getElementById('factoryField');
+    if (!span1 && !span2) {
+        return;
+    }
+    
+    var parent = span1 ? span1.parentNode : span2.parentNode;
+    
+    clearChildren( parent );
+    
+    if (span1) {
+        parent.appendChild( span1 );
+    }
+    if (span2) {
+        parent.appendChild( span2 );
+    }
+    
+    var trEl = tr( "content" );
+    var tdEl = createElement( "th", "content", { colSpan: "2" } );
+    addText( tdEl, obj.title );
+    trEl.appendChild( tdEl );
+    parent.appendChild( trEl );
+
+    trEl = tr( "content" );
+    parent.appendChild( trEl );
+    
+    tdEl = td( "content" );
+    addText( tdEl, "\u00a0" );
+    trEl.appendChild( tdEl );
+    
+    tdEl = td( "content" );
+    trEl.appendChild( tdEl );
+    
+    var formEl = createElement( "form", null, {
+            method: "post",
+            action: pluginRoot + "/" + obj.pid
+        });
+    tdEl.appendChild( formEl );
+    
+    var inputEl = createElement( "input", null, {
+            type: "hidden",
+            name: "apply",
+            value: "true"
+        });
+    formEl.appendChild( inputEl );
+    
+    // add the factory PID as a hidden form field if present
+    if (obj.factoryPid)
+    {
+        inputEl = createElement( "input", null, {
+                type: "hidden",
+                name: "factoryPid",
+                value: obj.factoryPid
+            });
+        formEl.appendChild( inputEl );
+    }
+    
+    // add the PID filter as a hidden form field if present
+    if (obj.pidFilter)
+    {
+        inputEl = createElement( "input", null, {
+                type: "hidden",
+                name: "pidFilter",
+                value: obj.pidFilter
+            });
+        formEl.appendChild( inputEl );
+    }
+    
+    inputEl = createElement( "input", null, {
+            type: "hidden",
+            name: "action",
+            value: "ajaxConfigManager"
+        });
+    formEl.appendChild( inputEl );
+    
+    var tableEl = createElement( "table", null, {
+            border: 0,
+            width: "100%"
+        });
+    formEl.appendChild( tableEl );
+    
+    var bodyEl = createElement( "tbody" );
+    tableEl.appendChild( bodyEl );
+    
+    if (obj.description)
+    {
+        trEl = tr( "content" );
+        tdEl = td( "content", { colSpan: "2" } );
+        addText( tdEl, obj.description );
+        trEl.appendChild( tdEl );
+        bodyEl.appendChild( trEl );
+    }
+    
+    if (obj.propertylist == 'properties')
+    {
+        printTextArea(bodyEl, obj.properties);
+    }
+    else
+    {
+        printForm(bodyEl, obj);
+    }
+    
+    trEl = tr( "content" );
+    bodyEl.appendChild( trEl );
+    
+    tdEl = td( "content" );
+    addText( tdEl, "\u00a0" );
+    trEl.appendChild( tdEl );
+    
+    tdEl = td( "content" );
+    trEl.appendChild( tdEl );
+
+    // define this TD as innerHTML otherwise the onClick event handler
+    // of the Delete button is not accepted by IE...    
+    var innerHTML = '<input type="submit" class="submit" name="submit" value="Save" />';
+    innerHTML += '&nbsp;&nbsp;&nbsp;';
+    innerHTML += '<input type="reset" class="submit" name="reset" value="Reset" />';
+    innerHTML += '&nbsp;&nbsp;&nbsp;';
+    innerHTML += '<input type="submit" class="submit" name="delete" value="Delete" onClick="return confirmDelete();"/>';
+    tdEl.innerHTML = innerHTML;
+
+    printConfigurationInfo(parent, obj);
+}
+
+function printTextArea(/* Element */ parent, props )
+{
+    
+    var propsValue = "";
+    for (var key in props)
+    {
+        propsValue += key + ' =  ' + props[key] + '\r\n';
+    }
+
+    return tr( "content", null, [
+        td( "content aligntop", null, [
+            text( "Properties" )
+        ]),
+        td( "content", { style: { width: "99%" } }, [
+            createElement( "textarea", null, {
+                    name: "properties",
+                    style: { height: "50%", width: "99%" }
+                }, [ text( propsValue ) ] ),
+            text( "Enter Name-Value pairs of configuration properties" )
+        ])
+    ]);        
+}
+
+function printForm( /* Element */ parent, obj ) {
+    var propList;
+    for (var idx in obj.propertylist)
+    {
+        var prop = obj.propertylist[idx];
+        var attr = obj[prop];
+  
+        var trEl = tr( "content", null, [
+                td( "content aligntop", null, [ text( attr.name ) ] )
+            ]);
+        parent.appendChild( trEl );
+
+        var tdEl = td( "content", { style: { width: "99%" } } );
+        trEl.appendChild( tdEl );
+  
+        if (attr.value != undefined)
+        {
+            // check is required to also handle empty strings, 0 and false
+            tdEl.appendChild( createInput( prop, attr.value, attr.type, '99%' ) );
+            tdEl.appendChild( createElement( "br" ) );
+        }
+        else if (typeof(attr.type) == 'object')
+        {
+        	// assume attr.values and multiselect
+        	createMultiSelect( tdEl, prop, attr.values, attr.type, '99%' );
+            tdEl.appendChild( createElement( "br" ) );
+        }
+        else if (attr.values.length == 0)
+        {
+            tdEl.appendChild( createSpan( prop, "", attr.type ) );
+        }
+        else
+        {
+            for (var vidx in attr.values)
+            {
+                tdEl.appendChild( createSpan( prop, attr.values[vidx], attr.type ) );
+            }
+        }
+        
+        if (attr.description)
+        {
+            addText( tdEl, attr.description );
+        }
+        
+        if (propList) {
+            propList += ',' + prop;
+        } else {
+            propList = prop;
+        }
+    }
+    
+    parent.appendChild( createElement( "input", null, {
+            type: "hidden",
+            name: "propertylist",
+            value: propList
+        })
+    );
+}
+
+function printConfigurationInfo( /* Element */ parent, obj )
+{
+    parent.appendChild( tr( "content", null, [
+            createElement( "th", "content", { colSpan: "2" }, [
+                text( "Configuration Information" )
+            ])
+        ])
+    );
+    
+    parent.appendChild( tr( "content", null, [
+            td( "content", null, [
+                text( "Persistent Identity (PID)" )
+            ]),
+            td( "content", null, [
+                text( obj.pid )
+            ])
+        ])
+    );
+
+    if (obj.factoryPid)
+    {
+        parent.appendChild( tr( "content", null, [
+                td( "content", null, [
+                    text( "Factory Peristent Identifier (Factory PID)" )
+                ]),
+                td( "content", null, [
+                    text( obj.factoryPid )
+                ])
+            ])
+        );
+    }
+    
+    var binding = obj.bundleLocation;
+    if (!binding)
+    {
+        binding = "Unbound or new configuration";
+    }
+    
+    parent.appendChild( tr( "content", null, [
+            td( "content", null, [
+                text( "Configuration Binding" )
+            ]),
+            td( "content", null, [
+                text( binding )
+            ])
+        ])
+    );
+}
+
+
+var spanCounter = 0;
+/* Element */ function createSpan(prop, value, type) {
+    spanCounter++;
+    var newId = prop + spanCounter;
+    
+    var spanEl = createElement( "span", null, { id: newId }, [
+        createInput( prop, value, type, '89%' )
+    ]);
+    
+    // define this SPAN as innerHTML otherwise the onClick event handler
+    // of the buttons is not accepted by IE...    
+    var innerHTML = "<input type='button' class='input' style='width:\"5%\"' value='+' onClick='addValue(\"" + prop + "\", \"" + newId + "\")' />";
+    innerHTML += "<input type='button' class='input' style='width:\"5%\"' value='-' onClick='removeValue(\"" + newId + "\")' />";
+    innerHTML += "<br />";
+    spanEl.innerHTML += innerHTML;
+    
+    return spanEl;
+}
+
+/* Element */ function createInput(prop, value, type, width) {
+    if (type == 11) { // AttributeDefinition.BOOLEAN
+
+        var inputEl = createElement( "input", "input", {
+                type: "checkbox",
+                name: prop,
+                value: true
+            });
+            
+        if (value && typeof(value) != "boolean")
+        {
+            value = value.toString().toLowerCase() == "true";
+        }
+        if (value)
+        {
+            inputEl.setAttribute( "checked", true );
+        }
+
+        var hiddenEl = createElement( "input", "input", {
+            type: "hidden",
+            name: prop,
+            value: false
+        });
+        
+        var divEl = createElement("div", "div");
+        divEl.appendChild(inputEl);
+        divEl.appendChild(hiddenEl);
+        return divEl;
+        
+    } else if (typeof(type) == "object") { // predefined values
+    
+        var selectEl = createElement( "select", "select", {
+                name: prop,
+                style: { width: width }
+            });
+
+    	var labels = type.labels;
+    	var values = type.values;
+        for (var idx in labels) {
+            var optionEl = createElement( "option", null, {
+                    value: values[idx]
+                }, [ text( labels[idx] ) ]);
+                
+            if (value == values[idx])
+            {
+                optionEl.setAttribute( "selected", true );
+            }
+            selectEl.appendChild( optionEl );
+    	}
+        
+    	return selectEl;
+        
+    } else { // Simple 
+    
+        return createElement( "input", "input", {
+                type: "text",
+                name: prop,
+                value: value,
+                style: { width: width }
+            });
+    }
+}
+
+function createMultiSelect(/* Element */ parent, prop, values, options, width) {
+    // convert value list into 'set'
+    var valueSet = new Object();
+    for (var idx in values) {
+    	valueSet[ values[idx] ] = true;
+    }
+    
+   	var labels = options.labels;
+   	var values = options.values;
+   	for (var idx in labels) {
+    
+        var inputEl = createElement( "input", null, {
+                type: "checkbox",
+                name: prop,
+                value: values[idx] 
+            });
+    
+        if (valueSet[ values[idx] ])
+        {
+            inputEl.setAttribute( "checked", true );
+        }
+        
+        var labelEl = createElement( "label" );
+        labelEl.appendChild( inputEl );
+        addText( labelEl, labels[idx] );
+        
+        parent.appendChild( labelEl );
+   	}
+}
+
+
+function addValue(prop, vidx)
+{
+    var span = document.getElementById(vidx);
+    if (!span)
+    {
+        return;
+    }
+    var newSpan = createSpan(prop, '');
+    span.parentNode.insertBefore(newSpan, span.nextSibling);
+}
+
+function removeValue(vidx)
+{
+    var span = document.getElementById(vidx);
+    if (!span)
+    {
+        return;
+    }
+    span.parentNode.removeChild(span);
+}
+
+function confirmDelete()
+{
+    return confirm("Are you sure to delete this configuration ?");
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/datatable.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/datatable.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/datatable.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+function renderDataTable( /* Array of Data Objects */ components )
+{
+    // number of actions plus 3 -- id, name and state
+    var columns = components.numActions + 3;
+    
+    header( columns );
+
+    if (components.error)
+    {
+        error( columns, components.error );
+    }
+    else
+    {
+        data ( components.data );
+    }
+
+    footer( columns );
+}
+
+
+function header( /* int */ columns )
+{
+    document.write( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='" + columns + "' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    document.write( "<tr class='content'>" );
+    document.write( "<th class='content'>ID</th>" );
+    document.write( "<th class='content' width='100%'>Name</th>" );
+    document.write( "<th class='content'>Status</th>" );
+    document.write( "<th class='content' colspan='" + (columns - 3) + "'>Actions</th>" );
+    document.write( "</tr>" );
+
+}
+
+
+function error( /* int */ columns, /* String */ message )
+{
+    document.write( "<tr class='content'>" );
+    document.write( "<td class='content'>&nbsp;</td>" );
+    document.write( "<td class='content' colspan='" + (columns - 1) + "'>" + message + "</td>" );
+    document.write( "</tr>" );
+}
+
+
+function data( /* Array of Object */ dataArray )
+{
+    // render components
+    if (dataArray.length == 1)
+    {
+        entry( dataArray[0], true );
+    }
+    else {
+        for ( var idx in dataArray )
+        {
+            entry( dataArray[idx] );
+        }
+    }
+}
+
+
+function footer( /* int */ columns )
+{
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='" + columns + "' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    document.write( "</table>" );
+}
+
+
+function entry( /* Object */ dataEntry, /* boolean */ singleEntry )
+{
+    var trElement = tr( null, { id: "entry" + dataEntry.id } );
+    entryInternal( trElement,  dataEntry, singleEntry );
+    document.write( serialize( trElement ) );
+
+    // dataEntry detailed properties
+    trElement = tr( null, { id: "entry" + dataEntry.id + "_details" } );
+    if (dataEntry.props)
+    {
+        getDataEntryDetails( trElement, dataEntry.props );
+    }
+    document.write( serialize( trElement ) );
+}
+
+
+function entryInternal( /* Element */ parent, /* Object */ dataEntry, /* boolean */ singleEntry )
+{
+
+    var id = dataEntry.id;
+    var name = dataEntry.name;
+    var state = dataEntry.state;
+    var icon = singleEntry ? "left" : (dataEntry.props ? "down" : "right");
+    var event = singleEntry ? "history.back()" : "showDataEntryDetails(" + id + ")"; 
+
+    parent.appendChild( td( "content right", null, [ text( id ) ] ) );
+    
+    parent.appendChild( td( "content", null, [
+            createElement( "img", null, {
+                src: appRoot + "/res/imgs/" + icon + ".gif",
+                onClick: event,
+                id: "entry" + id + "_inline"
+            } ),
+            text( "\u00a0" ),
+            createElement( "a", null, {
+                href: pluginRoot + "/" + id
+            }, [ text( name ) ]
+            )]
+        )
+    );
+
+    parent.appendChild( td( "content center", null, [ text( state ) ] ) );
+
+    for ( var aidx in dataEntry.actions )
+    {
+        var action = dataEntry.actions[aidx];
+        parent.appendChild( actionButton( action.enabled, id, action.link, action.name, action.title ) );
+    }
+}
+
+
+/* Element */ function actionButton( /* boolean */ enabled, /* long */ id, /* String */ op, /* String */ opLabel, /* String */ title )
+{
+    var buttonTd = td( "content", { align: "right" } );
+    if ( op )
+    {
+        var input = createElement( "input", "submit", {
+                type: 'button',
+                value: opLabel,
+                onClick: 'changeDataEntryState(' + id + ', "' + op + '");'
+            });
+        if (!enabled)
+        {
+            input.setAttribute( "disabled", true );
+        }
+        if (title)
+        {
+            input.setAttribute( "title", title );
+        }
+        buttonTd.appendChild( input );
+    }
+    else
+    {
+        addText( buttonTd, "\u00a0" );
+    }
+    
+    return buttonTd;
+}
+
+
+function getDataEntryDetails( /* Element */ parent, /* Array of Object */ details )
+{
+    parent.appendChild( addText( td( "content"), "\u00a0" ) );
+    
+    var tdEl = td( "content", { colspan: 4 } );
+    parent.appendChild( tdEl );
+    
+    var tableEl = createElement( "table", null, { border: 0 } );
+    tdEl.appendChild( tableEl );
+    
+    var tbody = createElement( "tbody" );
+    tableEl.appendChild( tbody );
+    for (var idx in details)
+    {
+        var prop = details[idx];
+        
+        
+        var trEl = tr();
+        trEl.appendChild( addText( td( "aligntop", { noWrap: true } ), prop.key ) );
+
+        var proptd = td( "aligntop" );
+        trEl.appendChild( proptd );
+        
+        if (prop.value)
+        {
+            var values = new String( prop.value ).split( "<br />" );
+            for (var i=0; i < values.length; i++)
+            {
+                if (i > 0) { proptd.appendChild( createElement( "br" ) ); }
+                
+                var span;
+                if (values[i].substring(0, 2) == "!!") {
+                    span = createElement( "span", null, { style: { color: "red" } } );
+                    proptd.appendChild( span );
+                } else {
+                    span = proptd;
+                }
+                
+                addText( span, values[i] );
+            }
+        }
+        else
+        {
+            addText( proptd, "\u00a0" );
+        }
+
+        tbody.appendChild( trEl );
+    }
+ }
+
+ 
+function showDetails(bundleId)
+{
+    var span = document.getElementById('bundle' + bundleId + '_details');
+}
+
+
+function showDataEntryDetails( id )
+{
+    var span = document.getElementById( 'entry' + id + '_details' );
+    if (span)
+    {
+        if (span.firstChild)
+        {
+            clearChildren( span );
+            newLinkValue( id, appRoot + "/res/imgs/right.gif" );
+        }
+        else
+        {
+            sendRequest( 'POST', pluginRoot + '/' + id, displayDataEntryDetails );
+            newLinkValue( id, appRoot + "/res/imgs/down.gif" );
+        }
+    }
+}
+
+
+function newLinkValue( /* long */ id, /* String */ newLinkValue )
+{
+    
+    var link = document.getElementById( "entry" + id + "_inline" );
+    if (link)
+    {
+        link.src = newLinkValue;
+    }
+}
+
+
+function displayDataEntryDetails( obj )
+{
+    var span = document.getElementById('entry' + obj.id + '_details');
+    if (span)
+    {
+        clearChildren( span );
+        getDataEntryDetails( span, obj.props );
+    }
+    
+}
+
+
+function changeDataEntryState(/* long */ id, /* String */ action)
+{
+    var parm = pluginRoot + "/" + id + "?action=" + action;
+    sendRequest('POST', parm, dataEntryStateChanged);
+}
+
+    
+function dataEntryStateChanged(obj)
+{
+    if (obj.reload)
+    {
+        document.location = document.location;
+    }
+    else
+    {
+        var id = obj.id;
+        if (obj.state)
+        {
+            // has status, so draw the line
+            if (obj.props)
+            {
+                var span = document.getElementById('entry' + id + '_details');
+                if (span && span.firstChild)
+                {
+                    clearChildren( span );
+                    getDataEntryDetails( span, obj.props );
+                }
+                else
+                {
+                    obj.props = false;
+                }
+            }
+
+            var span = document.getElementById('entry' + id);
+            if (span)
+            {
+                clearChildren( span );
+                entryInternal( span, obj );
+            }
+        }
+        else
+        {
+            // no status, dataEntry has been removed/uninstalled 
+            var span = document.getElementById('entry' + id);
+            if (span)
+            {
+                span.parentNode.removeChild(span);
+            }
+            var span = document.getElementById('entry' + id + '_details');
+            if (span)
+            {
+                span.parentNode.removeChild(span);
+            }
+        }
+    }    
+}
+
+    

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/events.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/events.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/events.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+function renderStatusLine() {
+    document.write( "<div class='fullwidth'>");
+    document.write( "<div class='statusline'></div>" );
+    document.write( "</div>" );
+}
+
+function renderView( /* Array of String */ columns, /* Array of String */ buttons ) {
+    renderStatusLine();
+    renderButtons(buttons);
+	document.write( "<div class='table'>");
+    document.write( "<table id='events' class='tablelayout'>" );
+
+    document.write( "<thead><tr>" );
+    for ( var name in columns ) {
+        document.write( "<th>" + columns[name] + "</th>" );
+    }
+    document.write( "</tr></thead><tbody>" );
+    document.write( "</tbody></table>" );
+    document.write( "</div>");
+    renderButtons(buttons);
+    renderStatusLine();	
+}
+
+function renderButtons( buttons ) {
+	document.write( "<div class='fullwidth'>");
+    document.write( "<div class='buttons'>" );
+    for( var b in buttons ) {
+    	document.write( "<div class='button'>");
+    	document.write(buttons[b]);
+    	document.write( "</div>");
+    }
+    document.write( "</div>" );
+    document.write( "</div>" );
+}
+
+function renderData( eventData )  {
+	$(".statusline").empty().append(eventData.status);
+	$("#events > tbody > tr").remove();	
+    for ( var idx in eventData.data ) {
+        entry( eventData.data[idx] );
+    }
+    $("#events").trigger("update");
+}
+
+function entry( /* Object */ dataEntry ) {
+    var trElement = tr( null, { id: "entry" + dataEntry.id } );
+    entryInternal( trElement,  dataEntry );
+	$("#events > tbody").append(trElement);	
+}
+
+
+function entryInternal( /* Element */ parent, /* Object */ dataEntry ) {
+    var id = dataEntry.id;
+    var topic = dataEntry.topic;
+    var properties = dataEntry.properties;
+
+    parent.appendChild( td( null, null, [ text( printDate(dataEntry.received) ) ] ) );
+    parent.appendChild( td( null, null, [ text( topic ) ] ) );
+
+    var propE;
+    if ( dataEntry.info ) {
+    	propE = text(dataEntry.info);
+    } else {
+	    var tableE = createElement("table");
+	    var bodyE = createElement("tbody");
+	    tableE.appendChild(bodyE);
+	
+	    for( var p in dataEntry.properties ) {
+	    	var c1 = td(null, null, [text(p)]);
+	    	c1.setAttribute("style", "border:0px none;");
+	    	var c2 = td(null, null, [text(dataEntry.properties[p])]);
+	    	c2.setAttribute("style", "border:0px none;");
+	    	bodyE.appendChild(tr(null, null, [ c1, c2 ]));
+	    }
+	    propE = tableE;
+    }
+    
+    parent.appendChild( td( null, null, [propE] ) );
+}
+
+/* displays a date in the user's local timezone */
+function printDate(time) {
+    var date = time ? new Date(time) : new Date();
+    return date.toLocaleString();
+}
+
+function loadData() {
+	$.get(pluginRoot + "/data.json", null, function(data) {
+	    renderData(data);
+	}, "json");	
+}
+
+function renderEvents() {
+    renderView( ["Received", "Topic", "Properties"],
+    		["<button id='reloadButton' type='button' name='reload'>Reload</button>",
+    		 "<button id='clearButton' type='button' name='clear'>Clear List</button>"]);
+	
+    loadData();
+    
+    $("#events").tablesorter();
+    $("#reloadButton").click(loadData);
+    $("#clearButton").click(function () {
+    	$("#events > tbody > tr").remove();
+    	$.post(pluginRoot, { "action":"clear" }, function(data) {
+    	    renderData(data);
+    	}, "json");
+    });
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery-1.2.6.min.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery-1.2.6.min.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery-1.2.6.min.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},cs!
 s:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:funct!
 ion(){return this.domManip(arguments,true,true,function(elem){if(this.
nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(valu!
 e);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataTyp!
 e:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;!
 return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===fa!
 lse)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];!
 }callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i]!
 )){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+=''!
 ;if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,func
tion(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j!
 >=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").repla!
 ce(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQ!
 uery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret!
 =jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery
.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}!
 },empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:!
 [\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegE
xp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").i!
 ndexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},h!
 eader:function(a){return/h\d/i.test(a.nodeName);},animated:function(a)
{return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(!
 \w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeN!
 ame(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#
"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQue!
 ry.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)!
 /first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuer
y.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.d!
 ata(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.hand!
 ler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,ty
pe){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefau!
 lt;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];f!
 or(var j in handlers){var handler=handlers[j];if(all||handler.type==na
mespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelB!
 ubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:!
 {ready:{setup:function(){bindReady();return;},teardown:function(){retu
rn;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQu!
 ery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(!
 jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser!
 .safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,pa!
 rams,callback){if(typeof url!='string')return this._load(url);var off=
url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).v!
 al();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout!
 :0,contentType:"application/x-www-form-urlencoded",processData:true,as
ync:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[!
 jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(!
 script);return undefined;}var requestDone=false;var xhr=window.ActiveX
Object?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success!
 "){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return!
  false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"t!
 oggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt!
 .complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.cs
s(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed!
 ,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")t!
 his.elem.style.display="block";},cur:function(force){if(this.elem[this
.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=j!
 Query.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.dura!
 tion);this.now=this.start+((this.end-this.start)*this.pos);this.update
();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParen!
 t.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",tr!
 ue));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0
;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(wi!
 ndow).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery.tablesorter-2.0.3.min.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery.tablesorter-2.0.3.min.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/jquery.tablesorter-2.0.3.min.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,2 @@
+
+(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).met!
 adata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var!
  c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j
<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config!
 .appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr!
 =arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tH
ead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled!
 ){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return !
 "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].
length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumn!
 Width(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function()!
 {this.config.parsers=buildParserCache(this,$headers);cache=buildCache(
this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseIn!
 t(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new !
 RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress
",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-!
 2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},fo!
 rmat:function(s,table,cell){var c=table.config,p=(!c.parserMetadataNam
e)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.css
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.css	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.css	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */ /* CSS Document */
+#licenseContent {
+    position: relative;
+    margin-top: 25px; padding : 5px;
+    width: 100%;
+    padding: 5px;
+}
+
+#licenseLeft {
+    width: 300px;
+    border-right: 1px black solid;
+}
+
+#licenseRight {
+    position: absolute;
+    top: 5px;
+    left: 305px;
+    padding: 5px;
+    width: 650px;
+    border-left: 1px black solid;
+}
+
+#licenseClear {
+    clear: both;
+    height: 1px;
+}
+
+.licenseButtons {
+    padding: 5px;
+}
+
+.licenseDetails {
+    padding: 5px;
+}
\ No newline at end of file

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/license.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+function displayBundle(/* String */ bundleId)
+{
+    var theBundleData = bundleData[bundleId];
+    if (!theBundleData)
+    {
+        return;
+    }
+
+    var title = theBundleData.title;
+    
+    var licenseButtons = document.getElementById('licenseButtons');
+    if (licenseButtons) {
+        
+        var innerHTML = "";
+        for (var name in theBundleData.files)
+        {
+            var entry = theBundleData.files[name];
+            var buttons = "";
+            for (var idx in entry)
+            {
+                var descr = entry[idx];
+                buttons += "<a href='javascript:displayFile(\"" + bundleId + "\", \"" + name + "\", " + idx + ");'"
+                   + " >" + descr.url + "</a> ";
+            }
+            if (buttons)
+            {
+                innerHTML += name + ": " + buttons + "<br />";
+            }
+        }
+        
+        if (!innerHTML)
+        {
+            innerHTML = "<em>The Bundle contains neither LICENSE nor NOTICE files</em>";
+        }
+        
+        licenseButtons.innerHTML = "<h1>" + title + "</h1>" + innerHTML;
+    }
+    
+    var licenseDetails = document.getElementById('licenseDetails');
+    if (licenseDetails)
+    {
+        licenseDetails.innerHTML = "";
+    }
+}
+
+function displayFile ( /* String */ bundleId, /* String */ name, /* int */ idx )
+{
+    var theBundleData = bundleData[bundleId];
+    if (!theBundleData)
+    {
+        return;
+    }
+    
+    var file = theBundleData.files[name][idx];
+    if (!file)
+    {
+        return;
+    }
+    
+    var licenseDetails = document.getElementById('licenseDetails');
+    if (licenseDetails)
+    {
+        licenseDetails.innerHTML = "<h3>" + name + ": " + file.url + "</h3><pre>" + file.data + "</pre>";
+    }
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/packages.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/packages.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/packages.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+function header( /* int */ columns )
+{
+    document.write( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='" + columns + "' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    document.write( "<tr class='content'>" );
+    document.write( "<th class='content'>Name</th>" );
+    document.write( "<th class='content' width='100%'>Details</th>" );
+    document.write( "<th class='content'>Version</th>" );
+    document.write( "<th class='content' colspan='" + (columns - 3) + "'>Actions</th>" );
+    document.write( "</tr>" );
+
+}
+
+
+function error( /* int */ columns, /* String */ message )
+{
+    document.write( "<tr class='content'>" );
+    document.write( "<td class='content'>&nbsp;</td>" );
+    document.write( "<td class='content' colspan='" + (columns - 1) + "'>" + message + "</td>" );
+    document.write( "</tr>" );
+}
+
+
+function data( /* Array of Object */ dataArray )
+{
+    // render components
+    if (dataArray.length == 1)
+    {
+        entry( dataArray[0], true );
+    }
+    else {
+        for ( var idx in dataArray )
+        {
+            entry( dataArray[idx] );
+        }
+    }
+}
+
+
+function footer( /* int */ columns )
+{
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='" + columns + "' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    document.write( "</table>" );
+}
+
+
+function entry( /* Object */ dataEntry, /* boolean */ singleEntry )
+{
+    var trElement = tr( null, { id: "entry" + dataEntry.id } );
+    entryInternal( trElement,  dataEntry, singleEntry );
+    document.write( serialize( trElement ) );
+
+    // dataEntry detailed properties
+    trElement = tr( null, { id: "entry" + dataEntry.id + "_details" } );
+    if (dataEntry.props)
+    {
+        getDataEntryDetails( trElement, dataEntry.props );
+    }
+    document.write( serialize( trElement ) );
+}
+
+
+function entryInternal( /* Element */ parent, /* Object */ dataEntry, /* boolean */ singleEntry )
+{
+
+    var id = dataEntry.id;
+    var name = dataEntry.name;
+    var state = dataEntry.state;
+    var icon = singleEntry ? "left" : (dataEntry.props ? "down" : "right");
+    var event = singleEntry ? "history.back()" : "showDataEntryDetails(" + id + ")"; 
+
+    parent.appendChild( td( "content right", null, [ text( id ) ] ) );
+    
+    parent.appendChild( td( "content", null, [
+            createElement( "img", null, {
+                src: appRoot + "/res/imgs/" + icon + ".gif",
+                onClick: event,
+                id: "entry" + id + "_inline"
+            } ),
+            text( "\u00a0" ),
+            createElement( "a", null, {
+                href: pluginRoot + "/" + id
+            }, [ text( name ) ]
+            )]
+        )
+    );
+
+    parent.appendChild( td( "content center", null, [ text( state ) ] ) );
+
+    for ( var aidx in dataEntry.actions )
+    {
+        var action = dataEntry.actions[aidx];
+        parent.appendChild( actionButton( action.enabled, id, action.link, action.name ) );
+    }
+}
+
+
+/* Element */ function actionButton( /* boolean */ enabled, /* long */ id, /* String */ op, /* String */ opLabel )
+{
+    var buttonTd = td( "content", { align: "right" } );
+    if ( op )
+    {
+        var input = createElement( "input", "submit", {
+                type: 'button',
+                value: opLabel,
+                onClick: 'changeDataEntryState("' + id + '", "' + op + '");'
+            });
+        if (!enabled)
+        {
+            input.setAttribute( "disabled", true );
+        }
+        buttonTd.appendChild( input );
+    }
+    else
+    {
+        addText( buttonTd, "\u00a0" );
+    }
+    
+    return buttonTd;
+}
+
+
+function getDataEntryDetails( /* Element */ parent, /* Array of Object */ details )
+{
+    parent.appendChild( addText( td( "content"), "\u00a0" ) );
+    
+    var tdEl = td( "content", { colspan: 4 } );
+    parent.appendChild( tdEl );
+    
+    var tableEl = createElement( "table", null, { border: 0 } );
+    tdEl.appendChild( tableEl );
+    
+    var tbody = createElement( "tbody" );
+    tableEl.appendChild( tbody );
+    for (var idx in details)
+    {
+        var prop = details[idx];
+        
+        
+        var trEl = tr();
+        trEl.appendChild( addText( td( "aligntop", { noWrap: true } ), prop.key ) );
+
+        var proptd = td( "aligntop" );
+        trEl.appendChild( proptd );
+        
+        if (prop.value )
+        {
+            var values = new String( prop.value ).split( "<br />" );
+            for (var i=0; i < values.length; i++)
+            {
+                if (i > 0) { proptd.appendChild( createElement( "br" ) ); }
+                addText( proptd, values[i] );
+            }
+        }
+        else
+        {
+            addText( proptd, "\u00a0" );
+        }
+
+        tbody.appendChild( trEl );
+    }
+ }
+
+ 
+function showDetails(bundleId)
+{
+    var span = document.getElementById('bundle' + bundleId + '_details');
+}
+
+
+function showDataEntryDetails( id )
+{
+    var span = document.getElementById( 'entry' + id + '_details' );
+    if (span)
+    {
+        if (span.firstChild)
+        {
+            clearChildren( span );
+            newLinkValue( id, appRoot + "/res/imgs/right.gif" );
+        }
+        else
+        {
+            sendRequest( 'POST', pluginRoot + '/' + id, displayDataEntryDetails );
+            newLinkValue( id, appRoot + "/res/imgs/down.gif" );
+        }
+    }
+}
+
+
+function newLinkValue( /* long */ id, /* String */ newLinkValue )
+{
+    
+    var link = document.getElementById( "entry" + id + "_inline" );
+    if (link)
+    {
+        link.src = newLinkValue;
+    }
+}
+
+
+function displayDataEntryDetails( obj )
+{
+    var span = document.getElementById('entry' + obj.id + '_details');
+    if (span)
+    {
+        clearChildren( span );
+        getDataEntryDetails( span, obj.props );
+    }
+    
+}
+
+
+function changeDataEntryState(/* long */ id, /* String */ action)
+{
+    var parm = pluginRoot + "/" + id + "?action=" + action;
+    sendRequest('POST', parm, dataEntryStateChanged);
+}
+
+    
+function dataEntryStateChanged(obj)
+{
+    if (obj.reload)
+    {
+        document.location = document.location;
+    }
+    else
+    {
+        var id = obj.id;
+        if (obj.state)
+        {
+            // has status, so draw the line
+            if (obj.props)
+            {
+                var span = document.getElementById('entry' + id + '_details');
+                if (span && span.firstChild)
+                {
+                    clearChildren( span );
+                    getDataEntryDetails( span, obj.props );
+                }
+                else
+                {
+                    obj.props = false;
+                }
+            }
+
+            var span = document.getElementById('entry' + id);
+            if (span)
+            {
+                clearChildren( span );
+                entryInternal( span, obj );
+            }
+        }
+        else
+        {
+            // no status, dataEntry has been removed/uninstalled 
+            var span = document.getElementById('entry' + id);
+            if (span)
+            {
+                span.parentNode.removeChild(span);
+            }
+            var span = document.getElementById('entry' + id + '_details');
+            if (span)
+            {
+                span.parentNode.removeChild(span);
+            }
+        }
+    }    
+}
+
+function renderPackage( /* Array of Data Objects */ bundleData )
+{
+
+    // number of actions plus 3 -- id, name and state
+    var columns = 4;
+    
+    header( columns );
+
+    installForm(  );
+
+    if (bundleData.error)
+    {
+        error( columns, bundleData.error );
+    }
+    else
+    {
+        data ( bundleData.data );
+    }
+
+    installForm(  );
+
+    footer( columns );
+}
+
+function installForm( )
+{
+    document.write( "<form method='post' enctype='multipart/form-data'>" );
+    document.write( "<tr class='content'>" );
+    document.write( "<td class='content'>&nbsp;</td>" );
+    document.write( "<td class='content'>" );
+    document.write( "<input type='hidden' name='action' value='deploydp' />" );
+    document.write( "<input class='input' type='file' name='pckfile' size='50'>" );
+    document.write( "</td>" );
+    document.write( "<td class='content' align='right' colspan='5' noWrap>" );
+    document.write( "<input class='submit' style='width:auto' type='submit' value='Install or Update'>" );
+    document.write( "</td>" );
+    document.write( "</tr>" );
+    document.write( "</form>" );
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.css
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.css	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.css	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+div.consolebuttons {
+    text-align: right;
+    border: none;
+    width: 955px;
+    padding-bottom: 2px;
+}
+
+div.consoleframe {
+    font-family: "Courier New", Courier, monospace;
+    font-size: 12px;
+    font-weight: normal;
+    background-color: #f0f0f0;
+    color: #000000;
+    border: 1px solid #999999;
+    width: 955px;
+    height: 500px;
+    overflow: auto;
+}
+
+div.console {
+}
+
+span.consolecommand {
+    white-space: pre;
+}
+
+span.error {
+    color: #ff0000;
+}
+
+span.prompt {
+    padding-left: 0px;
+    padding-top: 2px;
+    padding-bottom: 3px;
+}
+
+input.command {
+    font-family: "Courier New", Courier, monospace;
+    font-size: 12px;
+    font-weight: normal;
+    background-color: #f0f0f0;
+    color: #000000;
+    border: none;
+    width: 900px;
+    margin-left: -1px; 
+    margin-top: -1px; 
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/shell.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+function executeCommand(command) {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp) {
+        return;
+    }
+    
+    if (xmlhttp.readyState < 4) {
+        xmlhttp.abort();
+    }
+    
+    var url = document.location;
+    
+    xmlhttp.open("POST", url);
+    
+    // set If-Modified-Since way back in the past to prevent
+    // using any content from the cache
+    xmlhttp.setRequestHeader("If-Modified-Since", new Date(0));
+    xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
+    
+    xmlhttp.onreadystatechange = updateConsole;
+    
+    xmlhttp.send("command=" + encodeURIComponent(command));
+}
+
+function updateConsole() {
+    var xmlhttp = getXmlHttp();
+    if (!xmlhttp || xmlhttp.readyState != 4) {
+        return;
+    }
+    
+    var result = xmlhttp.responseText;
+    if (!result) {
+        return;
+    }
+
+    var console = document.getElementById("console");
+    
+    console.style.display = "";
+    console.innerHTML = console.innerHTML + result;
+    
+    var consoleframe = document.getElementById("consoleframe");
+    consoleframe.scrollTop = console.scrollHeight;
+
+    document.forms["shellCommandForm"].elements["command"].value = "";
+    
+    shellCommandFocus();
+}
+
+function clearConsole() {
+    var console = document.getElementById("console");
+
+    console.style.display = "none";
+    console.innerHTML = "";
+    
+    var consoleframe = document.getElementById("consoleframe");
+    consoleframe.scrollTop = 0;
+    
+    shellCommandFocus();
+}
+
+function shellCommandFocus() {
+    document.forms["shellCommandForm"].elements["command"].focus();
+}
+
+function runShellCommand() {
+    var command = document.forms["shellCommandForm"].elements["command"].value;
+    
+    executeCommand(command);
+}

Added: projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/ui.js
===================================================================
--- projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/ui.js	                        (rev 0)
+++ projects/jboss-osgi/branches/tdiesler/service/webconsole/src/main/resources/res/ui/ui.js	2009-02-25 12:05:12 UTC (rev 84726)
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+
+/* Element */ function clearChildren( /* Element */ element )
+{
+    while (element.firstChild)
+    {
+        element.removeChild(element.firstChild);
+    }
+    
+    return element;
+}
+
+/* String */ function serialize( /* Element */ element )
+{
+    var result = "";
+    
+    if (element)
+    {
+        if (element.nodeValue)
+        {
+            result = element.nodeValue;
+        }
+        else {
+            result += "<" + element.tagName;
+            
+            var attrs = element.attributes;
+            for (var i=0; i < attrs.length; i++)
+            {
+                if (attrs[i].nodeValue)
+                {
+                    result += " " + attrs[i].nodeName + "='" + attrs[i].nodeValue + "'";
+                }
+            }
+            
+            var children = element.childNodes;
+            if (children && children.length)
+            {
+                result += ">";
+            
+                for (var i=0; i < children.length; i++)
+                {
+                    result += serialize( children[i] );
+                }
+                result += "</" + element.tagName + ">";
+            }
+            else
+            {
+                result += "/>";
+            }
+        }
+    }
+    
+    return result;
+}
+
+/* Element */ function tr( /* String */ cssClass, /* Map */ attrs, /* Element[] */ children )
+{
+    return createElement( "tr", cssClass, attrs, children );
+}
+
+
+/* Element */ function td( /* String */ cssClass, /* Map */ attrs, /* Element[] */ children )
+{
+    return createElement( "td", cssClass, attrs, children );
+}
+
+
+/* Element */ function text( /* String */ textValue )
+{
+    return document.createTextNode( textValue );
+}
+
+
+/* Element */ function createElement( /* String */ name, /* String */ cssClass, /* Map */ attrs, /* Element[] */ children  )
+{
+    var element = document.createElement( name );
+    
+    if (cssClass)
+    {
+        element.setAttribute( "class", cssClass ); // non-IE
+        element.setAttribute( "className", cssClass ); // IE
+    }
+    
+    if (attrs)
+    {
+        for (var lab in attrs)
+        {
+            if ("style" == lab)
+            {
+                var styles = attrs[lab];
+                for (var styleName in styles)
+                {
+                    element.style[styleName] = styles[styleName];
+                }
+            }
+            else
+            {
+                element.setAttribute( lab, attrs[lab] );
+            }
+        }
+    }
+    
+    if (children && children.length)
+    {
+        for (var i=0; i < children.length; i++)
+        {
+            element.appendChild( children[i] );
+        }
+    }
+    
+    return element;
+}
+
+
+/* Element */ function addText( /* Element */ element, /* String */ textValue )
+{
+    if (element && textValue)
+    {
+        element.appendChild( text( textValue ) );
+    }
+    
+    return element;
+}
\ No newline at end of file




More information about the jboss-cvs-commits mailing list