Initial import of the karaf-webconsole from github prototype

git-svn-id: https://svn.apache.org/repos/asf/karaf/sandbox/pieber/karaf-webconsole/trunk@1156455 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5770dd4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.classpath
+*.project
+*.settings
+*target
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4332a41
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+=Open Issues=
+
+=0.1=
+*
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..56c7c7e
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+The base idea is to take the current felix webconsole (we use in Karaf), base it on wicket and handle the entire thing on pax-wicket. Based on this method it should be very simple to provide an VERY configurable and extendable webconsole which should be much easier to write than the current one based on plain jscript and servlets.
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..8f2f9de
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,102 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf</groupId>
+        <artifactId>webconsole</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.karaf.webconsole</groupId>
+    <artifactId>org.apache.karaf.webconsole.core</artifactId>
+    <name>Apache Karaf :: Karaf Webconsole Prototype :: Core</name>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>4.2.0</version>
+        </dependency>
+
+        <!-- WICKET DEPENDENCIES -->
+        <dependency>
+            <groupId>org.ops4j.pax.wicket</groupId>
+            <artifactId>org.ops4j.pax.wicket.service</artifactId>
+            <version>${ops4j.paxwicket.version}</version>
+        </dependency>
+
+        <!-- JUNIT DEPENDENCY FOR TESTING -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.1</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Karaf -->
+        <dependency>
+          <groupId>org.apache.karaf.features</groupId>
+          <artifactId>org.apache.karaf.features.core</artifactId>
+          <version>${karaf.version}</version>
+        </dependency>
+
+        <!-- <dependency> -->
+        <!-- <groupId>org.odlabs.wiquery</groupId> -->
+        <!-- <artifactId>wiquery</artifactId> -->
+        <!-- <version>1.2.4</version> -->
+        <!-- </dependency> -->
+        <!-- <dependency> -->
+        <!-- <groupId>org.slf4j</groupId> -->
+        <!-- <artifactId>slf4j-api</artifactId> -->
+        <!-- <version>1.6</version> -->
+        <!-- </dependency> -->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.5</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <!-- The bundle activator is only required if we 
+                            do the things by hand. -->
+                        <Import-Package>
+                            *,<!-- let bnd import direct dependencies -->
+                            org.apache.wicket.settings,
+                            org.apache.wicket.session,
+                            org.apache.wicket.util.file,
+                            org.apache.wicket.request,
+                            org.apache.wicket.ajax,
+                            org.apache.wicket.markup.html.link,
+
+                            <!-- then wicket stuff -->
+                            org.ops4j.pax.wicket.api,
+                            org.ops4j.pax.wicket.util,
+                            org.ops4j.pax.wicket.util.proxy,
+                            <!-- osgi stuff -->
+                            org.osgi.framework,
+                            org.osgi.service.blueprint,
+                            org.osgi.service.startlevel,
+                            <!-- cglib -->
+                            net.sf.cglib.proxy;version="[2,3)",
+                            net.sf.cglib.core;version="[2,3)",
+                            net.sf.cglib.reflect;version="[2,3)",
+                            <!-- and servlet api -->
+                            javax.servlet,
+                            javax.servlet.http,
+                            <!-- Karaf -->
+                            org.apache.karaf.features
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java b/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java
new file mode 100644
index 0000000..ce730d2
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java
@@ -0,0 +1,63 @@
+package org.apache.karaf.webconsole.core;
+
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.TabbedPanel;
+import org.apache.wicket.markup.html.CSSPackageResource;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.PageLink;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class BasePage extends WebPage {
+
+    @PaxWicketBean(name = "tabs")
+    private List<ConsoleTab> tabs;
+
+    public BasePage() {
+        add(CSSPackageResource.getHeaderContribution(BasePage.class, "style.css"));
+
+        add(new Label("footer", "Apache Karaf Console"));
+
+        add(new ListView<ConsoleTab>("tabs", tabs) {
+            @Override
+            protected void populateItem(ListItem<ConsoleTab> item) {
+                final ConsoleTab tab = item.getModelObject();
+                item.add(new PageLink("moduleLink", tab.getModuleHomePage()).add(new Label("moduleLabel", tab.getLabel())));
+
+                List<String> subItems = new LinkedList<String>(tab.getItems().keySet());
+                item.add(new ListView<String>("topLinks", subItems) {
+                    @Override
+                    protected void populateItem(ListItem<String> item) {
+                        String subItem = item.getModelObject();
+                        item.add(new PageLink("topLink", tab.getItems().get(subItem)).add(new Label("linkLabel", subItem)));
+                    }
+                });
+            }
+        });
+
+        List tabPanels = new ArrayList();
+        tabPanels.add(new AbstractTab(new Model("first tab")) {
+            public Panel getPanel(String panelId) {
+                return new TabPanel1(panelId);
+            }
+        });
+
+        add(new TabbedPanel("tabPanels", tabPanels));
+
+
+    }
+
+    class TabPanel1 extends Panel {
+        public TabPanel1(String id) {
+            super(id);
+        }
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/ConsoleTab.java b/core/src/main/java/org/apache/karaf/webconsole/core/ConsoleTab.java
new file mode 100644
index 0000000..9a45526
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/ConsoleTab.java
@@ -0,0 +1,17 @@
+package org.apache.karaf.webconsole.core;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Since the ConsoleTab is used directly in wicket please make sure that the implementing object is serializable
+ */
+public interface ConsoleTab extends Serializable {
+
+    String getLabel();
+
+    Class getModuleHomePage();
+
+    Map<String, Class> getItems();
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/DashboardPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/DashboardPage.java
new file mode 100644
index 0000000..8e955a3
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/DashboardPage.java
@@ -0,0 +1,11 @@
+package org.apache.karaf.webconsole.core.internal;
+
+import org.apache.karaf.webconsole.core.BasePage;
+
+public class DashboardPage extends BasePage {
+
+	public DashboardPage() {
+		
+	}
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/SystemConsoleTab.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/SystemConsoleTab.java
new file mode 100644
index 0000000..dd2ab40
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/SystemConsoleTab.java
@@ -0,0 +1,27 @@
+package org.apache.karaf.webconsole.core.internal;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.webconsole.core.ConsoleTab;
+
+public class SystemConsoleTab implements ConsoleTab, Serializable {
+
+    private static final long serialVersionUID = -7381914604367435106L;
+
+    public String getLabel() {
+        return "Dashboard";
+    }
+
+    public Class getModuleHomePage() {
+        return DashboardPage.class;
+    }
+
+    public Map<String, Class> getItems() {
+        Map<String, Class> map = new HashMap<String, Class>();
+        map.put("Dashboard", DashboardPage.class);
+        return map;
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/WicketApplication.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/WicketApplication.java
new file mode 100644
index 0000000..62ab63d
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/WicketApplication.java
@@ -0,0 +1,27 @@
+package org.apache.karaf.webconsole.core.internal;
+
+import org.apache.wicket.protocol.http.WebApplication;
+
+/**
+ * Application object for your web application. If you want to run this application without deploying, run the Start
+ * class.
+ * 
+ * @see org.code-house.Start#main(String[])
+ */
+public class WicketApplication extends WebApplication
+{
+
+    public WicketApplication() {
+        super();
+    }
+
+    /**
+     * @see org.apache.wicket.Application#getHomePage()
+     */
+    @Override
+    public Class<DashboardPage> getHomePage()
+    {
+        return DashboardPage.class;
+    }
+
+}
diff --git a/core/src/main/resources/OSGI-INF/blueprint/wicket.xml b/core/src/main/resources/OSGI-INF/blueprint/wicket.xml
new file mode 100644
index 0000000..c26402e
--- /dev/null
+++ b/core/src/main/resources/OSGI-INF/blueprint/wicket.xml
@@ -0,0 +1,13 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:wicket="http://www.ops4j.org/schema/wicket">
+
+<wicket:application id="karafWebConsole" 
+  class="org.apache.karaf.webconsole.core.internal.WicketApplication"
+  applicationName="karafWebConsole" mountPoint="cns" />
+
+  <reference-list id="tabs" interface="org.apache.karaf.webconsole.core.ConsoleTab" availability="optional" />
+
+  <service auto-export="interfaces">
+    <bean class="org.apache.karaf.webconsole.core.internal.SystemConsoleTab" />
+  </service>
+
+</blueprint>
diff --git a/core/src/main/resources/log4j.properties b/core/src/main/resources/log4j.properties
new file mode 100644
index 0000000..05cd58a
--- /dev/null
+++ b/core/src/main/resources/log4j.properties
@@ -0,0 +1,12 @@
+log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n
+
+log4j.rootLogger=INFO,Stdout
+
+log4j.logger.org.apache.wicket=INFO
+log4j.logger.org.apache.wicket.protocol.http.HttpSessionStore=INFO
+log4j.logger.org.apache.wicket.version=INFO
+log4j.logger.org.apache.wicket.RequestCycle=INFO
+
+
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage$TabPanel1.html b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage$TabPanel1.html
new file mode 100644
index 0000000..ac2fcd7
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage$TabPanel1.html
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+<wicket:panel>
+    <br/>
+    This is tab-panel 1
+</wicket:panel>
+</html>
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html
new file mode 100644
index 0000000..dd07167
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Karaf wicket console</title>
+</head>
+<body>
+
+    <div id="container">
+
+        <div id="header">
+            <h2>Karaf administrator</h2>
+
+            <div wicket:id="tabPanels" class="tabpanel">[tabbed panel will be here]</div>
+
+            <div id="topmenu">
+                <ul>
+                    <li wicket:id="tabs">
+                        <a wicket:id="moduleLink">
+                            <span wicket:id="moduleLabel">Category</span>
+                        </a>
+
+                        <ul>
+                            <li wicket:id="topLinks">
+                                <a wicket:id="topLink">
+                                    <span wicket:id="linkLabel">Label</span>
+                                </a>
+                            </li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+        </div>
+
+        <!--
+        <div id="top-panel">
+            <div id="panel">
+                <ul>
+                    <li class="current"><a href="#">OSGi</a></li>
+                    <li><a href="#">Services</a></li>
+                    <li><a href="#">Features</a></li>
+                </ul>
+            </div>
+        </div>
+        -->
+
+        <div id="wrapper">
+
+            <!--
+            <div id="sidebar">
+                <ul>
+                    <li>
+                        <h3>
+                            <a href="#">OSGi</a>
+                        </h3>
+                        <ul>
+                            <li class="current"><a href="#">Bundles</a></li>
+                            <li><a href="#">Configuration</a></li>
+                            <li><a href="#">Events</a></li>
+                        </ul>
+                    </li>
+                </ul>
+            </div>
+            -->
+
+            <div id="content">
+                <wicket:child />
+            </div>
+        </div>
+
+        <div id="footer">
+            <div id="credits" wicket:id="footer">Footer</div>
+        </div>
+
+    </div>
+
+
+</body>
+</html>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/internal/DashboardPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/internal/DashboardPage.html
new file mode 100644
index 0000000..b94f95b
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/internal/DashboardPage.html
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Karaf wicket console</title>
+</head>
+<body>
+
+   <wicket:extend>
+   
+   </wicket:extend>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/style.css b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
new file mode 100644
index 0000000..1278e43
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
@@ -0,0 +1,134 @@
+* {
+    font-family: Arial, Tahoma;
+    font-size: 16px;
+}
+
+body {
+    background: #FFFFFF;
+}
+
+#container {
+    width: 1000px;
+}
+
+a {
+    color: #0F3B5F;
+}
+
+li.current {
+    font-weight: bold;
+}
+
+div.widget {
+    float: left;
+    width: 250px;
+}
+
+#wrapper {
+    
+}
+
+#content {
+    float: left;
+    width: 750px;
+    margin: 0 auto;
+}
+
+#sidebar {
+    float: left;
+    width: 250px;
+}
+
+#sidebar ul li {
+    list-style-type: none;
+}
+
+#topmenu ul li, #top-panel ul li {
+    display: inline;
+}
+
+#topmenu {
+    background: #CC9752;
+}
+
+#top-panel ul {
+    margin: 0px;
+}
+
+#top-panel {
+    background: #CCCC00;
+}
+
+table.dataview {
+	margin-bottom: 10px;
+	border-bottom: 1px solid #0079d6;
+	font-size: 1em;
+	font-family: arial;
+	}
+
+table.dataview caption { text-align: left; }
+table.dataview tr { padding-top: 2px; padding-bottom: 2px; }
+table.dataview tr.even { background-color: #ffebcd; }
+table.dataview tr.odd { background-color: #fff; }
+table.dataview tr td { padding-left: 8px; padding-right: 30px; }
+table.dataview tr th { color: black; padding-top: 3px; padding-bottom: 3px; padding-left: 8px; padding-right: 30px; background-color: #c1e4ff; border-bottom: 1px solid #0079d6; border-top: 1px solid #0079d6; text-align: left; white-space: nowrap; vertical-align: middle;}
+
+table.dataview tr th { background-position: right; background-repeat:no-repeat; }
+table.dataview tr th.wicket_orderDown {
+	background-color: #87cbff; background-image: url(displaytag/img/arrow_down.png); }
+table.dataview tr th.wicket_orderUp {
+	background-color: #87cbff; background-image: url(displaytag/img/arrow_up.png); }
+table.dataview tr th.wicket_orderNone {
+	background-image: url(displaytag/img/arrow_off.png);
+}
+table.dataview tr th a { font-weight: normal; }
+table.dataview #message { padding-left: 3px; }
+table.dataview caption { padding-bottom: 2px; }
+
+div.tabpanel div.tab-row{
+  float:left;
+  width:100%;
+  background:#DAE0D2 url("tabs/bg.gif") repeat-x bottom;
+  line-height:normal;
+  }
+
+div.tabpanel div.tab-row ul {
+  margin:0;
+  padding:10px 10px 0;
+  list-style:none;
+  }
+
+div.tabpanel div.tab-row li {
+  float:left;
+  background:url("tabs/left.gif") no-repeat left top;
+  margin:0;
+  padding:0 0 0 9px;
+  }
+
+div.tabpanel div.tab-row a {
+  display:block;
+  background:url("tabs/right.gif") no-repeat right top;
+  padding:5px 15px 4px 6px;
+  text-decoration:none;
+  font-weight:bold;
+  white-space:nowrap;
+  color:#eee;
+  }
+
+div.tab-panel {
+	clear: left;
+}
+
+div.tabpanel div.tab-row a:hover {
+  color:#fff;
+  }
+
+div.tabpanel div.tab-row li.selected {
+  background-image:url("tabs/left_on.gif");
+  }
+
+div.tabpanel div.tab-row li.selected a {
+  background-image:url("tabs/right_on.gif");
+  color:#333;
+  padding-bottom:5px;
+}
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif
new file mode 100644
index 0000000..3ae5c60
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif
new file mode 100644
index 0000000..473505a
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif
new file mode 100644
index 0000000..58d8425
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif
new file mode 100644
index 0000000..e97e0e9
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif
new file mode 100644
index 0000000..9b02b58
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif
Binary files differ
diff --git a/core/src/main/webapp/WEB-INF/web.xml b/core/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..07af356
--- /dev/null
+++ b/core/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE web-app
+      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+      "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+    <display-name>Wicket Examples</display-name>
+    <filter>
+        <filter-name>HelloWorldApplication</filter-name>
+        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+        <init-param>
+          <param-name>applicationClassName</param-name>
+          <param-value>org.code_house.WicketApplication</param-value>
+        </init-param>
+    </filter>
+    <filter-mapping>
+        <filter-name>HelloWorldApplication</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+</web-app>
\ No newline at end of file
diff --git a/features/pom.xml b/features/pom.xml
new file mode 100644
index 0000000..0d3d12c
--- /dev/null
+++ b/features/pom.xml
@@ -0,0 +1,75 @@
+<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">
+
+  <parent>
+    <groupId>org.apache.karaf</groupId>
+    <artifactId>webconsole</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.karaf.webconsole</groupId>
+  <artifactId>features</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+
+  <packaging>pom</packaging>
+
+  <name>Apache Karaf :: Karaf Webconsole Prototype :: Karaf Feature File</name>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>${project.basedir}/src/main/filtered-resources</directory>
+        <filtering>true</filtering>
+        <includes>
+          <include>**/*</include>
+        </includes>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <configuration>
+          <useDefaultDelimiters>false</useDefaultDelimiters>
+          <delimiters>
+            <delimiter>${*}</delimiter>
+          </delimiters>
+        </configuration>
+        <executions>
+          <execution>
+            <id>filter</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>resources</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <phase>package</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>target/classes/features.xml</file>
+                  <type>xml</type>
+                  <classifier>features</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
+
diff --git a/features/src/main/filtered-resources/features.xml b/features/src/main/filtered-resources/features.xml
new file mode 100644
index 0000000..a56b06c
--- /dev/null
+++ b/features/src/main/filtered-resources/features.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright OPS4J
+
+    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.
+
+-->
+<features name="karaf-webconsole-${project.version}">
+
+  <repository>mvn:org.ops4j.pax.wicket/features/${ops4j.paxwicket.version}/xml/features</repository>
+
+  <!-- Pax-Wicket Core Feature; loading all required features. Do a feature:install paxwicket and you're ready to go -->
+  <feature name="karaf-webconsole" version="${project.version}">
+    <feature>wicket-spring</feature>
+    <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.core/${project.version}</bundle>
+    <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.osgi/${project.version}</bundle>
+  </feature>
+
+</features>
+
diff --git a/osgi/pom.xml b/osgi/pom.xml
new file mode 100644
index 0000000..2e5c646
--- /dev/null
+++ b/osgi/pom.xml
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf</groupId>
+        <artifactId>webconsole</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.karaf.webconsole</groupId>
+    <artifactId>org.apache.karaf.webconsole.osgi</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Karaf Webconsole Prototype :: OSGi Bundle Presentation</name>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.karaf.webconsole</groupId>
+            <artifactId>org.apache.karaf.webconsole.core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.5</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <!-- The bundle activator is only required if we 
+                            do the things by hand. -->
+                        <Import-Package>
+                            *,<!-- let bnd import direct dependencies -->
+                            org.apache.wicket.settings,
+                            org.apache.wicket.session,
+                            org.apache.wicket.util.file,
+                            org.apache.wicket.request,
+                            org.apache.wicket.ajax,
+                            org.apache.wicket.markup,
+                            org.apache.wicket.markup.html.link,
+                            org.apache.wicket.session.pagemap,
+                            org.apache.wicket.protocol.http,
+                            org.apache.wicket.markup.html.internal,
+                            org.apache.wicket.util.convert,
+                            org.apache.wicket.markup.html,
+                            <!-- then wicket stuff -->
+                            org.ops4j.pax.wicket.api,
+                            org.ops4j.pax.wicket.util,
+                            org.ops4j.pax.wicket.util.proxy,
+                            <!-- osgi stuff -->
+                            org.osgi.framework,
+                            org.osgi.service.blueprint,
+                            org.osgi.service.startlevel,
+                            <!-- cglib -->
+                            net.sf.cglib.proxy;version="[2,3)",
+                            net.sf.cglib.core;version="[2,3)",
+                            net.sf.cglib.reflect;version="[2,3)",
+                            <!-- and servlet api -->
+                            javax.servlet,
+                            javax.servlet.http
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/DetailsPage.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/DetailsPage.java
new file mode 100644
index 0000000..66c43f4
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/DetailsPage.java
@@ -0,0 +1,76 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import java.util.Arrays;
+
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class DetailsPage extends BasePage {
+
+	@PaxWicketBean(name = "blueprintBundleContext")
+	private BundleContext context;
+
+	public DetailsPage(PageParameters params) {
+		long bundleId = params.getLong("bundleId");
+		Bundle bundle = context.getBundle(bundleId);
+
+		add(new Label("name", bundle.getSymbolicName()));
+
+		String object = (String) bundle.getHeaders().get(Constants.IMPORT_PACKAGE);
+		if (object == null) object = "";
+
+		add(new ListView<String>("imports", Arrays.asList(object.split(","))) {
+			@Override
+			protected void populateItem(ListItem<String> item) {
+				item.add(new Label("importPackage", item.getModel()));
+			}
+		});
+
+		object = (String) bundle.getHeaders().get(Constants.EXPORT_PACKAGE);
+		if (object == null) object = "";
+		add(new ListView<String>("exports", Arrays.asList(object.split(","))) {
+			@Override
+			protected void populateItem(ListItem<String> item) {
+				item.add(new Label("exportPackage", item.getModel()));
+			}
+		});
+
+		ServiceReference[] servicesInUse = bundle.getServicesInUse();
+		if (servicesInUse == null) {
+			servicesInUse = new ServiceReference[0];
+		}
+
+		add(new ListView<ServiceReference>("servicesInUse", Arrays.asList(servicesInUse)) {
+
+			@Override
+			protected void populateItem(ListItem<ServiceReference> item) {
+				final ServiceReference reference = item.getModelObject();
+				item.add(new Label("serviceInUse", Arrays.toString((String[]) reference.getProperty("objectClass"))));
+
+				item.add(new ListView<String>("serviceInUseProperty", Arrays.asList(reference.getPropertyKeys())) {
+					@Override
+					protected void populateItem(ListItem<String> item) {
+						item.add(new Label("propertyName", item.getModelObject()));
+						Object property = reference.getProperty(item.getModelObject());
+						if (property instanceof Object[]) {
+							property = Arrays.toString((Object[]) property);
+						}
+						item.add(new Label("propertyValue", "" + property));
+					}
+				});
+				
+			}
+			
+		});
+	}
+
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java
new file mode 100644
index 0000000..cfe7909
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java
@@ -0,0 +1,111 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Feature;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class extending Feature class to provide additional info
+ * like Repository name, ...
+ */
+class ExtendedFeature implements Feature, Serializable {
+
+    public enum State {
+        INSTALLED, UNINSTALLED;
+
+        @Override
+        public String toString() {
+            //only capitalize the first letter
+            String s = super.toString();
+            return s.substring(0, 1) + s.substring(1).toLowerCase();
+        }
+    }
+
+    protected State state;
+    protected String repository;
+    protected Feature feature;
+
+
+    //
+    // Constructors
+    //
+
+    public ExtendedFeature(State state, String repository, Feature feature) {
+        this.state = state;
+        this.repository = repository;
+        this.feature = feature;
+    }
+
+
+    //
+    // Feature interface
+    //
+
+
+    public List<BundleInfo> getBundles() {
+        return this.feature.getBundles();
+    }
+
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        return this.feature.getConfigurations();
+    }
+
+    public List<ConfigFileInfo> getConfigurationFiles() {
+        return this.feature.getConfigurationFiles();
+    }
+
+    public String getId() {
+        return this.feature.getId();
+    }
+
+
+    public String getName() {
+        return this.feature.getName();
+    }
+
+
+    public String getVersion() {
+        return this.feature.getVersion();
+    }
+
+    public String getResolver() {
+        return this.feature.getResolver();
+    }
+
+    public List<Feature> getDependencies() {
+        return null;
+    }
+
+    public String getDescription() {
+        return this.feature.getDescription();
+    }
+
+    public String getDetails() {
+        return this.feature.getDetails();
+    }
+
+
+    //
+    // Additional methods
+    //
+
+
+    public String getRepository() {
+        return this.repository;
+    }
+
+
+    public State getState() {
+        return this.state;
+    }
+
+    public int getStartLevel() {
+        return 0;
+    }
+}
+
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesConsoleTab.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesConsoleTab.java
new file mode 100644
index 0000000..017693e
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesConsoleTab.java
@@ -0,0 +1,27 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.webconsole.core.ConsoleTab;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class FeaturesConsoleTab implements ConsoleTab {
+
+    private static final long serialVersionUID = 1L;
+
+    public String getLabel() {
+        return "Features";
+    }
+
+    public Class getModuleHomePage() {
+        return FeaturesPage.class;
+    }
+
+    public Map<String, Class> getItems() {
+        Map<String, Class> features = new HashMap<String, Class>();
+        features.put("Features List", FeaturesPage.class);
+        features.put("Feature repoz", RepositoriesPage.class);
+        return features;
+    }
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java
new file mode 100644
index 0000000..12efe33
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java
@@ -0,0 +1,126 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+import java.util.*;
+
+/**
+ * Features
+ */
+public class FeaturesPage extends BasePage {
+
+    @PaxWicketBean(name = "featuresService")
+    private FeaturesService featuresService;
+
+    /**
+     * Constructor that is invoked when page is invoked without a session.
+     *
+     * @param parameters Page parameters
+     */
+    public FeaturesPage() throws Exception {
+
+        Repository[] repositories = featuresService.listRepositories();
+        Feature[] features;
+        List<ExtendedFeature> model = new ArrayList<ExtendedFeature>();
+
+        for (Repository r : repositories) {
+            features = r.getFeatures();
+            for (Feature f : features) {
+                    ExtendedFeature.State state =
+                        featuresService.isInstalled(f) ? ExtendedFeature.State.INSTALLED : ExtendedFeature.State.UNINSTALLED;
+                    ExtendedFeature extendedFeature = new ExtendedFeature(  state, r.getName(), f );
+
+                    // add extended feature to Wicket model
+                    model.add(extendedFeature);
+            }
+        }
+
+/*        add(new ListView<ExtendedFeature>("features", model) {
+            @Override
+            protected void populateItem(ListItem<ExtendedFeature> item) {
+                final ExtendedFeature feature = item.getModelObject();
+                item.add(new Label("state", feature.getState().toString()));
+                item.add(new Label("version", feature.getVersion()));
+                item.add(new Label("name", feature.getName()));
+                item.add(new Label("repository", feature.getRepository()));
+                item.add(new Label("description", feature.getDescription()));
+
+                item.add(new Link("featuresDetailsPageLink") {
+                    @Override
+                    public void onClick() {
+                        PageParameters params = new PageParameters();
+                        params.put("featureId", feature.getId());
+                    }
+                });
+            }
+        });*/
+
+        List<IColumn<ExtendedFeature>> columns = new ArrayList<IColumn<ExtendedFeature>>();
+		columns.add(new PropertyColumn<ExtendedFeature>(Model.of("state"), "state",
+				"state"));
+		columns.add(new PropertyColumn<ExtendedFeature>(Model.of("version"), "version",
+				"version"));
+        columns.add(new PropertyColumn<ExtendedFeature>(Model.of("name"), "name",
+				"name"));
+        columns.add(new PropertyColumn<ExtendedFeature>(Model.of("repository"), "repository",
+				"repository"));
+        columns.add(new PropertyColumn<ExtendedFeature>(Model.of("description"), "description",
+				"description"));
+
+		add(new DefaultDataTable<ExtendedFeature>("features", columns,
+				new FeaturesProvider(model), 20));
+
+    }
+
+
+	static class FeaturesProvider extends SortableDataProvider<ExtendedFeature> {
+
+        List<ExtendedFeature> model;
+
+		public FeaturesProvider(List model) {
+            this.model = model;
+			setSort("name", true);
+		}
+
+		public Iterator<? extends ExtendedFeature> iterator(int first, int count) {
+			List<ExtendedFeature> data = new ArrayList<ExtendedFeature>(model);
+			Collections.sort(data, new Comparator<ExtendedFeature>() {
+
+				public int compare(ExtendedFeature o1, ExtendedFeature o2) {
+					int dir = getSort().isAscending() ? 1 : -1;
+
+                    if ("name".equals(getSort().getProperty())) {
+                      return dir * (o1.getName().compareTo(o2.getName()));
+                    } else if ("repository".equals(getSort().getProperty())) {
+                      return dir * (o1.getRepository().compareTo(o2.getRepository()));
+                    } else {
+                      return dir * (o1.getName().compareTo(o2.getName()));
+                    }
+				}
+			});
+			return data.subList(first, Math.min(first + count, data.size()))
+					.iterator();
+		}
+
+		public int size() {
+			return model.size();
+		}
+
+        public IModel<ExtendedFeature> model(ExtendedFeature object) {
+            return Model.of(object);
+        }
+
+	}
+
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/HomePage.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/HomePage.java
new file mode 100644
index 0000000..a7c81f6
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/HomePage.java
@@ -0,0 +1,154 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * Homepage
+ */
+public class HomePage extends BasePage {
+
+    @PaxWicketBean(name = "blueprintBundleContext")
+    private BundleContext context;
+
+    // TODO Add any page properties or variables here
+
+    interface ItemClassModifier {
+        List<String> getCssClasses(Bundle bundle);
+    }
+
+    class SystemBundleClassModifier implements ItemClassModifier {
+
+        public List<String> getCssClasses(Bundle bundle) {
+            List<String> classes = new ArrayList<String>();
+
+            if (bundle.getBundleId() == 0) {
+                classes.add("framework");
+            }
+
+            ServiceReference startLevelReference = context.getServiceReference(StartLevel.class.getName());
+
+            if (startLevelReference != null) {
+                StartLevel startLevel = (StartLevel) context.getService(startLevelReference);
+
+                int bundleStartLevel = startLevel.getBundleStartLevel(bundle);
+                if (bundleStartLevel < startLevel.getInitialBundleStartLevel()) {
+                    classes.add("system");
+                }
+                context.ungetService(startLevelReference);
+            }
+
+            return classes;
+        }
+    }
+
+    class BlueprintClassModifier implements ItemClassModifier {
+
+        public List<String> getCssClasses(Bundle bundle) {
+            List<String> classes = new ArrayList<String>();
+
+            ServiceReference[] registeredServices = bundle.getRegisteredServices();
+            if (registeredServices != null) {
+                for (ServiceReference reference : registeredServices) {
+                    List<String> oc = Arrays.asList((String[]) reference.getProperty("objectClass"));
+
+                    if (oc.contains("org.osgi.service.blueprint.container.BlueprintContainer")) {
+                        classes.add("blueprint");
+                        break;
+                    }
+
+                }
+            }
+
+            return classes;
+        }
+
+    }
+
+    class SpringClassModifier implements ItemClassModifier {
+
+        public List<String> getCssClasses(Bundle bundle) {
+            List<String> classes = new ArrayList<String>();
+
+            ServiceReference[] registeredServices = bundle.getRegisteredServices();
+            if (registeredServices != null) {
+                for (ServiceReference reference : registeredServices) {
+                    List<String> oc = Arrays.asList((String[]) reference.getProperty("objectClass"));
+
+                    if (oc.contains("org.springframework.context.ApplicationContext")) {
+                        classes.add("spring");
+                        break;
+                    }
+
+                }
+            }
+
+            return classes;
+        }
+
+    }
+
+    /**
+     * Constructor that is invoked when page is invoked without a session.
+     * 
+     * @param parameters Page parameters
+     */
+    public HomePage() {
+        final List<ItemClassModifier> modifiers = new ArrayList<HomePage.ItemClassModifier>();
+        modifiers.add(new SystemBundleClassModifier());
+        modifiers.add(new BlueprintClassModifier());
+        modifiers.add(new SpringClassModifier());
+
+        List<Bundle> model = context == null ? new ArrayList() : Arrays.asList(context.getBundles());
+
+        add(new ListView<Bundle>("bundles", model) {
+            @Override
+            protected void populateItem(ListItem<Bundle> item) {
+                final Bundle bundle = item.getModelObject();
+                item.add(new Label("id", "" + bundle.getBundleId()));
+                item.add(new Label("symbolicName", bundle.getSymbolicName()));
+                item.add(new Label("version", bundle.getVersion().toString()));
+
+                List<String> classes = new ArrayList<String>() {
+                    @Override
+                    public String toString() {
+                        String toString = "";
+                        for (String item : this) {
+                            toString += " " + item;
+                        }
+                        return toString;
+                    }
+                };
+
+                for (ItemClassModifier modifier : modifiers) {
+                    classes.addAll(modifier.getCssClasses(bundle));
+                }
+
+                item.add(new SimpleAttributeModifier("class", classes.toString()));
+                item.add(new Link("link") {
+                    @Override
+                    public void onClick() {
+                        PageParameters params = new PageParameters();
+                        params.put("bundleId", bundle.getBundleId());
+                        setResponsePage(new DetailsPage(params));
+                    }
+                });
+            }
+        });
+
+    }
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/OsgiConsoleTab.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/OsgiConsoleTab.java
new file mode 100644
index 0000000..be80e8c
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/OsgiConsoleTab.java
@@ -0,0 +1,24 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.webconsole.core.ConsoleTab;
+
+public class OsgiConsoleTab implements ConsoleTab {
+
+	public String getLabel() {
+		return "Runtime";
+	}
+
+	public Class getModuleHomePage() {
+		return HomePage.class;
+	}
+
+	public Map<String, Class> getItems() {
+		Map<String, Class> map = new HashMap<String, Class>();
+		map.put("OSGi", HomePage.class);
+		return map;
+	}
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.java
new file mode 100644
index 0000000..daf734b
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.java
@@ -0,0 +1,72 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.NavigationToolbar;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+public class RepositoriesPage extends BasePage {
+
+	@PaxWicketBean(name = "featuresService")
+	private FeaturesService featuresService;
+
+	public RepositoriesPage() {
+		List<ExtendedRepository> repos = new LinkedList<ExtendedRepository>();
+		for (Repository repo : featuresService.listRepositories()) {
+			repos.add(new ExtendedRepository(repo));
+		}
+
+		IColumn[] columns = new IColumn[] {
+			new PropertyColumn<Repository>(Model.of("name"), "name", "name"),
+			new PropertyColumn<Repository>(Model.of("URI"), "URI", "URI"),
+			new PropertyColumn<Repository>(Model.of("valid"), "valid", "valid"),
+		};
+
+		ListDataProvider provider = new ListDataProvider(repos);
+		DataTable<Repository> dataTable = new DataTable<Repository>("repositories", columns, provider, 10);
+		dataTable.addTopToolbar(new NavigationToolbar(dataTable));
+		add(dataTable);
+	}
+
+	class ExtendedRepository implements Repository, Serializable {
+
+		private final Repository repository;
+
+		public ExtendedRepository(Repository r) {
+			this.repository = r;
+		}
+
+		public String getName() {
+			return repository.getName();
+		}
+
+		public URI getURI() {
+			return repository.getURI();
+		}
+
+		public URI[] getRepositories() throws Exception {
+			return repository.getRepositories();
+		}
+
+		public Feature[] getFeatures() throws Exception {
+			return repository.getFeatures();
+		}
+
+		public boolean isValid() {
+			return repository.isValid();
+		}
+
+	}
+}
diff --git a/osgi/src/main/resources/OSGI-INF/blueprint/wicket.xml b/osgi/src/main/resources/OSGI-INF/blueprint/wicket.xml
new file mode 100644
index 0000000..cea1b2d
--- /dev/null
+++ b/osgi/src/main/resources/OSGI-INF/blueprint/wicket.xml
@@ -0,0 +1,14 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+    xmlns:wicket="http://www.ops4j.org/schema/wicket">
+
+    <service auto-export="interfaces">
+        <bean class="org.apache.karaf.webconsole.osgi.internal.OsgiConsoleTab" />
+    </service>
+    
+    <service auto-export="interfaces">
+        <bean class="org.apache.karaf.webconsole.osgi.internal.FeaturesConsoleTab" />
+    </service>
+    
+    <reference id="featuresService" interface="org.apache.karaf.features.FeaturesService"/>
+
+</blueprint>
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/DetailsPage.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/DetailsPage.html
new file mode 100644
index 0000000..ca9e23e
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/DetailsPage.html
@@ -0,0 +1,46 @@
+<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
+    <body>
+        <h1>Bundle details</h1>
+
+        <wicket:extend>
+            Details of <span wicket:id="name">symbolic name</span>
+
+            <h3>Imports</h3>
+            <ul>
+                <li wicket:id="imports">
+                    <span wicket:id="importPackage">org.osgi.framework</span>
+                </li>
+            </ul>
+
+            <h3>Exports</h3>
+            <ul>
+                <li wicket:id="exports">
+                    <span wicket:id="exportPackage">org.osgi.framework</span>
+                </li>
+            </ul>
+
+            <h3>Services in use</h3>
+            <ul>
+                <li wicket:id="servicesInUse">
+                    <span wicket:id="serviceInUse">org.osgi.framework</span>
+                    <table>
+                        <tr>
+                            <th>Property Name</th>
+                            <th>Property Value</th>
+                        </tr>
+                        <tr wicket:id="serviceInUseProperty">
+                            <td wicket:id="propertyName">Property Name</td>
+                            <td wicket:id="propertyValue">Property Value</td>
+                        </tr>
+                    </table>
+                </li>
+            </ul>
+            <!-- 
+            <ul>
+                <li wicket:id="servicesExported">
+                    <span wicket:id="serviceExported">org.osgi.framework</span>
+                </li>
+            </ul> -->
+        </wicket:extend>
+    </body>
+</html>
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html
new file mode 100644
index 0000000..366eb8f
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
+    <wicket:head>
+
+        <title>Karaf Wicket console - Features page</title>
+
+        <!--
+        <style type="text/css">
+            tr.system {
+                background-color: #CC6600;
+            }
+
+            tr.framework {
+                background-color: #EAB988;
+            }
+
+            tr.blueprint {
+                background-color: #FDF8F2;
+            }
+
+            tr.spring {
+                background-color: #D5D50D;
+            }
+        </style>
+        -->
+    </wicket:head>
+
+    <body>
+
+        <wicket:extend>
+
+            <h1>Features</h1>
+
+            <!--
+            <table>
+                <tr>
+                    <th>State</th>
+                    <th>Version</th>
+                    <th>Name</th>
+                    <th>Repository</th>
+                    <th>Description</th>
+                </tr>
+
+                <tr wicket:id="features">
+                    <td wicket:id="state">State</td>
+                    <td wicket:id="version">Version</td>
+                    <td wicket:id="name">Name</td>
+                    <td wicket:id="repository">Repository</td>
+                    <td wicket:id="description">Description</td>
+                    <td>
+                        <a href="FeatureDetailsPage.html" wicket:id="featuresDetailsPageLink">details</a>
+                    </td>
+                </tr>
+            </table>
+            -->
+            <table wicket:id="features" class="dataview"/>
+        </wicket:extend>
+    </body>
+</html>
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/HomePage.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/HomePage.html
new file mode 100644
index 0000000..3758f44
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/HomePage.html
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
+    <wicket:head>
+
+        <title>Karaf Wicket console</title>
+        
+        <style type="text/css">
+            tr.system {
+                background-color: #CC6600;
+            }
+
+            tr.framework {
+                background-color: #EAB988;
+            }
+
+            tr.blueprint {
+                background-color: #FDF8F2;
+            }
+
+            tr.spring {
+                background-color: #D5D50D;
+            }
+        </style>
+
+    </wicket:head>
+
+    <body>
+
+        <wicket:extend>
+
+            <h1>Bundles</h1>
+
+            <table>
+                <tr>
+                    <th>ID</th>
+                    <th>Symbolic name</th>
+                    <th>Version</th>
+                    <th>Details</th>
+                </tr>
+
+                <tr wicket:id="bundles">
+                    <td wicket:id="id">Id</td>
+                    <td wicket:id="symbolicName">Symbolic name</td>
+                    <td wicket:id="version">Version</td>
+                    <td>
+                        <a wicket:id="link" href="DetailsPage.html">bundle details</a>
+                    </td>
+                </tr>
+            </table>
+        </wicket:extend>
+    </body>
+</html>
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.html
new file mode 100644
index 0000000..cf2fe54
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/RepositoriesPage.html
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >
+    <wicket:head>
+        <title>Karaf Wicket console - Features page</title>
+    </wicket:head>
+
+    <body>
+
+        <wicket:extend>
+            <h1>Feature Repositories</h1>
+
+            <table wicket:id="repositories" class="dataview"/>
+        </wicket:extend>
+    </body>
+</html>
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..48ba2a5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.karaf</groupId>
+    <artifactId>webconsole</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <name>Apache Karaf :: Karaf Webconsole Prototype</name>
+
+    <packaging>pom</packaging>
+
+    <properties>
+        <jetty.version>6.1.25</jetty.version>
+        <slf4j.version>1.5.8</slf4j.version>
+        <log4j.version>1.2.14</log4j.version>
+        <ops4j.paxwicket.version>0.8.0-SNAPSHOT</ops4j.paxwicket.version>
+        <karaf.version>2.2.2</karaf.version>
+    </properties>
+
+    <modules>
+        <module>core</module>
+        <module>osgi</module>
+        <module>features</module>
+    </modules>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <configuration>
+                        <source>1.5</source>
+                        <target>1.5</target>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>wiquery</id>
+            <name>wiquery wicket components</name>
+            <url>http://wiquery.googlecode.com/svn/repo/</url>
+        </repository>
+    </repositories>
+
+</project>