Packages page, services page. Other small improvements in submodules.

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1291139 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/MetadataModel.java b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/MetadataModel.java
index f09c386..0306934 100644
--- a/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/MetadataModel.java
+++ b/osgi/blueprint/src/main/java/org/apache/karaf/webconsole/osgi/blueprint/details/MetadataModel.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.blueprint.details;
 
 import java.util.ArrayList;
@@ -12,6 +28,8 @@
 
 class MetadataModel extends LoadableDetachableModel<List<ComponentMetadata>> {
 
+    private static final long serialVersionUID = 1L;
+
     private int bundleId;
     private BundleContext context;
     private ServiceReference reference;
diff --git a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/bundle/decorator.css b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/bundle/decorator.css
index 2c3aa0e..07bd67e 100644
--- a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/bundle/decorator.css
+++ b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/bundle/decorator.css
@@ -1,3 +1,20 @@
+/*
+ * 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 {
     background: url("blueprint.gif");
     width: 16px;
diff --git a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/details/details.js b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/details/details.js
index ceba160..6a34b56 100644
--- a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/details/details.js
+++ b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/details/details.js
@@ -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.
+ */
 $(function() {
   var graph = new Graph();
   $("tr.component").each(function(key, value) {
diff --git a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/navigation.css b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/navigation.css
index 4534415..a09470d 100644
--- a/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/navigation.css
+++ b/osgi/blueprint/src/main/resources/org/apache/karaf/webconsole/osgi/blueprint/navigation.css
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
 .navbar span.blueprint {
     padding-left: 16px;
     background: url("bundle/blueprint.gif") no-repeat;
diff --git a/osgi/config/src/main/resources/org/apache/karaf/webconsole/osgi/config/configurations.css b/osgi/config/src/main/resources/org/apache/karaf/webconsole/osgi/config/configurations.css
index e4a6d63..70463cf 100644
--- a/osgi/config/src/main/resources/org/apache/karaf/webconsole/osgi/config/configurations.css
+++ b/osgi/config/src/main/resources/org/apache/karaf/webconsole/osgi/config/configurations.css
@@ -1,6 +1,19 @@
-a.remove {
-    color: red;
-}
+/*
+ * 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.
+ */
 
 .factory {
     font-weight: bolder;
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.java
new file mode 100644
index 0000000..3cba6f9
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle;
+
+import org.apache.karaf.webconsole.osgi.core.shared.State;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+import org.osgi.framework.Bundle;
+
+public class BundlePanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    public BundlePanel(String id, IModel<Bundle> model) {
+        this(id, model, false);
+    }
+
+    public BundlePanel(String id, IModel<Bundle> model, boolean renderLink) {
+        super(id, new CompoundPropertyModel<Bundle>(model));
+
+        Bundle bundle = model.getObject();
+        add(new Label("bundleId"));
+        add(new Label("state", State.of(bundle.getState()).toString()));
+        add(new Label("symbolicName"));
+        add(new Label("version", new PropertyModel<Bundle>(model, "version.toString")));
+        add(new Label("location"));
+
+        Link<SingleBundlePage> link = SingleBundlePage.createLink("link", bundle);
+        link.setVisible(renderLink);
+        add(link);
+    }
+
+}
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
index 233f129..bc437c2 100644
--- 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
@@ -21,10 +21,14 @@
 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.service.ExportServiceTable;
+import org.apache.karaf.webconsole.osgi.core.service.ImportServiceTable;
+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.model.CompoundPropertyModel;
 import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
 import org.osgi.framework.Bundle;
 
@@ -39,68 +43,19 @@
         bundleId = params.getLong("bundleId");
         Bundle bundle = context.getBundle(bundleId);
 
-        //ExportedPackage[] exported = admin.getExportedPackages(bundle);
+        BundleModel model = new BundleModel(bundle);
+        setDefaultModel(new CompoundPropertyModel<Bundle>(model));
+        add(new BundlePanel("bundle", model));
 
-        add(new Label("name", bundle.getSymbolicName()).setRenderBodyOnly(true));
+        add(new Label("symbolicName").setRenderBodyOnly(true));
+        add(new Label("version").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"))));
-//            }
-//        });
+        add(new ImportServiceTable("serviceImports", bundle));
+        add(new ExportServiceTable("serviceExports", bundle));
     }
 
-//    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.
      * 
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
index 22cd231..2178f06 100644
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/DecorationPanel.java
@@ -46,6 +46,8 @@
         }
 
         add(new ListView<Component>("extensions", components) {
+            private static final long serialVersionUID = 1L;
+
             @Override
             protected void populateItem(ListItem<Component> item) {
                 item.add(item.getModelObject());
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
deleted file mode 100644
index 7878824..0000000
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ExportPackage.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 3b7f65d..0000000
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/ImportPackage.java
+++ /dev/null
@@ -1,22 +0,0 @@
-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
index 9772db9..211a410 100644
--- 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
@@ -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.core.manifest;
 
 import java.io.IOException;
@@ -9,6 +25,9 @@
 import org.apache.felix.utils.manifest.Parser;
 import org.osgi.framework.Bundle;
 
+/**
+ * Utility class to work with bundle manifests.
+ */
 public abstract class ManifestUtil {
 
     public static Clause[] getHeader(Bundle bundle, String header) throws IOException {
@@ -17,8 +36,8 @@
 
     public static Clause[] getHeader(InputStream stream, String header) throws IOException {
         Manifest manifest = new Manifest(stream);
-		Attributes mainAttributes = manifest.getMainAttributes();
-		String value = mainAttributes.getValue(header);
+        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
deleted file mode 100644
index 60b9e05..0000000
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/manifest/Package.java
+++ /dev/null
@@ -1,30 +0,0 @@
-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/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
index 0c59369..a2b5523 100644
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/navigation/OsgiConsoleTabProvider.java
@@ -24,6 +24,7 @@
 import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
 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.pkg.list.PackagePage;
 import org.apache.karaf.webconsole.osgi.core.service.list.ServicePage;
 import org.apache.wicket.Page;
 import org.apache.wicket.markup.html.basic.Label;
@@ -42,6 +43,7 @@
         List<Link<Page>> links = new ArrayList<Link<Page>>();
         links.add(createPageLink(componentId, labelId, "Bundles", BundlePage.class));
         links.add(createPageLink(componentId, labelId, "Services", ServicePage.class));
+        links.add(createPageLink(componentId, labelId, "Packages", PackagePage.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
index 7dcb7b4..ef7d61f 100644
--- 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
@@ -1,18 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.karaf.webconsole.osgi.core.pkg;
 
+import java.io.IOException;
+
 import org.apache.felix.utils.manifest.Clause;
+import org.apache.karaf.webconsole.osgi.core.manifest.ManifestUtil;
 import org.apache.wicket.model.LoadableDetachableModel;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ClauseModel extends LoadableDetachableModel<Clause> {
 
     private static final long serialVersionUID = 1L;
+    private Bundle bundle;
+    private String header;
+    private String name;
 
-    public ClauseModel(Clause object) {
+    private transient Logger logger = LoggerFactory.getLogger(ClauseModel.class);
+
+    public ClauseModel(Bundle bundle, String header, Clause object) {
         super(object);
+        this.name = object.getName();
+        this.bundle = bundle;
+        this.header = header;
     }
 
     @Override
     protected Clause load() {
+        Clause[] clauses;
+        try {
+            clauses = ManifestUtil.getHeader(bundle, header);
+            for (Clause clause : clauses) {
+                if (name.equals(clause.getName())) {
+                    return clause;
+                }
+            }
+        } catch (IOException e) {
+            logger.error("Unable to load manifest", e);
+        }
         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
index 90ae6af..c602ca4 100644
--- 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
@@ -1,8 +1,23 @@
+/*
+ * 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.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;
@@ -12,10 +27,11 @@
 
 public class ExportPackageTable extends HeaderTable {
 
+	private static final long serialVersionUID = 1L;
+
 	@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"),
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
index 1f375dd..a0d9789 100644
--- 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
@@ -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.core.pkg;
 
 import java.io.IOException;
@@ -19,8 +35,13 @@
     private static final long serialVersionUID = 1L;
     private transient Logger logger = LoggerFactory.getLogger(getClass());
     private transient Clause[] clauses;
+    private final Bundle bundle;
+    private final String header;
 
     public HeaderDataProvider(Bundle bundle, String header) {
+        this.bundle = bundle;
+        this.header = header;
+
         try {
             clauses = ManifestUtil.getHeader(bundle, header);
         } catch (IOException e) {
@@ -40,7 +61,7 @@
     }
 
     public IModel<Clause> model(Clause object) {
-        return new ClauseModel(object);
+        return new ClauseModel(bundle, header, 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
index 70de1e2..88214ca 100644
--- 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
@@ -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.core.pkg;
 
 import org.apache.felix.utils.manifest.Clause;
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
index 17cbc31..3b7e14e 100644
--- 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
@@ -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.core.pkg;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -13,18 +29,20 @@
 
 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"),
-	};
+    private static final long serialVersionUID = 1L;
 
-	public ImportPackageTable(String id, Bundle bundle) {
-		super(id, columns, bundle, Constants.IMPORT_PACKAGE);
-	}
+    @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
deleted file mode 100644
index 4cc5194..0000000
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/PackagePage.java
+++ /dev/null
@@ -1,92 +0,0 @@
-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/SinglePackagePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/SinglePackagePage.java
new file mode 100644
index 0000000..186acd9
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/SinglePackagePage.java
@@ -0,0 +1,84 @@
+/*
+ * 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.pkg;
+
+import java.util.Arrays;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.BundlePanel;
+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.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+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 SinglePackagePage extends OsgiPage {
+
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
+
+    public SinglePackagePage(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) {
+            throw new IllegalArgumentException("Package " + pkg + " " + version + " not found");
+        }
+    }
+
+    private void populate(ExportedPackage exportPkg) {
+        Bundle exporter = exportPkg.getExportingBundle();
+        Bundle[] importers = exportPkg.getImportingBundles();
+
+        add(new BundlePanel("exporter", new BundleModel(exporter)));
+
+        add(new Label("packageDet", exportPkg.getName()));
+
+        add(new ListView<Bundle>("importers", Arrays.asList(importers)) {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(ListItem<Bundle> item) {
+                BundlePanel panel = new BundlePanel("importer", item.getModel(), true);
+                item.add(panel);
+            }
+        });
+
+    }
+}
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
deleted file mode 100644
index b3256ef..0000000
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/WicketClause.java
+++ /dev/null
@@ -1,15 +0,0 @@
-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
index 6390f45..72b8638 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -6,15 +22,16 @@
 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);
-	}
+    private static final long serialVersionUID = 1L;
 
-	public void populateItem(Item<ICellPopulator<Clause>> cellItem, String componentId, IModel<Clause> rowModel) {
-		cellItem.add(new AttributesPanel(componentId, rowModel));
-	}
+    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
index a32cb19..4a64555 100644
--- 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
@@ -1,30 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.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.WebMarkupContainer;
 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.markup.repeater.RepeatingView;
 import org.apache.wicket.model.IModel;
+import org.osgi.framework.Constants;
 
 public class AttributesPanel extends Panel {
 
-	public AttributesPanel(String componentId, IModel<Clause> model) {
-		super(componentId, new CompoundPropertyModel<Clause>(model));
+    private static final long serialVersionUID = 1L;
 
-		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"));
-			}
-		});
-	}
+    public AttributesPanel(String componentId, IModel<Clause> model) {
+        super(componentId);
+        RepeatingView repeatingView = new RepeatingView("attributes");
+
+        Attribute[] attributes = model.getObject().getAttributes();
+        for (Attribute attribute : attributes) {
+            // skip version attribute
+            if (Constants.VERSION_ATTRIBUTE.equals(attribute.getName())) {
+                continue;
+            }
+            WebMarkupContainer container = new WebMarkupContainer(repeatingView.newChildId());
+
+            container.add(new Label("name", attribute.getName()));
+            container.add(new Label("value", attribute.getValue()));
+            repeatingView.add(container);
+        }
+        add(repeatingView);
+    }
 
 }
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
index 0cfc979..8cb737a 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -6,15 +22,16 @@
 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);
-	}
+    private static final long serialVersionUID = 1L;
 
-	public void populateItem(Item<ICellPopulator<Clause>> cellItem, String componentId, IModel<Clause> rowModel) {
-		cellItem.add(new DirectivesPanel(componentId, rowModel));
-	}
+    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
index aeb900a..efd1dc3 100644
--- 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
@@ -1,29 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.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.WebMarkupContainer;
 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.markup.repeater.RepeatingView;
 import org.apache.wicket.model.IModel;
+import org.osgi.framework.Constants;
 
 public class DirectivesPanel extends Panel {
 
-	public DirectivesPanel(String componentId, IModel<Clause> model) {
-		super(componentId);
+    private static final long serialVersionUID = 1L;
 
-		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"));
-			}
-		});
-	}
+    public DirectivesPanel(String componentId, IModel<Clause> model) {
+        super(componentId);
+        RepeatingView repeatingView = new RepeatingView("directives");
+
+        Directive[] directives = model.getObject().getDirectives();
+        for (Directive directive : directives) {
+            // skip resolution directive
+            if (Constants.RESOLUTION_DIRECTIVE.equals(directive.getName())) {
+                continue;
+            }
+            WebMarkupContainer container = new WebMarkupContainer(repeatingView.newChildId());
+
+            container.add(new Label("name", directive.getName()));
+            container.add(new Label("value", directive.getValue()));
+            repeatingView.add(container);
+        }
+        add(repeatingView);
+    }
 
 }
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
index 394d25e..b600aff 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -8,12 +24,15 @@
 
 public class PackageColumn extends PropertyColumnExt<Clause> {
 
-	public PackageColumn(String property) {
-		super(property, "name");
-	}
+    private static final long serialVersionUID = 1L;
 
-	@Override
-	public void populateItem(Item<ICellPopulator<Clause>> item, String componentId, IModel<Clause> rowModel) {
-		item.add(new PackagePanel(componentId, rowModel));
-	}
+    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
index 0e73cad..7cfcde4 100644
--- 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
@@ -1,7 +1,23 @@
+/*
+ * 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.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
-import org.apache.karaf.webconsole.osgi.core.pkg.PackagePage;
+import org.apache.karaf.webconsole.osgi.core.pkg.SinglePackagePage;
 import org.apache.wicket.PageParameters;
 import org.apache.wicket.behavior.SimpleAttributeModifier;
 import org.apache.wicket.markup.html.basic.Label;
@@ -16,35 +32,37 @@
 
 public class PackagePanel extends Panel {
 
-	@PaxWicketBean(name = "packageAdmin")
-	private PackageAdmin admin;
+    private static final long serialVersionUID = 1L;
 
-	public PackagePanel(String componentId, IModel<Clause> model) {
-		super(componentId);
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
 
-		Clause clause = model.getObject();
+    public PackagePanel(String componentId, IModel<Clause> model) {
+        super(componentId);
 
-		PageParameters params = new PageParameters();
-		String pkg = clause.getName();
-		params.add("package", pkg);
+        Clause clause = model.getObject();
 
-		String version = clause.getAttribute(Constants.VERSION_ATTRIBUTE);
-		if (version != null) {
-			params.add("version", version);
-		} else {
-			params.add("version", Version.emptyVersion.toString());
-		}
+        PageParameters params = new PageParameters();
+        String pkg = clause.getName();
+        params.add("package", pkg);
 
-		BookmarkablePageLink<PackagePage> link = new BookmarkablePageLink<PackagePage>("link", PackagePage.class, params);
-		link.add(new Label("label", pkg));
+        String version = clause.getAttribute(Constants.VERSION_ATTRIBUTE);
+        if (version != null) {
+            params.add("version", version);
+        } else {
+            params.add("version", Version.emptyVersion.toString());
+        }
+
+        BookmarkablePageLink<SinglePackagePage> link = new BookmarkablePageLink<SinglePackagePage>("link", SinglePackagePage.class, params);
+        link.add(new Label("label", pkg));
 
 
-		ExportedPackage exportedPackage = admin.getExportedPackage(pkg);
-		if (exportedPackage == null) {
-			link.add(new SimpleAttributeModifier("class", "error"));
-		}
+        ExportedPackage exportedPackage = admin.getExportedPackage(pkg);
+        if (exportedPackage == null) {
+            link.add(new SimpleAttributeModifier("class", "error"));
+        }
 
-		add(link);
-	}
+        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
index 1d4e074..605a71f 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -5,16 +21,17 @@
 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);
-	}
+    private static final long serialVersionUID = 1L;
 
-	@Override
-	public void populateItem(Item<ICellPopulator<Clause>> item, String componentId, IModel<Clause> rowModel) {
-		item.add(new ResolutionPanel(componentId, rowModel));
-	}
+    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
index 96093ab..7c1e7f5 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -9,29 +25,31 @@
 
 public class ResolutionPanel extends Panel {
 
-	public ResolutionPanel(String id, IModel<Clause> model) {
-		super(id);
+    private static final long serialVersionUID = 1L;
 
-		Clause clause = model.getObject();
+    public ResolutionPanel(String id, IModel<Clause> model) {
+        super(id);
 
-		String resolution = clause.getDirective(Constants.RESOLUTION_DIRECTIVE);
-		if (resolution == null) {
-			resolution = Constants.RESOLUTION_MANDATORY;
-		}
+        Clause clause = model.getObject();
 
-		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";
-		}
+        String resolution = clause.getDirective(Constants.RESOLUTION_DIRECTIVE);
+        if (resolution == null) {
+            resolution = Constants.RESOLUTION_MANDATORY;
+        }
 
-		add(new Label("resolution", resolution).setRenderBodyOnly(true));
-		Label icon = new Label("icon");
-		icon.add(new SimpleAttributeModifier("class", css));
-		add(icon);
+        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 SimpleAttributeModifier("title", "Resolution is " + resolution));
-	}
+        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
index 81c36a8..001bd8b 100644
--- 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
@@ -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.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
index 3514fff..1ec0bdd 100644
--- 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
@@ -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.core.pkg.column;
 
 import org.apache.felix.utils.manifest.Clause;
@@ -10,13 +26,15 @@
 
 public class VersionRangeColumn extends PropertyColumnExt<Clause> {
 
-	public VersionRangeColumn(String property) {
-		super(property);
-	}
+    private static final long serialVersionUID = 1L;
 
-	@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));
-	}
+    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/pkg/list/ExportPackageModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/ExportPackageModel.java
new file mode 100644
index 0000000..1ea5aa5
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/ExportPackageModel.java
@@ -0,0 +1,37 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.list;
+
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.osgi.framework.Version;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class ExportPackageModel extends LoadableDetachableModel<ExportedPackage> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final PackageAdmin admin;
+    private String name;
+    private String version;
+
+    public ExportPackageModel(PackageAdmin admin, ExportedPackage object) {
+        super(object);
+        this.admin = admin;
+        name = object.getName();
+        version = object.getVersion().toString();
+    }
+
+    @Override
+    protected ExportedPackage load() {
+        ExportedPackage[] packages = admin.getExportedPackages(name);
+        if (packages != null) {
+            Version vers = new Version(version);
+            for (ExportedPackage pkg : packages) {
+                if (vers.equals(pkg.getVersion())) {
+                    return pkg;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackageDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackageDataProvider.java
new file mode 100644
index 0000000..171700c
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackageDataProvider.java
@@ -0,0 +1,41 @@
+package org.apache.karaf.webconsole.osgi.core.pkg.list;
+
+import java.util.ArrayList;
+import java.util.Collections;
+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.Bundle;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class PackageDataProvider extends SortableDataProvider<ExportedPackage> {
+
+    private static final long serialVersionUID = 1L;
+
+    private transient ExportedPackage[] packages;
+
+    private final PackageAdmin admin;
+
+    public PackageDataProvider(PackageAdmin admin) {
+        this.admin = admin;
+        packages = admin.getExportedPackages((Bundle) null);
+    }
+
+    public Iterator<? extends ExportedPackage> iterator(int first, int count) {
+        List<ExportedPackage> list = new ArrayList<ExportedPackage>();
+        Collections.addAll(list, packages);
+        return list.subList(first, count).iterator();
+    }
+
+    public int size() {
+        return packages.length;
+    }
+
+    public IModel<ExportedPackage> model(ExportedPackage object) {
+        return new ExportPackageModel(admin, object);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.java
new file mode 100644
index 0000000..c1c38a2
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.pkg.list;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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.wicket.PageParameters;
+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.PaxWicketBean;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+@PaxWicketMountPoint(mountPoint = "/osgi/package")
+public class PackagePage extends OsgiPage {
+
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
+
+    public PackagePage(PageParameters params) {
+        List<IColumn<ExportedPackage>> columns = new ArrayList<IColumn<ExportedPackage>>();
+        columns.add(new OrdinalColumn<ExportedPackage>());
+        columns.add(new PropertyColumnExt<ExportedPackage>("Package name", "name"));
+        columns.add(new PropertyColumnExt<ExportedPackage>("Version", "version.toString"));
+        columns.add(new PropertyColumnExt<ExportedPackage>("Provider", "exportingBundle.symbolicName"));
+        add(new DefaultDataTable<ExportedPackage>("packages", columns, new PackageDataProvider(admin), Integer.MAX_VALUE));
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceDataProvider.java
new file mode 100644
index 0000000..afde57e
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceDataProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.service;
+
+import org.apache.karaf.webconsole.osgi.core.shared.ServiceDataProvider;
+import org.osgi.framework.Bundle;
+
+public class ExportServiceDataProvider extends ServiceDataProvider {
+
+    private static final long serialVersionUID = 1L;
+
+    public ExportServiceDataProvider(Bundle bundle) {
+        super(bundle.getRegisteredServices());
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceTable.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceTable.java
new file mode 100644
index 0000000..94ccba3
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ExportServiceTable.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.karaf.webconsole.osgi.core.service.column.ObjectClassColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServiceConsumerColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServicePropertyColumn;
+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.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class ExportServiceTable extends DefaultDataTable<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static IColumn<ServiceReference>[] columns = new IColumn[] {
+        new ServicePropertyColumn("Service Id", Constants.SERVICE_ID),
+        new ObjectClassColumn(Model.of("Object classes")),
+        new ServiceConsumerColumn("Consumers"),
+    };
+
+    public ExportServiceTable(String id, Bundle bundle) {
+        super(id, columns, new ExportServiceDataProvider(bundle), Integer.MAX_VALUE);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceDataProvider.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceDataProvider.java
new file mode 100644
index 0000000..2fe33e4
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceDataProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.service;
+
+import org.apache.karaf.webconsole.osgi.core.shared.ServiceDataProvider;
+import org.osgi.framework.Bundle;
+
+public class ImportServiceDataProvider extends ServiceDataProvider {
+
+    private static final long serialVersionUID = 1L;
+
+    public ImportServiceDataProvider(Bundle bundle) {
+        super(bundle.getServicesInUse());
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceTable.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceTable.java
new file mode 100644
index 0000000..d6b30fa
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/ImportServiceTable.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import org.apache.karaf.webconsole.osgi.core.service.column.ObjectClassColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServicePropertyColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServiceProviderColumn;
+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.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class ImportServiceTable extends DefaultDataTable<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static IColumn<ServiceReference>[] columns = new IColumn[] {
+        new ServicePropertyColumn("Service Id", Constants.SERVICE_ID),
+        new ObjectClassColumn(Model.of("Object classes")),
+        new ServiceProviderColumn(Model.of("Provider")),
+    };
+
+    public ImportServiceTable(String id, Bundle bundle) {
+        super(id, columns, new ImportServiceDataProvider(bundle), Integer.MAX_VALUE);
+    }
+
+}
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
index e3e9492..f58c564 100644
--- 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
@@ -1,5 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.karaf.webconsole.osgi.core.service;
 
-public class ServiceDetailPage {
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service details page.
+ */
+public class ServiceDetailPage extends OsgiPage {
+
+    public ServiceDetailPage(PageParameters parameters) {
+        long serviceId = parameters.getLong("id");
+
+        RepeatingView repeatingView = new RepeatingView("keys");
+        add(repeatingView);
+
+        String filter = "(" + Constants.SERVICE_ID + "=" + serviceId + ")";
+        try {
+            ServiceReference[] references = context.getServiceReferences(null, filter);
+
+            if (references != null && references.length == 1) {
+                ServiceReference reference = references[0];
+
+                for(String key : reference.getPropertyKeys()) {
+                    WebMarkupContainer container = new WebMarkupContainer(repeatingView.newChildId());
+                    container.add(new Label("key", key));
+                    container.add(new Label("value", reference.getProperty(key).toString()));
+                    repeatingView.add(container);
+                }
+            }
+        } catch (InvalidSyntaxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
 
 }
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassColumn.java
new file mode 100644
index 0000000..32d8c56
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassColumn.java
@@ -0,0 +1,37 @@
+/*
+ * 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.column;
+
+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.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.ServiceReference;
+
+public class ObjectClassColumn extends AbstractColumn<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ObjectClassColumn(IModel<String> displayModel) {
+        super(displayModel);
+    }
+
+    public void populateItem(Item<ICellPopulator<ServiceReference>> cellItem, String componentId, IModel<ServiceReference> rowModel) {
+        cellItem.add(new ObjectClassPanel(componentId, rowModel));
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.java
new file mode 100644
index 0000000..37765cb
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.java
@@ -0,0 +1,56 @@
+/*
+ * 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.column;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+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.IModel;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class ObjectClassPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    public ObjectClassPanel(String id, IModel<ServiceReference> model) {
+        super(id, model);
+
+        Object property = model.getObject().getProperty(Constants.OBJECTCLASS);
+        List<String> objectClasses = new ArrayList<String>();
+        if (property instanceof String[]) {
+            Collections.addAll(objectClasses, (String[]) property);
+        } else {
+            objectClasses.add(property.toString());
+        }
+
+        add(new ListView<String>("objectClasses", objectClasses) {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(ListItem<String> item) {
+                item.add(new Label("objectClass", item.getModel()));
+            }
+        });
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerColumn.java
new file mode 100644
index 0000000..e49fa49
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerColumn.java
@@ -0,0 +1,38 @@
+/*
+ * 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.column;
+
+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.ServiceReference;
+
+public class ServiceConsumerColumn extends PropertyColumnExt<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServiceConsumerColumn(String property) {
+        super(property);
+    }
+
+    @Override
+    public void populateItem(Item<ICellPopulator<ServiceReference>> item, String componentId, IModel<ServiceReference> rowModel) {
+        item.add(new ServiceConsumerPanel(componentId, rowModel));
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerPanel.java
new file mode 100644
index 0000000..0b049ad
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerPanel.java
@@ -0,0 +1,57 @@
+/*
+ * 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.column;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage;
+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.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceConsumerPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServiceConsumerPanel(String id, IModel<ServiceReference> model) {
+        super(id, model);
+
+        List<Bundle> consumers = new ArrayList<Bundle>();
+        Bundle[] usingBundles = model.getObject().getUsingBundles();
+        if (usingBundles != null && usingBundles.length > 0) {
+            Collections.addAll(consumers, usingBundles);
+        }
+        add(new ListView<Bundle>("bundles", consumers) {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(ListItem<Bundle> item) {
+                Link<SingleBundlePage> link = SingleBundlePage.createLink("link", item.getModelObject());
+                link.add(new Label("label", item.getModelObject().getSymbolicName()));
+                item.add(link);
+            }
+        });
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServicePropertyColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServicePropertyColumn.java
new file mode 100644
index 0000000..0bfaefe
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServicePropertyColumn.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.service.column;
+
+import java.io.Serializable;
+
+import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.osgi.framework.ServiceReference;
+
+public class ServicePropertyColumn extends PropertyColumnExt<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServicePropertyColumn(String label, String property) {
+        super(label, property);
+    }
+
+    @Override
+    protected IModel<?> createLabelModel(IModel<ServiceReference> rowModel) {
+        Object property = rowModel.getObject().getProperty(getPropertyExpression());
+
+        if (property instanceof Serializable) {
+            return Model.of((Serializable) property);
+        } else {
+            return Model.of(property.toString());
+        }
+    }
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderColumn.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderColumn.java
new file mode 100644
index 0000000..2c5998e
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderColumn.java
@@ -0,0 +1,37 @@
+/*
+ * 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.column;
+
+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.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceProviderColumn extends AbstractColumn<ServiceReference> {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServiceProviderColumn(IModel<String> displayModel) {
+        super(displayModel);
+    }
+
+    public void populateItem(Item<ICellPopulator<ServiceReference>> cellItem, String componentId, IModel<ServiceReference> rowModel) {
+        cellItem.add(new ServiceProviderPanel(componentId, rowModel));
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.java
new file mode 100644
index 0000000..aebccd7
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.java
@@ -0,0 +1,40 @@
+/*
+ * 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.column;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceProviderPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    public ServiceProviderPanel(String id, IModel<ServiceReference> model) {
+        super(id);
+
+        Bundle bundle = model.getObject().getBundle();
+        Link<SingleBundlePage> link = SingleBundlePage.createLink("link", bundle);
+        link.add(new Label("label", bundle.getSymbolicName()));
+        add(link);
+    }
+
+}
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
index 249ea47..d7ccdc4 100644
--- 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
@@ -17,15 +17,16 @@
 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.service.column.ObjectClassColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServiceConsumerColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServicePropertyColumn;
+import org.apache.karaf.webconsole.osgi.core.service.column.ServiceProviderColumn;
 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;
@@ -39,22 +40,12 @@
 
     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 ServicePropertyColumn("Service Id", Constants.SERVICE_ID));
+        columns.add(new ObjectClassColumn(Model.of("Object classes")));
+        columns.add(new ServiceProviderColumn(Model.of("Provider")));
+        columns.add(new ServiceConsumerColumn("Consumers"));
 
-        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));
+        add(new DefaultDataTable<ServiceReference>("services", columns, new ServiceDataProvider(context, (String) null), Integer.MAX_VALUE));
     }
 
 }
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
index f0d4eb3..549013f 100644
--- 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
@@ -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.core.shared;
 
 import java.util.ArrayList;
@@ -20,13 +36,10 @@
 
     private static final long serialVersionUID = 1L;
 
-    private transient List<ServiceReference> services;
-
-    private BundleContext context;
-
-    private final String clazz;
-
-    private final String filter;
+    /**
+     * List of services.
+     */
+    private final transient List<ServiceReference> services;
 
     /**
      * Base constructor.
@@ -35,22 +48,25 @@
      * @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;
+    public ServiceDataProvider(ServiceReference ... services) {
+        if (services != null) {
+            this.services = Arrays.asList(services);
+        } else {
+            this.services = new ArrayList<ServiceReference>();
+        }
     }
 
-    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);
-            }
+    public ServiceDataProvider(BundleContext context, String clazz, String filter) {
+        this(retrieveServices(context, clazz, filter));
+    }
+
+    private static ServiceReference[] retrieveServices(BundleContext context, String clazz, String filter) {
+        try {
+            ServiceReference[] references = context.getServiceReferences(clazz, filter);
+            return references != null ? references : new ServiceReference[0];
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException("Unable to list services", e);
         }
-        return services;
     }
 
     public ServiceDataProvider(BundleContext context, String clazz) {
@@ -67,7 +83,7 @@
 
     // provide methods
     public Iterator<? extends ServiceReference> iterator(int first, int count) {
-        return getServices().subList(first, count).iterator();
+        return services.subList(first, count).iterator();
     }
 
     public IModel<ServiceReference> model(ServiceReference object) {
@@ -75,7 +91,7 @@
     }
 
     public int size() {
-        return getServices().size();
+        return services.size();
     }
 
 }
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java
index 34e8c5f..95c01a5 100644
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/shared/State.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.core.shared;
 
 import org.osgi.framework.Bundle;
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.html
new file mode 100644
index 0000000..a4e4cfc
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/BundlePanel.html
@@ -0,0 +1,42 @@
+<?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">
+    <table class="table table-stipped table-bordered">
+        <tr>
+            <td><wicket:message key="bundle.id" /></td>
+            <td><span wicket:id="bundleId"></span></td>
+        </tr>
+        <tr>
+            <td><wicket:message key="bundle.symbolicName" /></td>
+            <td><span wicket:id="symbolicName"></span></td>
+        </tr>
+        <tr>
+            <td><wicket:message key="bundle.state" /></td>
+            <td><span wicket:id="state"></span></td>
+        </tr>
+        <tr>
+            <td><wicket:message key="bundle.version" /></td>
+            <td><span wicket:id="version"></span></td>
+        </tr>
+        <tr>
+            <td><wicket:message key="bundle.location" /></td>
+            <td><span wicket:id="location"></span></td>
+        </tr>
+    </table>
+    <a wicket:id="link">More</a>
+</wicket:panel>
\ No newline at end of file
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
index 6a63259..73b99ef 100644
--- 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
@@ -16,42 +16,59 @@
    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>
+    <h1>
+        <wicket:message key="bundle" />
+        <span wicket:id="symbolicName"></span> 
+        <small>
+            <span wicket:id="version"></span>
+            <wicket:message key="details" />
+        </small>
+    </h1>
+
+    <div wicket:id="bundle"></div>
 
     <ul class="nav nav-pills">
         <li class="active">
-            <a href="#imports" data-toggle="tab">Imports</a>
+            <a href="#imports" data-toggle="tab">
+                <wicket:message key="package.imports" />
+            </a>
         </li>
         <li>
-            <a href="#exports" data-toggle="tab">Exports</a>
+            <a href="#exports" data-toggle="tab">
+                <wicket:message key="package.exports" />
+            </a>
         </li>
         <li>
-            <a href="#servicesIn" data-toggle="tab">Services in use</a>
+            <a href="#servicesIn" data-toggle="tab">
+                <wicket:message key="service.imports" />
+            </a>
         </li>
         <li>
-            <a href="#servicesOut" data-toggle="tab">Services provided</a>
+            <a href="#servicesOut" data-toggle="tab">
+                <wicket:message key="service.exports" />
+            </a>
         </li>
     </ul>
 
     <div class="tab-content">
         <div class="tab-pane active" id="imports">
-            <h2>Imports</h2>
+            <h2><wicket:message key="package.imports" /></h2>
             <table wicket:id="imports" class="table table-stripped table-bordered"></table>
         </div>
 
         <div class="tab-pane" id="exports">
-            <h3>Exports</h3>
+            <h3><wicket:message key="package.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> -->
+            <h3><wicket:message key="service.imports" /></h3>
+            <table wicket:id="serviceImports" class="table table-stripped table-bordered"></table>
         </div>
 
         <div class="tab-pane" id="servicesOut">
-            <h3>Services provided by bundle</h3>
-<!--             <div wicket:id="servicesOut"></div> -->
+            <h3><wicket:message key="service.exports" /></h3>
+            <table wicket:id="serviceExports" class="table table-stripped table-bordered"></table>
         </div>
     </div>
 
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css
index 3222be5..6483fc3 100644
--- a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/decoration.css
@@ -1,3 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 div.decorations ul {
     list-style-type: none;
     margin: 0px;
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/package.properties b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/package.properties
index 0a8351e..6650253 100644
--- a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/package.properties
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/package.properties
@@ -14,6 +14,12 @@
  # limitations under the License. 
 
 bundle Bundle
+bundle.id Bundle ID
+bundle.symbolicName Symbolic name
+bundle.version Version
+bundle.state State
+bundle.location Location
+
 bundle.install Install new bundle
 
 bundle.start Bundle $\{symbolicName\} ($\{bundleId\}) started
@@ -32,4 +38,15 @@
 bundle.refresh.fail Bundle refresh fail: ${message}
 
 bundle.resolve Bundle $\{symbolicName\} ($\{bundleId\}) resolved
-bundle.resolve.fail Bundle resolving error: ${message}
\ No newline at end of file
+bundle.resolve.fail Bundle resolving error: ${message}
+
+package Package
+
+package.imports Imported packages
+package.exports Exported packages
+
+service.imports Imported services
+service.exports Exported services
+
+package.exporter Exporting bundle
+package.importers Importing bundles
\ No newline at end of file
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
index 66692c1..1eabde7 100644
--- 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
@@ -16,26 +16,36 @@
    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>
+    <h1>
+        <wicket:message key="package" />
+        <span wicket:id="package"></span>
+        <small>
+            <span wicket:id="version"></span>
+            <wicket:message key="details" />
+        </small>
+    </h1>
 
     <div class="row-fluid">
-        <div class="span4">
-            <h2>Exporter</h2>
-            <a wicket:id="exporterLink">
-                <span wicket:id="exporterLabel"></span>
-            </a>
+        <h2>
+            <wicket:message key="package" />
+        </h2>
+        <span wicket:id="packageDet"></span>
+    </div>
+
+    <div class="row-fluid">
+        <div class="span6">
+            <h2>
+                <wicket:message key="package.exporter" />
+            </h2>
+            <div wicket:id="exporter"></div>
         </div>
-        <div class="span4">
-            <h2>Package</h2>
-            <span wicket:id="packageDet"></span>
-        </div>
-        <div class="span4">
-            <h2>Importer</h2>
-            <ul>
+        <div class="span6">
+            <h2>
+                <wicket:message key="package.importers" />
+            </h2>
+            <ul class="unstyled">
                 <li wicket:id="importers">
-                    <a wicket:id="importerLink">
-                        <span wicket:id="importerLabel"></span>
-                    </a>
+                    <div wicket:id="importer"></div>
                 </li>
             </ul>
         </div>
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.html
new file mode 100644
index 0000000..ed3a0a6
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/pkg/list/PackagePage.html
@@ -0,0 +1,24 @@
+<?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>
+        <wicket:message key="package" />
+    </h1>
+
+    <table wicket:id="packages" class="table table-stripped table-condensed" />
+</wicket:extend>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.html
new file mode 100644
index 0000000..b75c260
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ObjectClassPanel.html
@@ -0,0 +1,24 @@
+<?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 class="unstyled">
+        <li wicket:id="objectClasses">
+            <span wicket:id="objectClass"></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/service/column/ServiceConsumerPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerPanel.html
new file mode 100644
index 0000000..f6e597a
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ServiceConsumerPanel.html
@@ -0,0 +1,26 @@
+<?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 class="unstyled">
+        <li wicket:id="bundles">
+            <a wicket:id="link">
+                <span wicket:id="label"></span>
+            </a>
+        </li>
+    </ul>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.html
new file mode 100644
index 0000000..f2d5860
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/service/column/ServiceProviderPanel.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 wicket:id="link">
+        <span wicket:id="label"></span>
+    </a>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/event/src/main/resources/org/apache/karaf/webconsole/osgi/event/EventsPage.html b/osgi/event/src/main/resources/org/apache/karaf/webconsole/osgi/event/EventsPage.html
index 9bccda2..b0edd21 100644
--- a/osgi/event/src/main/resources/org/apache/karaf/webconsole/osgi/event/EventsPage.html
+++ b/osgi/event/src/main/resources/org/apache/karaf/webconsole/osgi/event/EventsPage.html
@@ -18,5 +18,5 @@
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
     <h1>Events</h1>
 
-    <table wicket:id="topics" />
+    <table wicket:id="topics" class="table table-striped table-condensed" />
 </wicket:extend>
\ No newline at end of file
diff --git a/osgi/scr/src/main/resources/org/apache/karaf/webconsole/osgi/scr/decorator.css b/osgi/scr/src/main/resources/org/apache/karaf/webconsole/osgi/scr/decorator.css
index 6b48c3c..477ab9f 100644
--- a/osgi/scr/src/main/resources/org/apache/karaf/webconsole/osgi/scr/decorator.css
+++ b/osgi/scr/src/main/resources/org/apache/karaf/webconsole/osgi/scr/decorator.css
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
 .scr {
     background: url("scr.gif");
     width: 16px;