Merge of osgi framework and bundle modules into core module. All dependant changes + features update. Add new pages to core - services and package introspection (needs more work).

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1242797 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/assembly/src/main/resources/features.xml b/assembly/src/main/resources/features.xml
index c3e9d9a..78b74e3 100644
--- a/assembly/src/main/resources/features.xml
+++ b/assembly/src/main/resources/features.xml
@@ -41,8 +41,7 @@
   <feature name="webconsole-osgi" version="${project.version}" description="Karaf WebConsole OSGi Core">
     <details>Adds support for osgi packages to the webconsole.</details>
     <feature>webconsole-core</feature>
-    <bundle>mvn:org.apache.karaf.webconsole.osgi/org.apache.karaf.webconsole.osgi.framework/${project.version}</bundle>
-    <bundle>mvn:org.apache.karaf.webconsole.osgi/org.apache.karaf.webconsole.osgi.bundle/${project.version}</bundle>
+    <bundle>mvn:org.apache.karaf.webconsole.osgi/org.apache.karaf.webconsole.osgi.core/${project.version}</bundle>
   </feature>
 
   <feature name="webconsole-config" version="${project.version}" description="Karaf WebConsole OSGi ConfigurationAdmin">
@@ -82,7 +81,7 @@
     <details>Adds support for osgi Service Components. This feature also install felix scr runtime.</details>
     <feature>webconsole-osgi</feature>
     <bundle>mvn:org.apache.felix/org.apache.felix.scr/${felix-scr.version}</bundle>
-    <bundle>mvn:org.apache.karaf.webconsole.osgi/org.apache.karaf.webconsole.osgi.log/${project.version}</bundle>
+    <bundle>mvn:org.apache.karaf.webconsole.osgi/org.apache.karaf.webconsole.osgi.scr/${project.version}</bundle>
   </feature>
 
 </features>
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
new file mode 100644
index 0000000..f3fb286
--- /dev/null
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
@@ -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.karaf.webconsole.core.page;
+
+import org.apache.karaf.webconsole.core.WebConsoleTest;
+import org.apache.karaf.webconsole.core.test.AlwaysAuthenticatedWebSession;
+import org.apache.wicket.authentication.AuthenticatedWebSession;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Test secured page and navigation rendering.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class SecuredPageTest extends WebConsoleTest {
+
+    /**
+     * Test logout link behavior.
+     */
+    @Test
+    public void shouldRenderLogoutLink() {
+        WicketTester tester = new WicketTester(application);
+
+        tester.startPage(SinglePage.class);
+        tester.debugComponentTrees();
+        tester.clickLink("topPanel:logoutLink");
+        tester.assertRenderedPage(LoginPage.class);
+    }
+
+    protected Class<? extends AuthenticatedWebSession> getWebSessionClass() {
+        return AlwaysAuthenticatedWebSession.class;
+    }
+
+}
diff --git a/osgi/blueprint/pom.xml b/osgi/blueprint/pom.xml
index a54428b..0f802cb 100644
--- a/osgi/blueprint/pom.xml
+++ b/osgi/blueprint/pom.xml
@@ -33,8 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.bundle</artifactId>
-            <version>${project.version}</version>
+            <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
         </dependency>
 
         <dependency>
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintDataProvider.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintDataProvider.java
index d8c661c..56aef1d 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintDataProvider.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintDataProvider.java
@@ -20,7 +20,7 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.karaf.webconsole.osgi.blueprint.model.ServiceReferenceModel;
+import org.apache.karaf.webconsole.osgi.core.shared.ServiceReferenceModel;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 import org.apache.wicket.model.IModel;
 import org.osgi.framework.ServiceReference;
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintPage.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintPage.java
index 66c50ca..8471ab4 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintPage.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/BlueprintPage.java
@@ -48,7 +48,7 @@
 
                 PageParameters params = new PageParameters();
                 params.put("bundleId", reference.getBundle().getBundleId());
-                item.add(new BookmarkablePageLink<DetailsPage>("details", DetailsPage.class, params));
+                item.add(new BookmarkablePageLink<SingleBundlePage>("details", SingleBundlePage.class, params));
             }
             
         });
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintActionProvider.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintActionProvider.java
index aaf700f..2290ebc 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintActionProvider.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintActionProvider.java
@@ -18,7 +18,7 @@
 
 import org.apache.karaf.webconsole.osgi.blueprint.IBlueprintBundleStateTracker;
 import org.apache.karaf.webconsole.osgi.blueprint.details.DetailsPage;
-import org.apache.karaf.webconsole.osgi.bundle.IActionProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IActionProvider;
 import org.apache.wicket.Component;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintColumnProvider.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintColumnProvider.java
index 3844485..307ed95 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintColumnProvider.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintColumnProvider.java
@@ -18,7 +18,7 @@
 
 import org.apache.karaf.webconsole.osgi.blueprint.BlueprintState;
 import org.apache.karaf.webconsole.osgi.blueprint.IBlueprintBundleStateTracker;
-import org.apache.karaf.webconsole.osgi.bundle.IColumnProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintDecorationProvider.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintDecorationProvider.java
index cdda501..a4182ba 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintDecorationProvider.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/bundle/BlueprintDecorationProvider.java
@@ -18,7 +18,7 @@
 
 import org.apache.karaf.webconsole.core.panel.StaticImagePanel;
 import org.apache.karaf.webconsole.osgi.blueprint.IBlueprintBundleStateTracker;
-import org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
 import org.apache.wicket.ResourceReference;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/DetailsPage.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/DetailsPage.java
index 83e556d..da36a04 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/DetailsPage.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/DetailsPage.java
@@ -19,7 +19,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.markup.html.JavascriptPackageResource;
 import org.apache.wicket.markup.html.basic.Label;
diff --git a/osgi/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/osgi/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index bafa115..8a7ccbb 100644
--- a/osgi/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/osgi/blueprint/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -33,7 +33,7 @@
 
     <bean id="tracker" class="org.apache.karaf.webconsole.osgi.blueprint.BlueprintBundleStateTracker" />
 
-    <service interface="org.apache.karaf.webconsole.osgi.bundle.IActionProvider">
+    <service auto-export="interfaces">
         <bean class="org.apache.karaf.webconsole.osgi.blueprint.bundle.BlueprintActionProvider">
             <argument ref="trackerService" />
         </bean>
diff --git a/osgi/bundle/pom.xml b/osgi/bundle/pom.xml
deleted file mode 100644
index d332649..0000000
--- a/osgi/bundle/pom.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.karaf.webconsole</groupId>
-        <artifactId>osgi</artifactId>
-        <version>0.3.0-SNAPSHOT</version>
-    </parent>
-
-    <groupId>org.apache.karaf.webconsole.osgi</groupId>
-    <artifactId>org.apache.karaf.webconsole.osgi.bundle</artifactId>
-    <name>Apache Karaf :: WebConsole :: OSGi :: Bundle</name>
-    <packaging>bundle</packaging>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <configuration>
-                    <instructions>
-                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
-                        <Import-Package>
-                            !org.apache.karaf.webconsole.osgi.bundle*,
-                            *,<!-- let bnd import direct dependencies -->
-                            <!-- transient dependencies -->
-                            org.ops4j.pax.wicket.api,
-                            org.ops4j.pax.wicket.util,
-                            org.ops4j.pax.wicket.util.proxy
-                        </Import-Package>
-                        <Export-Package>
-                            org.apache.karaf.webconsole.osgi.bundle
-                        </Export-Package>
-                    </instructions>
-                </configuration>
-                <extensions>true</extensions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundleNavigationProvider.java b/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundleNavigationProvider.java
deleted file mode 100644
index af8b0fa..0000000
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundleNavigationProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.karaf.webconsole.osgi.bundle.internal;
-
-import static org.apache.karaf.webconsole.core.util.LinkUtils.createPageLink;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.karaf.webconsole.core.navigation.NavigationProvider;
-import org.apache.wicket.Page;
-import org.apache.wicket.markup.html.link.Link;
-
-public class BundleNavigationProvider implements NavigationProvider {
-
-    public List<Link<Page>> getItems(String componentId, String labelId) {
-        List<Link<Page>> links = new ArrayList<Link<Page>>();
-        links.add(createPageLink(componentId, labelId, "Bundles", BundlesPage.class));
-        return links;
-    }
-
-}
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.java b/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.java
deleted file mode 100644
index 9d4ec22..0000000
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.karaf.webconsole.osgi.bundle.internal;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.karaf.webconsole.core.page.SinglePage;
-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.apache.wicket.model.IModel;
-import org.apache.wicket.model.LoadableDetachableModel;
-import org.ops4j.pax.wicket.api.PaxWicketBean;
-import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-@PaxWicketMountPoint(mountPoint = "/osgi/bundle/detail")
-public class DetailsPage extends SinglePage {
-
-    @PaxWicketBean(name = "blueprintBundleContext")
-    private BundleContext context;
-    private long bundleId;
-
-    public DetailsPage(PageParameters params) {
-        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()));
-            }
-        });
-
-        IModel<List<ServiceReference>> model = new LoadableDetachableModel<List<ServiceReference>>() {
-            @Override
-            protected List<ServiceReference> load() {
-                return Arrays.asList(context.getBundle(bundleId).getServicesInUse());
-            }
-        };
-
-        add(new ListView<ServiceReference>("servicesInUse", model) {
-            @Override
-            protected void populateItem(ListItem<ServiceReference> item) {
-                ServiceReference reference = item.getModelObject();
-                item.add(new Label("serviceInUse", Arrays.toString((String[]) reference.getProperty("objectClass"))));
-            }
-        });
-
-        model = new LoadableDetachableModel<List<ServiceReference>>() {
-            @Override
-            protected List<ServiceReference> load() {
-                return Arrays.asList(context.getBundle(bundleId).getRegisteredServices());
-            }
-        };
-
-        add(new ListView<ServiceReference>("servicesExported", model) {
-            @Override
-            protected void populateItem(ListItem<ServiceReference> item) {
-                ServiceReference reference = item.getModelObject();
-                item.add(new Label("serviceExported", Arrays.toString((String[]) reference.getProperty("objectClass"))));
-            }
-        });
-    }
-
-
-}
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundlesDataTable.java b/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundlesDataTable.java
deleted file mode 100644
index 2c85c46..0000000
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundlesDataTable.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.karaf.webconsole.osgi.bundle.internal.view;
-
-import java.util.List;
-
-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.ISortableDataProvider;
-import org.osgi.framework.Bundle;
-
-public class BundlesDataTable extends DefaultDataTable<Bundle> {
-
-    public BundlesDataTable(String id, List<IColumn<Bundle>> columns, ISortableDataProvider<Bundle> dataProvider, int rowsPerPage) {
-        super(id, columns, dataProvider, rowsPerPage);
-    }
-
-}
diff --git a/osgi/bundle/src/main/resources/OSGI-INF/blueprint/osgi.xml b/osgi/bundle/src/main/resources/OSGI-INF/blueprint/osgi.xml
deleted file mode 100644
index 3c7be24..0000000
--- a/osgi/bundle/src/main/resources/OSGI-INF/blueprint/osgi.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?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.
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="
-        http://www.osgi.org/xmlns/blueprint/v1.0.0
-        http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
-    ">
-
-    <reference id="startLevel" interface="org.osgi.service.startlevel.StartLevel" />
-    <reference id="packageAdmin" interface="org.osgi.service.packageadmin.PackageAdmin" />
-
-    <reference-list id="columnProviders" interface="org.apache.karaf.webconsole.osgi.bundle.IColumnProvider" availability="optional" />
-    <reference-list id="actionProviders" interface="org.apache.karaf.webconsole.osgi.bundle.IActionProvider" availability="optional" />
-    <reference-list id="decorationProviders" interface="org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider" availability="optional" />
-
-    <service auto-export="interfaces">
-        <bean class="org.apache.karaf.webconsole.osgi.bundle.internal.view.SystemBundleDecorationProvider">
-            <argument ref="startLevel" />
-        </bean>
-    </service>
-
-    <service ref="bundleNavigationProvider" interface="org.apache.karaf.webconsole.core.navigation.NavigationProvider">
-        <service-properties>
-            <entry key="extends" value="osgi" />
-            <entry key="service.ranking" value="1" />
-        </service-properties>
-    </service>
-
-    <bean id="bundleNavigationProvider" class="org.apache.karaf.webconsole.osgi.bundle.internal.BundleNavigationProvider" />
-
-</blueprint>
diff --git a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.html b/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.html
deleted file mode 100644
index dd9d9fb..0000000
--- a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/DetailsPage.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<?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.
--->
-<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <h1>Bundle details</h1>
-    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>
-
-    <h3>Services provided by bundle</h3>
-    <ul>
-        <li wicket:id="servicesExported">
-            <span wicket:id="serviceExported">org.osgi.framework</span>
-        </li>
-    </ul>
-</wicket:extend>
\ No newline at end of file
diff --git a/osgi/config/pom.xml b/osgi/config/pom.xml
index dc81806..25dfe7c 100644
--- a/osgi/config/pom.xml
+++ b/osgi/config/pom.xml
@@ -33,8 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
-            <version>${project.version}</version>
+            <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationEditPage.java b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationEditPage.java
index b63eb84..4394291 100644
--- a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationEditPage.java
+++ b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationEditPage.java
@@ -24,7 +24,7 @@
 import org.apache.karaf.webconsole.core.table.map.MapDataTable;
 import org.apache.karaf.webconsole.core.util.DictionaryUtils;
 import org.apache.karaf.webconsole.osgi.config.model.ConfigurationModel;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.RequestCycle;
 import org.apache.wicket.Session;
diff --git a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationNavigationProvider.java b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationNavigationProvider.java
index c075431..1399ec2 100644
--- a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationNavigationProvider.java
+++ b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationNavigationProvider.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.config;
 
 import static org.apache.karaf.webconsole.core.util.LinkUtils.createPageLink;
@@ -9,6 +25,9 @@
 import org.apache.wicket.Page;
 import org.apache.wicket.markup.html.link.Link;
 
+/**
+ * Navigation provider for configurations.
+ */
 public class ConfigurationNavigationProvider implements NavigationProvider {
 
     public List<Link<Page>> getItems(String componentId, String labelId) {
diff --git a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationRemovePage.java b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationRemovePage.java
index aa8da63..07c6c62 100644
--- a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationRemovePage.java
+++ b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationRemovePage.java
@@ -18,7 +18,7 @@
 
 import org.apache.karaf.webconsole.osgi.config.model.ConfigurationModel;
 import org.apache.karaf.webconsole.osgi.config.view.ConfigurationRemoveForm;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.markup.html.basic.Label;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
diff --git a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationsPage.java b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationsPage.java
index f6a286c..695fae4 100644
--- a/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationsPage.java
+++ b/osgi/config/src/main/java/org/apache/karaf/webconsole/osgi/config/ConfigurationsPage.java
@@ -17,7 +17,7 @@
 package org.apache.karaf.webconsole.osgi.config;
 
 import org.apache.karaf.webconsole.osgi.config.view.ConfigurationsDataTable;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.wicket.markup.html.CSSPackageResource;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
 import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
diff --git a/osgi/bundle/NOTICE b/osgi/core/NOTICE
similarity index 100%
rename from osgi/bundle/NOTICE
rename to osgi/core/NOTICE
diff --git a/osgi/framework/pom.xml b/osgi/core/pom.xml
similarity index 61%
rename from osgi/framework/pom.xml
rename to osgi/core/pom.xml
index d9793ce..7b5af22 100644
--- a/osgi/framework/pom.xml
+++ b/osgi/core/pom.xml
@@ -26,8 +26,8 @@
     </parent>
 
     <groupId>org.apache.karaf.webconsole.osgi</groupId>
-    <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
-    <name>Apache Karaf :: WebConsole :: OSGi :: Framework</name>
+    <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
+    <name>Apache Karaf :: WebConsole :: OSGi :: Core</name>
     <packaging>bundle</packaging>
 
     <dependencies>
@@ -40,6 +40,25 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <version>1.1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.10</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <version>1.6.4</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -50,18 +69,37 @@
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            org.apache.karaf.webconsole.osgi.core.spi,
+                            org.apache.karaf.webconsole.osgi.core.shared
+                        </Export-Package>
                         <Import-Package>
-                            !org.apache.karaf.webconsole.osgi.framework*,
+                            !org.apache.karaf.webconsole.osgi.core*,
                             *,<!-- let bnd import direct dependencies -->
                             <!-- transient dependencies -->
                             org.ops4j.pax.wicket.api,
                             org.ops4j.pax.wicket.util,
                             org.ops4j.pax.wicket.util.proxy
                         </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.webconsole.osgi.core*,
+                            <!-- manifest parsing -->
+                            org.apache.felix.utils.manifest,
+                            org.apache.felix.utils.version
+                        </Private-Package>
                     </instructions>
                 </configuration>
                 <extensions>true</extensions>
             </plugin>
         </plugins>
     </build>
+
+
+    <repositories>
+        <repository>
+		    <id>com.springsource.repository.bundles.release</id>
+		    <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+		    <url>http://repository.springsource.com/maven/bundles/release</url>
+		</repository>
+    </repositories>
 </project>
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/FrameworkPage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/FrameworkPage.java
similarity index 88%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/FrameworkPage.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/FrameworkPage.java
index d04dc71..3f159f9 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/FrameworkPage.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/FrameworkPage.java
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework.internal;
+package org.apache.karaf.webconsole.osgi.core;
 
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
-import org.apache.karaf.webconsole.osgi.framework.SystemBundleModel;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.SystemBundleModel;
 import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.CompoundPropertyModel;
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.java
new file mode 100644
index 0000000..233f129
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.java
@@ -0,0 +1,128 @@
+/*
+ * 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.karaf.webconsole.osgi.core.bundle;
+
+import java.io.IOException;
+
+import org.apache.karaf.webconsole.core.security.SecuredPageLink;
+import org.apache.karaf.webconsole.osgi.core.pkg.ExportPackageTable;
+import org.apache.karaf.webconsole.osgi.core.pkg.ImportPackageTable;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+import org.osgi.framework.Bundle;
+
+@PaxWicketMountPoint(mountPoint = "/osgi/bundle/detail")
+public class SingleBundlePage extends OsgiPage {
+
+    public static String BUNDLE_ID = "bundleId";
+
+    private long bundleId;
+
+    public SingleBundlePage(PageParameters params) throws IOException {
+        bundleId = params.getLong("bundleId");
+        Bundle bundle = context.getBundle(bundleId);
+
+        //ExportedPackage[] exported = admin.getExportedPackages(bundle);
+
+        add(new Label("name", bundle.getSymbolicName()).setRenderBodyOnly(true));
+
+//        String object = (String) bundle.getHeaders().get(Constants.IMPORT_PACKAGE);
+//        if (object == null) object = "";
+        add(new ImportPackageTable("imports", bundle));
+
+//        add(new ListView<Package>("imports", parser.getImportPackages()) {
+//            @Override
+//            protected void populateItem(ListItem<Package> item) {
+//                Package model = item.getModelObject();
+//                String value = model.getName();
+//                item.add(new Label("importPackage", value));
+//            }
+//        });
+
+        add(new ExportPackageTable("exports", bundle));
+
+//        IModel<List<ServiceReference>> model = new LoadableDetachableModel<List<ServiceReference>>() {
+//            @Override
+//            protected List<ServiceReference> load() {
+//                return Arrays.asList(context.getBundle(bundleId).getServicesInUse());
+//            }
+//        };
+//
+//        add(new ListView<ServiceReference>("servicesIn", model) {
+//            @Override
+//            protected void populateItem(ListItem<ServiceReference> item) {
+//                ServiceReference reference = item.getModelObject();
+//                item.add(new Label("serviceInUse", Arrays.toString((String[]) reference.getProperty("objectClass"))));
+//            }
+//        });
+//
+//        model = new LoadableDetachableModel<List<ServiceReference>>() {
+//            @Override
+//            protected List<ServiceReference> load() {
+//                return Arrays.asList(context.getBundle(bundleId).getRegisteredServices());
+//            }
+//        };
+//
+//        add(new ListView<ServiceReference>("servicesOut", model) {
+//            @Override
+//            protected void populateItem(ListItem<ServiceReference> item) {
+//                ServiceReference reference = item.getModelObject();
+//                item.add(new Label("serviceExported", Arrays.toString((String[]) reference.getProperty("objectClass"))));
+//            }
+//        });
+    }
+
+//    public static void main(String[] args) throws IOException {
+//        Manifest manifest = new Manifest(new FileInputStream("target/classes/META-INF/MANIFEST.MF"));
+//        Attributes mainAttributes = manifest.getMainAttributes();
+//
+//        Map<String, Map<String, String>> keySet = OSGiHeader.parseHeader(manifest.getMainAttributes().getValue(Constants.IMPORT_PACKAGE));
+//        System.out.println(keySet);
+//
+////        for (Entry<Object, Object> string : mainAttributes.entrySet()) {
+////            System.out.println(OSGiHeader.parseHeader("" + string.getValue()));
+////        }
+//    }
+
+    /**
+     * Create link to page with given bundle.
+     * 
+     * @param id Link id.
+     * @param bundle Bundle.
+     * @return Link to page.
+     */
+    public static Link<SingleBundlePage> createLink(String id, Bundle bundle) {
+        return createLink(id, bundle.getBundleId());
+    }
+
+    /**
+     * Create link to page with given bundle id..
+     * 
+     * @param id Link id.
+     * @param bundleId Bundle identifier.
+     * @return Link to page.
+     */
+    public static Link<SingleBundlePage> createLink(String id, long bundleId) {
+        PageParameters params = new PageParameters();
+        params.put(BUNDLE_ID, bundleId);
+        return new SecuredPageLink<SingleBundlePage>(id, SingleBundlePage.class, params);
+    }
+
+}
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundleActionsPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
similarity index 87%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundleActionsPanel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
index d6fa107..e249ec3 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/BundleActionsPanel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
@@ -14,16 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle.internal.view;
+package org.apache.karaf.webconsole.osgi.core.bundle.list;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.karaf.webconsole.core.table.ActionsPanel;
-import org.apache.karaf.webconsole.osgi.bundle.IActionProvider;
-import org.apache.karaf.webconsole.osgi.bundle.internal.BundlesPage;
-import org.apache.karaf.webconsole.osgi.bundle.internal.DetailsPage;
-import org.apache.karaf.webconsole.osgi.bundle.internal.State;
+import org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage;
+import org.apache.karaf.webconsole.osgi.core.shared.State;
+import org.apache.karaf.webconsole.osgi.core.spi.IActionProvider;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.RequestCycle;
 import org.apache.wicket.Session;
@@ -66,7 +65,7 @@
         List<Link> links = new ArrayList<Link>();
 
         // details link
-        Link link = new BookmarkablePageLink<DetailsPage>(linkId, DetailsPage.class, params);
+        Link link = new BookmarkablePageLink<SingleBundlePage>(linkId, SingleBundlePage.class, params);
         link.add(new Label("label", "Details"));
 
         links.add(link);
@@ -96,7 +95,7 @@
                     bundle.uninstall();
 
                     Session.get().info("Bundle " + bundle.getSymbolicName() + " uninstalled");
-                    RequestCycle.get().setResponsePage(BundlesPage.class);
+                    RequestCycle.get().setResponsePage(BundlePage.class);
                 } catch (BundleException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
@@ -116,7 +115,7 @@
 
                 admin.refreshPackages(new Bundle[] {bundle});
                 Session.get().info("Bundle " + bundle.getSymbolicName() + " refreshed");
-                RequestCycle.get().setResponsePage(BundlesPage.class);
+                RequestCycle.get().setResponsePage(BundlePage.class);
             }
             
         };
@@ -133,7 +132,7 @@
                 try {
                     bundle.start();
                     Session.get().info("Bundle " + bundle.getSymbolicName() + " started");
-                    RequestCycle.get().setResponsePage(BundlesPage.class);
+                    RequestCycle.get().setResponsePage(BundlePage.class);
                 } catch (BundleException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
@@ -152,7 +151,7 @@
                 try {
                     bundle.stop();
                     Session.get().info("Bundle " + bundle.getSymbolicName() + " stopped");
-                    RequestCycle.get().setResponsePage(BundlesPage.class);
+                    RequestCycle.get().setResponsePage(BundlePage.class);
                 } catch (BundleException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesPage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
similarity index 82%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesPage.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
index 4004081..589003c 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesPage.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle.internal;
+package org.apache.karaf.webconsole.osgi.core.bundle.list;
 
 import static org.apache.wicket.model.Model.of;
 
@@ -22,15 +22,15 @@
 import java.util.List;
 
 import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
-import org.apache.karaf.webconsole.osgi.bundle.IActionProvider;
-import org.apache.karaf.webconsole.osgi.bundle.IColumnProvider;
-import org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider;
-import org.apache.karaf.webconsole.osgi.bundle.internal.view.BundleActionsPanel;
-import org.apache.karaf.webconsole.osgi.bundle.internal.view.BundlesDataTable;
-import org.apache.karaf.webconsole.osgi.bundle.internal.view.DecorationPanel;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.BundleDataProvider;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.State;
+import org.apache.karaf.webconsole.osgi.core.spi.IActionProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+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.markup.html.basic.Label;
 import org.apache.wicket.markup.repeater.Item;
@@ -41,8 +41,8 @@
 import org.osgi.framework.Bundle;
 import org.osgi.service.startlevel.StartLevel;
 
-@PaxWicketMountPoint(mountPoint = "/osgi/bundles")
-public class BundlesPage extends OsgiPage {
+@PaxWicketMountPoint(mountPoint = "/osgi/bundle")
+public class BundlePage extends OsgiPage {
 
     @PaxWicketBean(name = "columnProviders")
     private List<IColumnProvider> columnProviders;
@@ -56,7 +56,7 @@
     @PaxWicketBean(name = "startLevel")
     private StartLevel startLevel;
 
-    public BundlesPage() {
+    public BundlePage() {
         List<IColumn<Bundle>> columns = new ArrayList<IColumn<Bundle>>();
         columns.add(new AbstractColumn<Bundle>(of("")) {
             public void populateItem(Item<ICellPopulator<Bundle>> cellItem, final String componentId, final IModel<Bundle> rowModel) {
@@ -89,7 +89,7 @@
             }
         });
 
-        add(new BundlesDataTable("bundles", columns, new BundlesDataProvider(context), 100));
+        add(new DefaultDataTable<Bundle>("bundles", columns, new BundleDataProvider(context), 100));
     }
 
 }
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/DecorationPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
similarity index 93%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/DecorationPanel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
index b184204..df06406 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/DecorationPanel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
@@ -14,12 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle.internal.view;
+package org.apache.karaf.webconsole.osgi.core.bundle.list;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
 import org.apache.wicket.Component;
 import org.apache.wicket.markup.html.CSSPackageResource;
 import org.apache.wicket.markup.html.list.ListItem;
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/SystemBundleDecorationProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/SystemBundleDecorationProvider.java
similarity index 92%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/SystemBundleDecorationProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/SystemBundleDecorationProvider.java
index 5a9c041..ee8cb6f 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/view/SystemBundleDecorationProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/SystemBundleDecorationProvider.java
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle.internal.view;
+package org.apache.karaf.webconsole.osgi.core.bundle.list;
 
 import org.apache.karaf.webconsole.core.panel.CssImagePanel;
-import org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.osgi.framework.Bundle;
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ExportPackage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ExportPackage.java
new file mode 100644
index 0000000..7878824
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ExportPackage.java
@@ -0,0 +1,31 @@
+package org.apache.karaf.webconsole.osgi.core.manifest;
+
+import org.osgi.framework.Version;
+
+public class ExportPackage extends Package {
+
+	private static final long serialVersionUID = 1L;
+	private Version version;
+	private String uses;
+
+	public ExportPackage(String name) {
+		super(name);
+	}
+
+	public void setVersion(Version version) {
+		this.version = version;
+	}
+
+	public Version getVersion() {
+		return version;
+	}
+
+	public void setUses(String uses) {
+		this.uses = uses;
+	}
+
+	public String getUses() {
+		return uses;
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ImportPackage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ImportPackage.java
new file mode 100644
index 0000000..3b7f65d
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ImportPackage.java
@@ -0,0 +1,22 @@
+package org.apache.karaf.webconsole.osgi.core.manifest;
+
+import org.apache.felix.utils.version.VersionRange;
+
+public class ImportPackage extends Package {
+
+	private static final long serialVersionUID = 1L;
+	private VersionRange versionRange;
+	private String provider;
+
+	public ImportPackage(String name) {
+		super(name);
+	}
+
+	public void setVersionRange(VersionRange versionRange) {
+		this.versionRange = versionRange;
+	}
+
+	public VersionRange getVersionRange() {
+		return versionRange;
+	}
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ManifestUtil.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ManifestUtil.java
new file mode 100644
index 0000000..9772db9
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ManifestUtil.java
@@ -0,0 +1,25 @@
+package org.apache.karaf.webconsole.osgi.core.manifest;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.osgi.framework.Bundle;
+
+public abstract class ManifestUtil {
+
+    public static Clause[] getHeader(Bundle bundle, String header) throws IOException {
+        return getHeader(bundle.getResource("META-INF/MANIFEST.MF").openStream(), header);
+    }
+
+    public static Clause[] getHeader(InputStream stream, String header) throws IOException {
+        Manifest manifest = new Manifest(stream);
+		Attributes mainAttributes = manifest.getMainAttributes();
+		String value = mainAttributes.getValue(header);
+        return Parser.parseHeader(value);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/Package.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/Package.java
new file mode 100644
index 0000000..60b9e05
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/Package.java
@@ -0,0 +1,30 @@
+package org.apache.karaf.webconsole.osgi.core.manifest;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+public class Package implements Serializable {
+
+	private String name;
+	private Map<String, String> attributes;
+
+	public Package(String name) {
+		this.name = name;
+	}
+
+
+	public void setAttributes(Map<String, String> attributes) {
+		this.attributes = attributes;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public Map<String, String> getAttributes() {
+		return attributes;
+	}
+
+}
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/navigation/OsgiConsoleTabProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
similarity index 70%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/navigation/OsgiConsoleTabProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
index 7c33906..0c59369 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/navigation/OsgiConsoleTabProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
@@ -14,13 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework.navigation;
+package org.apache.karaf.webconsole.osgi.core.navigation;
 
-import java.util.Collections;
+import static org.apache.karaf.webconsole.core.util.LinkUtils.createPageLink;
+
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
-import org.apache.karaf.webconsole.osgi.framework.internal.FrameworkPage;
+import org.apache.karaf.webconsole.osgi.core.FrameworkPage;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.karaf.webconsole.osgi.core.service.list.ServicePage;
 import org.apache.wicket.Page;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
@@ -35,7 +39,10 @@
     }
 
     public List<Link<Page>> getItems(String componentId, String labelId) {
-        return Collections.emptyList();
+        List<Link<Page>> links = new ArrayList<Link<Page>>();
+        links.add(createPageLink(componentId, labelId, "Bundles", BundlePage.class));
+        links.add(createPageLink(componentId, labelId, "Services", ServicePage.class));
+        return links;
     }
 
 }
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ClauseModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ClauseModel.java
new file mode 100644
index 0000000..7dcb7b4
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ClauseModel.java
@@ -0,0 +1,19 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.wicket.model.LoadableDetachableModel;
+
+public class ClauseModel extends LoadableDetachableModel<Clause> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ClauseModel(Clause object) {
+        super(object);
+    }
+
+    @Override
+    protected Clause load() {
+        return null;
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ExportPackageTable.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ExportPackageTable.java
new file mode 100644
index 0000000..90ae6af
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ExportPackageTable.java
@@ -0,0 +1,30 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.OrdinalColumn;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.AttributesColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.DirectivesColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.PackageColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class ExportPackageTable extends HeaderTable {
+
+	@SuppressWarnings("unchecked")
+	static IColumn<Clause>[] columns = new IColumn[] {
+		new OrdinalColumn<Clause>(),
+		new PropertyColumnExt<Clause>("Package", "name"),
+		new PackageColumn("Export"),
+//		new ResolutionColumn("Resolution"),
+//		new VersionRangeColumn("Version"),
+		new AttributesColumn("Attributes"),
+		new DirectivesColumn("Directives"),
+	};
+
+	public ExportPackageTable(String id, Bundle bundle) {
+		super(id, columns, bundle, Constants.EXPORT_PACKAGE);
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderDataProvider.java
new file mode 100644
index 0000000..1f375dd
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderDataProvider.java
@@ -0,0 +1,46 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.osgi.core.manifest.ManifestUtil;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HeaderDataProvider extends SortableDataProvider<Clause> {
+
+    private static final long serialVersionUID = 1L;
+    private transient Logger logger = LoggerFactory.getLogger(getClass());
+    private transient Clause[] clauses;
+
+    public HeaderDataProvider(Bundle bundle, String header) {
+        try {
+            clauses = ManifestUtil.getHeader(bundle, header);
+        } catch (IOException e) {
+            clauses = new Clause[0];
+            logger.error("Cannot parse bundle headers", e);
+        }
+    }
+
+    public Iterator<? extends Clause> iterator(int first, int count) {
+        List<Clause> clauses = new ArrayList<Clause>();
+        clauses.addAll(Arrays.asList(this.clauses));
+        return clauses.subList(first, count).iterator();
+    }
+
+    public int size() {
+        return clauses.length;
+    }
+
+    public IModel<Clause> model(Clause object) {
+        return new ClauseModel(object);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderTable.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderTable.java
new file mode 100644
index 0000000..70de1e2
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/HeaderTable.java
@@ -0,0 +1,16 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.osgi.framework.Bundle;
+
+public class HeaderTable extends DefaultDataTable<Clause> {
+
+	private static final long serialVersionUID = 1L;
+
+	public HeaderTable(String id, IColumn<Clause>[] columns, Bundle bundle, String header) {
+		super(id, columns, new HeaderDataProvider(bundle, header), Integer.MAX_VALUE);
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ImportPackageTable.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ImportPackageTable.java
new file mode 100644
index 0000000..17cbc31
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/ImportPackageTable.java
@@ -0,0 +1,30 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.OrdinalColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.AttributesColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.DirectivesColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.PackageColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.ResolutionColumn;
+import org.apache.karaf.webconsole.osgi.core.pkg.column.VersionRangeColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+
+public class ImportPackageTable extends HeaderTable {
+
+	@SuppressWarnings("unchecked")
+	static IColumn<Clause>[] columns = new IColumn[] {
+		new OrdinalColumn<Clause>(),
+		new PackageColumn("Import"),
+		new ResolutionColumn("Resolution"),
+		new VersionRangeColumn("Version"),
+		new AttributesColumn("Attributes"),
+		new DirectivesColumn("Directives"),
+	};
+
+	public ImportPackageTable(String id, Bundle bundle) {
+		super(id, columns, bundle, Constants.IMPORT_PACKAGE);
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.java
new file mode 100644
index 0000000..4cc5194
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.java
@@ -0,0 +1,92 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import static org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage.createLink;
+
+import java.util.Arrays;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage;
+import org.apache.karaf.webconsole.osgi.core.shared.BundleModel;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.wicket.PageParameters;
+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.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.model.PropertyModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+@PaxWicketMountPoint(mountPoint = "/osgi/package/detail")
+public class PackagePage extends OsgiPage {
+
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
+
+    public PackagePage(PageParameters params) {
+        String pkg = params.getString("package");
+        String version = params.getString("version");
+
+        add(new Label("package", pkg).setRenderBodyOnly(true));
+        add(new Label("version", version).setRenderBodyOnly(true));
+
+        ExportedPackage[] packages = admin.getExportedPackages((Bundle) null);
+
+        boolean found = false;
+        Version osgiVersion = new Version(version);
+        for (ExportedPackage exportPkg : packages) {
+            if (pkg.equals(exportPkg.getName()) && osgiVersion.equals(exportPkg.getVersion())) {
+                found = true;
+                populate(exportPkg);
+                break;
+            }
+        }
+
+        if (!found) {
+            Link link = new Link("exporterLink") {
+                @Override
+                public void onClick() {
+                    // TODO Auto-generated method stub
+                    
+                }
+            };
+
+            error("Unable to find package " + pkg);
+
+            link.add(new Label("exporterLabel", "NOT FOUND"));
+            add(link);
+            add(new Label("packageDet"));
+            add(new RepeatingView("importers"));
+        }
+    }
+
+    private void populate(ExportedPackage exportPkg) {
+        Bundle exporter = exportPkg.getExportingBundle();
+        Bundle[] importers = exportPkg.getImportingBundles();
+
+        PageParameters params = new PageParameters();
+        params.put("bundleId", exporter.getBundleId());
+
+        Link<SingleBundlePage> link = createLink("exporterLink", exporter);
+        link.add(new Label("exporterLabel", new PropertyModel(new BundleModel(exporter), "symbolicName")));
+        add(link);
+
+        add(new Label("packageDet", exportPkg.getName()));
+
+        add(new ListView<Bundle>("importers", Arrays.asList(importers)) {
+            @Override
+            protected void populateItem(ListItem<Bundle> item) {
+                Bundle model = item.getModel().getObject();
+
+                Link<SingleBundlePage> link = createLink("importerLink", model);
+                link.add(new Label("importerLabel", model.getSymbolicName()));
+                item.add(link);
+            }
+        });
+
+    }
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/WicketClause.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/WicketClause.java
new file mode 100644
index 0000000..b3256ef
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/WicketClause.java
@@ -0,0 +1,15 @@
+package org.apache.karaf.webconsole.osgi.core.pkg;
+
+import java.io.Serializable;
+
+import org.apache.felix.utils.manifest.Clause;
+
+public class WicketClause extends Clause implements Serializable {
+
+	private static final long serialVersionUID = 1428726206399185187L;
+
+	public WicketClause(Clause clause) {
+		super(clause.getName(), clause.getDirectives(), clause.getAttributes());
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesColumn.java
new file mode 100644
index 0000000..6390f45
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesColumn.java
@@ -0,0 +1,20 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+
+public class AttributesColumn extends PropertyColumnExt<Clause> {
+
+	public AttributesColumn(String property) {
+		super(property);
+	}
+
+	public void populateItem(Item<ICellPopulator<Clause>> cellItem, String componentId, IModel<Clause> rowModel) {
+		cellItem.add(new AttributesPanel(componentId, rowModel));
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.java
new file mode 100644
index 0000000..a32cb19
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.java
@@ -0,0 +1,30 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import java.util.Arrays;
+
+import org.apache.felix.utils.manifest.Attribute;
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Directive;
+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.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+public class AttributesPanel extends Panel {
+
+	public AttributesPanel(String componentId, IModel<Clause> model) {
+		super(componentId, new CompoundPropertyModel<Clause>(model));
+
+		add(new ListView<Attribute>("attributes", Arrays.asList(model.getObject().getAttributes())) {
+			@Override
+			protected void populateItem(ListItem<Attribute> item) {
+				item.setModel(new CompoundPropertyModel<Attribute>(item.getModel()));
+				item.add(new Label("name"));
+				item.add(new Label("value"));
+			}
+		});
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesColumn.java
new file mode 100644
index 0000000..0cfc979
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesColumn.java
@@ -0,0 +1,20 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+
+public class DirectivesColumn extends PropertyColumnExt<Clause> {
+
+	public DirectivesColumn(String property) {
+		super(property);
+	}
+
+	public void populateItem(Item<ICellPopulator<Clause>> cellItem, String componentId, IModel<Clause> rowModel) {
+		cellItem.add(new DirectivesPanel(componentId, rowModel));
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.java
new file mode 100644
index 0000000..aeb900a
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.java
@@ -0,0 +1,29 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import java.util.Arrays;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Directive;
+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.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+public class DirectivesPanel extends Panel {
+
+	public DirectivesPanel(String componentId, IModel<Clause> model) {
+		super(componentId);
+
+		add(new ListView<Directive>("directives", Arrays.asList(model.getObject().getDirectives())) {
+			@Override
+			protected void populateItem(ListItem<Directive> item) {
+				item.setModel(new CompoundPropertyModel<Directive>(item.getModel()));
+				item.add(new Label("name"));
+				item.add(new Label("value"));
+			}
+		});
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackageColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackageColumn.java
new file mode 100644
index 0000000..394d25e
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackageColumn.java
@@ -0,0 +1,19 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+public class PackageColumn extends PropertyColumnExt<Clause> {
+
+	public PackageColumn(String property) {
+		super(property, "name");
+	}
+
+	@Override
+	public void populateItem(Item<ICellPopulator<Clause>> item, String componentId, IModel<Clause> rowModel) {
+		item.add(new PackagePanel(componentId, rowModel));
+	}
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.java
new file mode 100644
index 0000000..0e73cad
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.java
@@ -0,0 +1,50 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.osgi.core.pkg.PackagePage;
+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.BookmarkablePageLink;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class PackagePanel extends Panel {
+
+	@PaxWicketBean(name = "packageAdmin")
+	private PackageAdmin admin;
+
+	public PackagePanel(String componentId, IModel<Clause> model) {
+		super(componentId);
+
+		Clause clause = model.getObject();
+
+		PageParameters params = new PageParameters();
+		String pkg = clause.getName();
+		params.add("package", pkg);
+
+		String version = clause.getAttribute(Constants.VERSION_ATTRIBUTE);
+		if (version != null) {
+			params.add("version", version);
+		} else {
+			params.add("version", Version.emptyVersion.toString());
+		}
+
+		BookmarkablePageLink<PackagePage> link = new BookmarkablePageLink<PackagePage>("link", PackagePage.class, params);
+		link.add(new Label("label", pkg));
+
+
+		ExportedPackage exportedPackage = admin.getExportedPackage(pkg);
+		if (exportedPackage == null) {
+			link.add(new SimpleAttributeModifier("class", "error"));
+		}
+
+		add(link);
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionColumn.java
new file mode 100644
index 0000000..1d4e074
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionColumn.java
@@ -0,0 +1,20 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Constants;
+
+public class ResolutionColumn extends PropertyColumnExt<Clause> {
+
+	public ResolutionColumn(String property) {
+		super(property, property);
+	}
+
+	@Override
+	public void populateItem(Item<ICellPopulator<Clause>> item, String componentId, IModel<Clause> rowModel) {
+		item.add(new ResolutionPanel(componentId, rowModel));
+	}
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.java
new file mode 100644
index 0000000..96093ab
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.java
@@ -0,0 +1,37 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Constants;
+
+public class ResolutionPanel extends Panel {
+
+	public ResolutionPanel(String id, IModel<Clause> model) {
+		super(id);
+
+		Clause clause = model.getObject();
+
+		String resolution = clause.getDirective(Constants.RESOLUTION_DIRECTIVE);
+		if (resolution == null) {
+			resolution = Constants.RESOLUTION_MANDATORY;
+		}
+
+		String css = "icon-question-sign"; // unknown resolution
+		if (Constants.RESOLUTION_MANDATORY.equals(resolution)) {
+			css = "icon-lock";
+		} else if (Constants.RESOLUTION_OPTIONAL.equals(resolution)) {
+			css = "icon-adjust";
+		}
+
+		add(new Label("resolution", resolution).setRenderBodyOnly(true));
+		Label icon = new Label("icon");
+		icon.add(new SimpleAttributeModifier("class", css));
+		add(icon);
+
+		add(new SimpleAttributeModifier("title", "Resolution is " + resolution));
+	}
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionColumn.java
new file mode 100644
index 0000000..81c36a8
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionColumn.java
@@ -0,0 +1,5 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+public class VersionColumn {
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionRangeColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionRangeColumn.java
new file mode 100644
index 0000000..3514fff
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/column/VersionRangeColumn.java
@@ -0,0 +1,22 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.column;
+
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Constants;
+
+public class VersionRangeColumn extends PropertyColumnExt<Clause> {
+
+	public VersionRangeColumn(String property) {
+		super(property);
+	}
+
+	@Override
+	public void populateItem(Item<ICellPopulator<Clause>> item, String componentId, IModel<Clause> rowModel) {
+		String version = rowModel.getObject().getAttribute(Constants.VERSION_ATTRIBUTE);
+		item.add(new Label(componentId, version));
+	}
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ServiceDetailPage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ServiceDetailPage.java
new file mode 100644
index 0000000..e3e9492
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ServiceDetailPage.java
@@ -0,0 +1,5 @@
+package org.apache.karaf.webconsole.osgi.core.service;
+
+public class ServiceDetailPage {
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.java
new file mode 100644
index 0000000..249ea47
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.java
@@ -0,0 +1,60 @@
+/*
+ * 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.karaf.webconsole.osgi.core.service.list;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.ServiceDataProvider;
+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.model.IModel;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service list page.
+ */
+@PaxWicketMountPoint(mountPoint = "/osgi/service")
+public class ServicePage extends OsgiPage {
+
+    public ServicePage() {
+        List<IColumn<ServiceReference>> columns = new ArrayList<IColumn<ServiceReference>>();
+        columns.add(new PropertyColumnExt<ServiceReference>("Service Id") {
+            @Override
+            protected IModel<?> createLabelModel(IModel<ServiceReference> rowModel) {
+                return Model.of((Long) rowModel.getObject().getProperty(Constants.SERVICE_ID));
+            }
+        });
+
+        columns.add(new PropertyColumnExt<ServiceReference>("Interfaces") {
+            @Override
+            protected IModel<?> createLabelModel(IModel<ServiceReference> rowModel) {
+                return Model.of(Arrays.toString((String[]) rowModel.getObject().getProperty(Constants.OBJECTCLASS)));
+            }
+        });
+        columns.add(new PropertyColumnExt<ServiceReference>("Exporter", "bundle.symbolicName"));
+
+        add(new DefaultDataTable<ServiceReference>("services", columns, new ServiceDataProvider(context, (String) null), 100));
+    }
+
+}
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleDataProvider.java
similarity index 83%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesDataProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleDataProvider.java
index 5898236..f0bdcbd 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesDataProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleDataProvider.java
@@ -14,23 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle.internal;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.karaf.webconsole.osgi.framework.BundleModel;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
 import org.apache.wicket.model.IModel;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
-public class BundlesDataProvider extends SortableDataProvider<Bundle> {
+/**
+ * Data provider to which lists all installed bundles.
+ */
+public class BundleDataProvider extends SortableDataProvider<Bundle> {
 
+    private static final long serialVersionUID = 1L;
     private BundleContext context;
 
-    public BundlesDataProvider(BundleContext context) {
+    public BundleDataProvider(BundleContext context) {
         this.context = context;
     }
 
@@ -48,6 +51,4 @@
         return context.getBundles().length;
     }
 
-
-
 }
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/BundleModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleModel.java
similarity index 86%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/BundleModel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleModel.java
index 27c6871..a9ce91b 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/BundleModel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/BundleModel.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
 import org.apache.wicket.model.LoadableDetachableModel;
 import org.osgi.framework.Bundle;
@@ -25,6 +25,8 @@
  */
 public class BundleModel extends LoadableDetachableModel<Bundle> {
 
+    private static final long serialVersionUID = 1L;
+
     private BundleContext context;
     private long bundleId;
 
@@ -33,6 +35,10 @@
         this.context = context;
         bundleId = bundle.getBundleId();
     }
+    
+    public BundleModel(Bundle bundle) {
+        this(bundle.getBundleContext(), bundle);
+    }
 
     @Override
     protected Bundle load() {
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/MissingServiceReferenceException.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/MissingServiceReferenceException.java
similarity index 80%
rename from osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/MissingServiceReferenceException.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/MissingServiceReferenceException.java
index 8e9c593..982507d 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/MissingServiceReferenceException.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/MissingServiceReferenceException.java
@@ -14,14 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.blueprint.model;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
-import java.util.Arrays;
-
+/**
+ * Exception thrown when service is no longer available.
+ */
 public class MissingServiceReferenceException extends RuntimeException {
 
-    public MissingServiceReferenceException(String symbolicName, String[] classes) {
-        super("Bundle " + symbolicName + " doesn't register any service with classes " + Arrays.toString(classes));
+    public MissingServiceReferenceException(String symbolicName, Long serviceId) {
+        super("Bundle " + symbolicName + " doesn't register service with id " + serviceId);
     }
 
 }
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/OsgiPage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/OsgiPage.java
similarity index 78%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/OsgiPage.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/OsgiPage.java
index ef551aa..11a0a4d 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/OsgiPage.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/OsgiPage.java
@@ -14,25 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
-import org.apache.karaf.webconsole.core.page.SecuredPage;
+import org.apache.karaf.webconsole.core.page.SinglePage;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
 import org.osgi.framework.BundleContext;
 
 /**
  * Base page class for extensions which use {@link BundleContext}.
  */
-public abstract class OsgiPage extends SecuredPage {
-
-    //@PaxWicketBean(name = "osgiSidebar")
-    //private SidebarProvider provider;
+public abstract class OsgiPage extends SinglePage {
 
     @PaxWicketBean(name = "blueprintBundleContext")
     protected BundleContext context;
 
     protected OsgiPage() {
-        //setSidebarProvider(provider);
     }
 
 }
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceDataProvider.java
new file mode 100644
index 0000000..f0d4eb3
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceDataProvider.java
@@ -0,0 +1,81 @@
+package org.apache.karaf.webconsole.osgi.core.shared;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * OSGi service registry data provider. Scans registry for services matching
+ * given criteria.
+ * <strong>The service list might be outdated before model is used!</strong>
+ */
+public class ServiceDataProvider extends SortableDataProvider<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    private transient List<ServiceReference> services;
+
+    private BundleContext context;
+
+    private final String clazz;
+
+    private final String filter;
+
+    /**
+     * Base constructor.
+     * 
+     * @param context Bundle context.
+     * @param clazz Class name.
+     * @param filter Filter to apply.
+     */
+    public ServiceDataProvider(BundleContext context, String clazz, String filter) {
+        this.context = context;
+        this.clazz = clazz;
+        this.filter = filter;
+    }
+
+    private List<ServiceReference> getServices() {
+        if (services == null) {
+            try {
+                ServiceReference[] references = context.getServiceReferences(clazz, filter);
+                this.services = references != null ? Arrays.asList(references) : new ArrayList<ServiceReference>();
+            } catch (InvalidSyntaxException e) {
+                throw new RuntimeException("Unable to list services", e);
+            }
+        }
+        return services;
+    }
+
+    public ServiceDataProvider(BundleContext context, String clazz) {
+        this(context, clazz, "(objectClass=*)");
+    }
+
+    public ServiceDataProvider(BundleContext context, Class<?> clazz, String filter) {
+        this(context, clazz.getName(), filter);
+    }
+
+    public ServiceDataProvider(BundleContext context, Class<?> clazz) {
+        this(context, clazz.getName());
+    }
+
+    // provide methods
+    public Iterator<? extends ServiceReference> iterator(int first, int count) {
+        return getServices().subList(first, count).iterator();
+    }
+
+    public IModel<ServiceReference> model(ServiceReference object) {
+        return new ServiceReferenceModel(object);
+    }
+
+    public int size() {
+        return getServices().size();
+    }
+
+}
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/ServiceReferenceModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceReferenceModel.java
similarity index 79%
rename from osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/ServiceReferenceModel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceReferenceModel.java
index c6448ff..096b32b 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/model/ServiceReferenceModel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/ServiceReferenceModel.java
@@ -14,16 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.blueprint.model;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
 import org.apache.wicket.model.LoadableDetachableModel;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
+/**
+ * Model to keep service references.
+ */
 public class ServiceReferenceModel extends LoadableDetachableModel<ServiceReference> {
 
+    private static final long serialVersionUID = 1L;
+
     private final Bundle bundle;
-    private String[] classes;
+    private Long serviceId;
 
     public ServiceReferenceModel(ServiceReference object) {
         this(object, object.getBundle());
@@ -31,7 +37,7 @@
 
     public ServiceReferenceModel(ServiceReference object, Bundle bundle) {
         this.bundle = bundle;
-        classes = (String[]) object.getProperty("objectClass");
+        serviceId = (Long) object.getProperty(Constants.SERVICE_ID);
     }
 
     @Override
@@ -39,12 +45,12 @@
         ServiceReference[] services = bundle.getRegisteredServices();
 
         for (ServiceReference reference : services) {
-            if (classes.equals(reference.getProperty("objectClass"))) {
+            if (serviceId.equals(reference.getProperty(Constants.SERVICE_ID))) {
                 return reference;
             }
         }
 
-        throw new MissingServiceReferenceException(bundle.getSymbolicName(), classes);
+        throw new MissingServiceReferenceException(bundle.getSymbolicName(), serviceId);
     }
 
 }
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/State.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java
similarity index 72%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/State.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java
index a027e4e..34e8c5f 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/internal/State.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java
@@ -1,4 +1,6 @@
-package org.apache.karaf.webconsole.osgi.bundle.internal;
+package org.apache.karaf.webconsole.osgi.core.shared;
+
+import org.osgi.framework.Bundle;
 
 public enum State {
     UNINSTALLED(1),
@@ -25,5 +27,9 @@
         }
         return UNKNOWN;
     }
-    
+
+    public static State of(Bundle bundle) {
+        return of(bundle.getState());
+    }
+
 }
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/SystemBundleModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/SystemBundleModel.java
similarity index 90%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/SystemBundleModel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/SystemBundleModel.java
index 1083851..1502d2e 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/SystemBundleModel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/SystemBundleModel.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework;
+package org.apache.karaf.webconsole.osgi.core.shared;
 
 import org.osgi.framework.BundleContext;
 
@@ -23,6 +23,8 @@
  */
 public class SystemBundleModel extends BundleModel {
 
+    private static final long serialVersionUID = 1L;
+
     public SystemBundleModel(BundleContext context) {
         super(context, context.getBundle(0));
     }
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IActionProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IActionProvider.java
similarity index 94%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IActionProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IActionProvider.java
index e9674ee..694b940 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IActionProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IActionProvider.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle;
+package org.apache.karaf.webconsole.osgi.core.spi;
 
 import org.apache.wicket.Component;
 import org.osgi.framework.Bundle;
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IColumnProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IColumnProvider.java
similarity index 94%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IColumnProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IColumnProvider.java
index 100f09f..f8ef2f1 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IColumnProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IColumnProvider.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle;
+package org.apache.karaf.webconsole.osgi.core.spi;
 
 import java.io.Serializable;
 
diff --git a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IDecorationProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IDecorationProvider.java
similarity index 95%
rename from osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IDecorationProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IDecorationProvider.java
index 1e93552..2709b6f 100644
--- a/osgi/bundle/src/main/java/org/apache/karaf/webconsole/osgi/bundle/IDecorationProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/spi/IDecorationProvider.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.bundle;
+package org.apache.karaf.webconsole.osgi.core.spi;
 
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetPanel.java
similarity index 88%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetPanel.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetPanel.java
index 11794b7..2ab444e 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetPanel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetPanel.java
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework.internal;
+package org.apache.karaf.webconsole.osgi.core.widget;
 
-import org.apache.karaf.webconsole.osgi.framework.SystemBundleModel;
+import org.apache.karaf.webconsole.osgi.core.shared.SystemBundleModel;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.CompoundPropertyModel;
@@ -28,6 +28,8 @@
  */
 public class OsgiWidgetPanel extends Panel {
 
+    private static final long serialVersionUID = 1L;
+
     public OsgiWidgetPanel(String id, BundleContext context) {
         super(id, new CompoundPropertyModel<Bundle>(new SystemBundleModel(context)));
 
diff --git a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetProvider.java
similarity index 95%
rename from osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetProvider.java
rename to osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetProvider.java
index 02a51eb..57b1efd 100644
--- a/osgi/framework/src/main/java/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetProvider.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.karaf.webconsole.osgi.framework.internal;
+package org.apache.karaf.webconsole.osgi.core.widget;
 
 import org.apache.karaf.webconsole.core.widget.WidgetProvider;
 import org.apache.wicket.markup.html.panel.Panel;
diff --git a/osgi/framework/src/main/resources/OSGI-INF/blueprint/framework.xml b/osgi/core/src/main/resources/OSGI-INF/blueprint/framework.xml
similarity index 60%
rename from osgi/framework/src/main/resources/OSGI-INF/blueprint/framework.xml
rename to osgi/core/src/main/resources/OSGI-INF/blueprint/framework.xml
index 6371d3c..ed1e480 100644
--- a/osgi/framework/src/main/resources/OSGI-INF/blueprint/framework.xml
+++ b/osgi/core/src/main/resources/OSGI-INF/blueprint/framework.xml
@@ -17,10 +17,17 @@
 -->
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
 
+    <reference id="startLevel" interface="org.osgi.service.startlevel.StartLevel" />
+    <reference id="packageAdmin" interface="org.osgi.service.packageadmin.PackageAdmin" />
+
+    <reference-list id="columnProviders" interface="org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider" availability="optional" />
+    <reference-list id="actionProviders" interface="org.apache.karaf.webconsole.osgi.core.spi.IActionProvider" availability="optional" />
+    <reference-list id="decorationProviders" interface="org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider" availability="optional" />
+
     <service interface="org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider">
         <bean class="org.apache.karaf.webconsole.core.navigation.ExtendableConsoleTabProvider">
             <argument>
-                <bean class="org.apache.karaf.webconsole.osgi.framework.navigation.OsgiConsoleTabProvider" />
+                <bean class="org.apache.karaf.webconsole.osgi.core.navigation.OsgiConsoleTabProvider" />
             </argument>
             <property name="extensions">
                 <reference-list interface="org.apache.karaf.webconsole.core.navigation.NavigationProvider"
@@ -29,8 +36,16 @@
         </bean>
     </service>
 
-    <bean id="widgetProvider" class="org.apache.karaf.webconsole.osgi.framework.internal.OsgiWidgetProvider">
+    <bean id="widgetProvider" class="org.apache.karaf.webconsole.osgi.core.widget.OsgiWidgetProvider">
         <argument ref="blueprintBundleContext" />
     </bean>
 
-</blueprint>
+    <service auto-export="interfaces" ref="widgetProvider" />
+
+    <service auto-export="interfaces">
+        <bean class="org.apache.karaf.webconsole.osgi.core.bundle.list.SystemBundleDecorationProvider">
+            <argument ref="startLevel" />
+        </bean>
+    </service>
+
+</blueprint>
\ No newline at end of file
diff --git a/osgi/framework/src/main/resources/org/apache/karaf/webconsole/osgi/framework/internal/FrameworkPage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/FrameworkPage.html
similarity index 100%
rename from osgi/framework/src/main/resources/org/apache/karaf/webconsole/osgi/framework/internal/FrameworkPage.html
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/FrameworkPage.html
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.html
new file mode 100644
index 0000000..6a63259
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/SingleBundlePage.html
@@ -0,0 +1,58 @@
+<?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.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <h1><span wicket:id="name">symbolic name</span> <small>details</small></h1>
+
+    <ul class="nav nav-pills">
+        <li class="active">
+            <a href="#imports" data-toggle="tab">Imports</a>
+        </li>
+        <li>
+            <a href="#exports" data-toggle="tab">Exports</a>
+        </li>
+        <li>
+            <a href="#servicesIn" data-toggle="tab">Services in use</a>
+        </li>
+        <li>
+            <a href="#servicesOut" data-toggle="tab">Services provided</a>
+        </li>
+    </ul>
+
+    <div class="tab-content">
+        <div class="tab-pane active" id="imports">
+            <h2>Imports</h2>
+            <table wicket:id="imports" class="table table-stripped table-bordered"></table>
+        </div>
+
+        <div class="tab-pane" id="exports">
+            <h3>Exports</h3>
+            <table wicket:id="exports" class="table table-stripped table-bordered"></table>
+        </div>
+
+        <div class="tab-pane" id="servicesIn">
+            <h3>Services in use</h3>
+<!--             <div wicket:id="servicesIn"></div> -->
+        </div>
+
+        <div class="tab-pane" id="servicesOut">
+            <h3>Services provided by bundle</h3>
+<!--             <div wicket:id="servicesOut"></div> -->
+        </div>
+    </div>
+
+</wicket:extend>
\ No newline at end of file
diff --git a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesPage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html
similarity index 100%
rename from osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/BundlesPage.html
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html
diff --git a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/DecorationPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.html
similarity index 100%
rename from osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/DecorationPanel.html
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.html
diff --git a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/decoration.css b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css
similarity index 100%
rename from osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/decoration.css
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css
diff --git a/osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/system.gif b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/system.gif
similarity index 100%
rename from osgi/bundle/src/main/resources/org/apache/karaf/webconsole/osgi/bundle/internal/view/system.gif
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/system.gif
Binary files differ
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.html
new file mode 100644
index 0000000..66692c1
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.html
@@ -0,0 +1,43 @@
+<?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.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <h1><span wicket:id="package"></span> <small><span wicket:id="version"></span> details</small></h1>
+
+    <div class="row-fluid">
+        <div class="span4">
+            <h2>Exporter</h2>
+            <a wicket:id="exporterLink">
+                <span wicket:id="exporterLabel"></span>
+            </a>
+        </div>
+        <div class="span4">
+            <h2>Package</h2>
+            <span wicket:id="packageDet"></span>
+        </div>
+        <div class="span4">
+            <h2>Importer</h2>
+            <ul>
+                <li wicket:id="importers">
+                    <a wicket:id="importerLink">
+                        <span wicket:id="importerLabel"></span>
+                    </a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</wicket:extend>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.html
new file mode 100644
index 0000000..152235a
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/AttributesPanel.html
@@ -0,0 +1,25 @@
+<?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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <ul>
+        <li wicket:id="attributes">
+            <span wicket:id="name"></span>
+            <span wicket:id="value"></span>
+        </li>
+    </ul>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.html
new file mode 100644
index 0000000..dfaa572
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/DirectivesPanel.html
@@ -0,0 +1,25 @@
+<?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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <ul>
+        <li wicket:id="directives">
+            <span wicket:id="name"></span>
+            <span wicket:id="value"></span>
+        </li>
+    </ul>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.html
new file mode 100644
index 0000000..4c36aea
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/PackagePanel.html
@@ -0,0 +1,22 @@
+<?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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <a href="#" wicket:id="link">
+        <span wicket:id="label"></span>
+    </a>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.html
new file mode 100644
index 0000000..11a3ace
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/column/ResolutionPanel.html
@@ -0,0 +1,23 @@
+<?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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <span>
+        <i wicket:id="icon" class="icon"></i>
+        <span wicket:id="resolution"></span>
+    </span>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.html
new file mode 100644
index 0000000..96cb526
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/list/ServicePage.html
@@ -0,0 +1,23 @@
+<?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.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <h1>Services</h1>
+
+    <table wicket:id="services" class="table table-striped table-condensed" />
+
+</wicket:extend>
diff --git a/osgi/framework/src/main/resources/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetPanel.html
similarity index 100%
rename from osgi/framework/src/main/resources/org/apache/karaf/webconsole/osgi/framework/internal/OsgiWidgetPanel.html
rename to osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/widget/OsgiWidgetPanel.html
diff --git a/osgi/event/pom.xml b/osgi/event/pom.xml
index 60f5366..e6db382 100644
--- a/osgi/event/pom.xml
+++ b/osgi/event/pom.xml
@@ -33,7 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
+            <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/osgi/event/src/main/java/org/apache/karaf/webconsole/osgi/event/EventsPage.java b/osgi/event/src/main/java/org/apache/karaf/webconsole/osgi/event/EventsPage.java
index 3b1ffbc..8114fed 100644
--- a/osgi/event/src/main/java/org/apache/karaf/webconsole/osgi/event/EventsPage.java
+++ b/osgi/event/src/main/java/org/apache/karaf/webconsole/osgi/event/EventsPage.java
@@ -21,9 +21,9 @@
 
 import org.apache.karaf.webconsole.core.table.OrdinalColumn;
 import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.karaf.webconsole.osgi.event.model.EventTopicInfo;
 import org.apache.karaf.webconsole.osgi.event.model.EventTopicsProvider;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
diff --git a/osgi/framework/NOTICE b/osgi/framework/NOTICE
deleted file mode 100644
index 5a8c619..0000000
--- a/osgi/framework/NOTICE
+++ /dev/null
@@ -1,33 +0,0 @@
-Apache Karaf Webconsole
-Copyright 2011 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 written by
-Antony Lesuisse.
-Licensed under Public Domain.
-
-
-II. Used Software
-
-This product uses software developed at
-The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2010).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-OPS4J (http://www.ops4j.org/).
-Licensed under the Apache License 2.0.
-
-This product uses software developed at
-SLF4J (http://www.slf4j.org/).
-Licensed under the MIT License.
-
-III. License Summary
-- Apache License 2.0
-
diff --git a/osgi/log/pom.xml b/osgi/log/pom.xml
index e6420cf..2080df0 100644
--- a/osgi/log/pom.xml
+++ b/osgi/log/pom.xml
@@ -33,7 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
+            <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntriesDataProvider.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntriesDataProvider.java
index 34ab809..755e85e 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntriesDataProvider.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntriesDataProvider.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import java.util.Enumeration;
@@ -11,8 +27,13 @@
 import org.osgi.service.log.LogEntry;
 import org.osgi.service.log.LogReaderService;
 
+/**
+ * Data provider for log table.
+ */
 final class LogEntriesDataProvider extends SortableDataProvider<LogEntry> {
 
+    private static final long serialVersionUID = 1L;
+
     private LogReaderService logReader;
 
     private List<LogEntry> entries;
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntryModel.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntryModel.java
index 7842813..aee48fc 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntryModel.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogEntryModel.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import java.util.Collections;
@@ -7,8 +23,13 @@
 import org.osgi.service.log.LogEntry;
 import org.osgi.service.log.LogReaderService;
 
+/**
+ * Singular log entry model, for table rows.
+ */
 public class LogEntryModel extends LoadableDetachableModel<LogEntry> {
 
+    private static final long serialVersionUID = 1L;
+
     private int hashCode;
     private LogReaderService logReader;
 
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogNavigationProvider.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogNavigationProvider.java
index 89dc353..33d37fc 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogNavigationProvider.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogNavigationProvider.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import static org.apache.karaf.webconsole.core.util.LinkUtils.createPageLink;
@@ -9,6 +25,9 @@
 import org.apache.wicket.Page;
 import org.apache.wicket.markup.html.link.Link;
 
+/**
+ * Log navigation provider.
+ */
 public class LogNavigationProvider implements NavigationProvider {
 
     public List<Link<Page>> getItems(String componentId, String labelId) {
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogsPage.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogsPage.java
index 3132bbc..32af587 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogsPage.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/LogsPage.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import java.text.DateFormat;
@@ -6,7 +22,7 @@
 import java.util.List;
 
 import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
-import org.apache.karaf.webconsole.osgi.framework.OsgiPage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.karaf.webconsole.osgi.log.search.BundleMatcher;
 import org.apache.karaf.webconsole.osgi.log.search.DateFromMatcher;
 import org.apache.karaf.webconsole.osgi.log.search.DateToMatcher;
@@ -28,6 +44,9 @@
 import org.osgi.service.log.LogEntry;
 import org.osgi.service.log.LogReaderService;
 
+/**
+ * Page with log table and search form.
+ */
 @PaxWicketMountPoint(mountPoint = "/osgi/log")
 public class LogsPage extends OsgiPage {
 
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Options.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Options.java
index 5ac3471..f4c0943 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Options.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Options.java
@@ -1,9 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.karaf.webconsole.osgi.log;
 
 import java.io.Serializable;
 
+/**
+ * Options POJO, used to configure data provider for logs table.
+ */
 public class Options implements Serializable {
 
+    private static final long serialVersionUID = 1L;
+
     private Priority priority = Priority.Any;
 
     private String bundleNameFragment;
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/OptionsForm.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/OptionsForm.java
index ec95c75..3957bf5 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/OptionsForm.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/OptionsForm.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import java.util.Arrays;
@@ -12,8 +28,13 @@
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 
+/**
+ * Search configuration form.
+ */
 public class OptionsForm extends Form<Options> {
 
+    private static final long serialVersionUID = 1L;
+
     public OptionsForm(String id, CompoundPropertyModel<Options> model) {
         super(id, model);
 
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Priority.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Priority.java
index db662a2..be60df2 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Priority.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/Priority.java
@@ -1,3 +1,19 @@
+/*
+ * 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.karaf.webconsole.osgi.log;
 
 import static org.osgi.service.log.LogService.LOG_DEBUG;
@@ -7,7 +23,9 @@
 
 import org.osgi.service.log.LogEntry;
 
-
+/**
+ * Log priority mapping.
+ */
 public enum Priority {
 
     Error(LOG_ERROR),
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/BundleMatcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/BundleMatcher.java
index 7ab470e..23fab0c 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/BundleMatcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/BundleMatcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Bundle name log entry matcher.
+ */
 public class BundleMatcher implements Matcher {
 
     public boolean matches(LogEntry entry, Options options) {
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateFromMatcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateFromMatcher.java
index db226df..c954864 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateFromMatcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateFromMatcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Log entry date matcher.
+ */
 public class DateFromMatcher implements Matcher {
 
     public boolean matches(LogEntry entry, Options options) {
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateToMatcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateToMatcher.java
index 77f4f8d..06bfdab 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateToMatcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/DateToMatcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Log entry date matcher.
+ */
 public class DateToMatcher implements Matcher {
 
     public boolean matches(LogEntry entry, Options options) {
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/Matcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/Matcher.java
index dfdb760..18967bf 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/Matcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/Matcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Generic interface for log entry matchers.
+ */
 public interface Matcher {
 
     boolean matches(LogEntry entry, Options options);
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/MessageMatcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/MessageMatcher.java
index 02a6084..0c940f3 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/MessageMatcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/MessageMatcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Log entry message matcher.
+ */
 public class MessageMatcher implements Matcher {
 
     public boolean matches(LogEntry entry, Options options) {
diff --git a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/PriorityMatcher.java b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/PriorityMatcher.java
index 592bbb1..3adeed6 100644
--- a/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/PriorityMatcher.java
+++ b/osgi/log/src/main/java/org/apache/karaf/webconsole/osgi/log/search/PriorityMatcher.java
@@ -1,8 +1,27 @@
+/*
+ * 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.karaf.webconsole.osgi.log.search;
 
 import org.apache.karaf.webconsole.osgi.log.Options;
 import org.osgi.service.log.LogEntry;
 
+/**
+ * Log entry priority matcher.
+ */
 public class PriorityMatcher implements Matcher {
 
     public boolean matches(LogEntry entry, Options options) {
diff --git a/osgi/pom.xml b/osgi/pom.xml
index 5ac99ea..8734761 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -31,11 +31,10 @@
     <packaging>pom</packaging>
 
     <modules>
-        <module>bundle</module>
         <module>log</module>
         <module>event</module>
         <module>config</module>
-        <module>framework</module>
+        <module>core</module>
         <module>blueprint</module>
         <module>scr</module>
     </modules>
@@ -44,7 +43,7 @@
         <dependencies>
             <dependency>
                 <groupId>org.apache.karaf.webconsole.osgi</groupId>
-                <artifactId>org.apache.karaf.webconsole.osgi.framework</artifactId>
+                <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
                 <version>${project.version}</version>
             </dependency>
         </dependencies>
diff --git a/osgi/scr/pom.xml b/osgi/scr/pom.xml
index 0a292e9..1fd737c 100644
--- a/osgi/scr/pom.xml
+++ b/osgi/scr/pom.xml
@@ -33,8 +33,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.karaf.webconsole.osgi</groupId>
-            <artifactId>org.apache.karaf.webconsole.osgi.bundle</artifactId>
-            <version>${project.version}</version>
+            <artifactId>org.apache.karaf.webconsole.osgi.core</artifactId>
         </dependency>
 
         <dependency>
diff --git a/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrColumnProvider.java b/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrColumnProvider.java
index 366202c..3624d26 100644
--- a/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrColumnProvider.java
+++ b/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrColumnProvider.java
@@ -16,7 +16,7 @@
  */
 package org.apache.karaf.webconsole.osgi.scr;
 
-import org.apache.karaf.webconsole.osgi.bundle.IColumnProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.osgi.framework.Bundle;
 
@@ -25,6 +25,8 @@
  */
 public class ScrColumnProvider extends ScrComponent implements IColumnProvider {
 
+    private static final long serialVersionUID = 1L;
+
     public IColumn<Bundle> getColumn() {
         return new ScrColumn(scr, "SCR");
     }
diff --git a/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrDecorationProvider.java b/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrDecorationProvider.java
index 7b1b28d..01bd89d 100644
--- a/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrDecorationProvider.java
+++ b/osgi/scr/src/main/java/org/apache/karaf/webconsole/osgi/scr/ScrDecorationProvider.java
@@ -20,7 +20,7 @@
 import static org.apache.wicket.markup.html.CSSPackageResource.getHeaderContribution;
 
 import org.apache.karaf.webconsole.core.panel.CssImagePanel;
-import org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider;
+import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.osgi.framework.Bundle;
diff --git a/osgi/scr/src/main/resources/OSGI-INF/column.xml b/osgi/scr/src/main/resources/OSGI-INF/column.xml
index 1a57cbf..d9f006d 100644
--- a/osgi/scr/src/main/resources/OSGI-INF/column.xml
+++ b/osgi/scr/src/main/resources/OSGI-INF/column.xml
@@ -19,7 +19,7 @@
    <implementation class="org.apache.karaf.webconsole.osgi.scr.ScrColumnProvider"/>
 
    <service>
-      <provide interface="org.apache.karaf.webconsole.osgi.bundle.IColumnProvider"/>
+      <provide interface="org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider"/>
    </service>
 
    <reference name="ScrService" cardinality="1..1" interface="org.apache.felix.scr.ScrService" policy="static" bind="bind" unbind="unbind" />
diff --git a/osgi/scr/src/main/resources/OSGI-INF/decoration.xml b/osgi/scr/src/main/resources/OSGI-INF/decoration.xml
index 9655adb..b60a1bd 100644
--- a/osgi/scr/src/main/resources/OSGI-INF/decoration.xml
+++ b/osgi/scr/src/main/resources/OSGI-INF/decoration.xml
@@ -19,7 +19,7 @@
    <implementation class="org.apache.karaf.webconsole.osgi.scr.ScrDecorationProvider" />
 
    <service>
-      <provide interface="org.apache.karaf.webconsole.osgi.bundle.IDecorationProvider"/>
+      <provide interface="org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider"/>
    </service>
 
    <reference name="ScrService" cardinality="1..1" interface="org.apache.felix.scr.ScrService" policy="static" bind="bind" unbind="unbind" />