Added support for setting preferences through osgi PreferencesService. Possibility to change user avatar. Added PanelProvider interface. Now WidgetProvider extends PanelProvider.

Signed-off-by: Lukasz Dywicki <luke@code-house.org>

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1170831 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/camel/src/main/java/org/apache/karaf/webconsole/camel/internal/widget/CamelWidgetProvider.java b/camel/src/main/java/org/apache/karaf/webconsole/camel/internal/widget/CamelWidgetProvider.java
index 507bc91..ee095c9 100644
--- a/camel/src/main/java/org/apache/karaf/webconsole/camel/internal/widget/CamelWidgetProvider.java
+++ b/camel/src/main/java/org/apache/karaf/webconsole/camel/internal/widget/CamelWidgetProvider.java
@@ -14,7 +14,7 @@
         this.contexts = contexts;
     }
 
-    public Panel getWidgetPanel(String id) {
+    public Panel createPanel(String id) {
         return new CamelWidget(id, contexts);
     }
 
diff --git a/core/pom.xml b/core/pom.xml
index 8f8152c..c3341b6 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -36,6 +36,11 @@
             <artifactId>org.osgi.core</artifactId>
             <version>4.2.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>4.2.0</version>
+        </dependency>
 
         <!-- WICKET DEPENDENCIES -->
         <dependency>
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/dashboard/DashboardPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/dashboard/DashboardPage.java
index d3f8217..a0339b6 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/dashboard/DashboardPage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/dashboard/DashboardPage.java
@@ -29,6 +29,9 @@
 import org.ops4j.pax.wicket.api.PaxWicketBean;
 import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
 
+/**
+ * Default page shown to user after successful login or after click in logo.
+ */
 @PaxWicketMountPoint(mountPoint = "/dashboard")
 public class DashboardPage extends SinglePage {
 
@@ -48,7 +51,7 @@
         add(new ListView<WidgetProvider>("widgets", new ListModel<WidgetProvider>(widgets)) {
             @Override
             protected void populateItem(ListItem<WidgetProvider> item) {
-                item.add(item.getModelObject().getWidgetPanel("widget"));
+                item.add(item.getModelObject().createPanel("widget"));
             }
         });
     }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/SidebarPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/SidebarPanel.java
index ca55555..33dad69 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/internal/SidebarPanel.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/SidebarPanel.java
@@ -41,7 +41,7 @@
         add(new ListView<WidgetProvider>("widgets", provider.getWidgetProviders()) {
             @Override
             protected void populateItem(ListItem<WidgetProvider> item) {
-                item.add(item.getModelObject().getWidgetPanel("widget"));
+                item.add(item.getModelObject().createPanel("widget"));
             }
         });
     }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesForm.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesForm.java
new file mode 100644
index 0000000..0366523
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesForm.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.internal.preferences;
+
+import org.apache.karaf.webconsole.core.preferences.PreferencesPage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Form which allows editing webconsole core bundle preferences.
+ */
+public class SystemPreferencesForm extends Form<Preferences> {
+
+    private transient Logger logger = LoggerFactory.getLogger(SystemPreferencesForm.class);
+
+    private FileUploadField upload;
+
+    public SystemPreferencesForm(String id, IModel<Preferences> model) {
+        super(id, model);
+
+        setMultiPart(true);
+        add(upload = new FileUploadField("avatar"));
+        add(new Button("submit"));
+    }
+
+    @Override
+    protected void onSubmit() {
+        Preferences prefs = getModelObject();
+
+        FileUpload file = upload.getFileUpload();
+
+        prefs.putByteArray("avatar", file.getBytes());
+        prefs.put("avatar-mime-type", file.getContentType());
+
+        try {
+            prefs.flush();
+        } catch (BackingStoreException e) {
+            logger.error("Error while flusing user preferences", e);
+            Session.get().error("Cannot store avatar");
+        }
+
+        RequestCycle requestCycle = RequestCycle.get();
+        requestCycle.setRedirect(true);
+        requestCycle.setResponsePage(PreferencesPage.class);
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.java
new file mode 100644
index 0000000..f16cfb6
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.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.core.internal.preferences;
+
+import org.apache.karaf.webconsole.core.page.AvatarImage;
+import org.apache.karaf.webconsole.core.preferences.PreferencesModel;
+import org.apache.karaf.webconsole.core.security.WebConsoleSession;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Preferences edit panel.
+ */
+public class SystemPreferencesPanel extends Panel {
+
+    @PaxWicketBean(name = "preferencesService")
+    private PreferencesService preferences;
+
+    public SystemPreferencesPanel(String id) {
+        super(id);
+
+        String user = WebConsoleSession.get().getUsername();
+
+        Preferences userPreferences = preferences.getUserPreferences(user);
+
+        add(new AvatarImage("currentAvatar", userPreferences));
+
+        PreferencesModel formModel = new PreferencesModel(preferences, userPreferences, user);
+        add(new SystemPreferencesForm("systemPreferences", formModel));
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanelProvider.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanelProvider.java
new file mode 100644
index 0000000..10c76e2
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanelProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.internal.preferences;
+
+import org.apache.karaf.webconsole.core.panel.PanelProvider;
+import org.apache.wicket.markup.html.panel.Panel;
+
+/**
+ * System preferences panel provider.
+ */
+public class SystemPreferencesPanelProvider implements PanelProvider {
+
+    public Panel createPanel(String id) {
+        return new SystemPreferencesPanel(id);
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/page/AvatarImage.java b/core/src/main/java/org/apache/karaf/webconsole/core/page/AvatarImage.java
new file mode 100644
index 0000000..e6fa853
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/page/AvatarImage.java
@@ -0,0 +1,26 @@
+package org.apache.karaf.webconsole.core.page;
+
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.resource.ByteArrayResource;
+import org.osgi.service.prefs.Preferences;
+
+public class AvatarImage extends Image {
+
+    public AvatarImage(String id, Preferences preferences) {
+        super(id);
+
+        byte[] avatar = preferences.getByteArray("avatar", new byte[0]);
+
+        if (avatar != null && avatar.length > 0) {
+            String contentType = preferences.get("avatar-mime-type", "image/jpg");
+            ByteArrayResource resource = new ByteArrayResource(contentType, avatar);
+            resource.setCacheable(false);
+            setImageResource(resource);
+            return;
+        }
+
+        setImageResourceReference(new ResourceReference(AvatarImage.class, "apache-avatar.png"));
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
index 497cb2f..6904e2d 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
@@ -21,13 +21,16 @@
 import org.apache.karaf.webconsole.core.BasePage;
 import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
 import org.apache.karaf.webconsole.core.navigation.markup.NavigationPanel;
+import org.apache.karaf.webconsole.core.preferences.PreferencesPage;
 import org.apache.karaf.webconsole.core.security.WebConsoleSession;
 import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.StringResourceModel;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.service.prefs.PreferencesService;
 
 /**
  * Page which requires admin role, in other words authorized user.
@@ -38,6 +41,9 @@
     @PaxWicketBean(name = "tabs")
     private List<ConsoleTabProvider> tabs;
 
+    @PaxWicketBean(name = "preferencesService")
+    private PreferencesService preferences;
+
     public SecuredPage() {
         add(new NavigationPanel("navigationPanel", new LoadableDetachableModel<List<ConsoleTabProvider>>() {
             @Override
@@ -46,7 +52,11 @@
             }
         }));
 
-        add(new Label("username", WebConsoleSession.get().getUsername()));
+        String username = WebConsoleSession.get().getUsername();
+        add(new AvatarImage("avatar", preferences.getUserPreferences(username)));
+
+        add(new Label("username", username));
+        add(new BookmarkablePageLink<PreferencesPage>("preferencesLink", PreferencesPage.class));
 
         Link<Void> aLink = new Link<Void>("logoutLink") {
             @Override
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/panel/PanelProvider.java b/core/src/main/java/org/apache/karaf/webconsole/core/panel/PanelProvider.java
new file mode 100644
index 0000000..4b87d3d
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/panel/PanelProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.panel;
+
+import org.apache.wicket.markup.html.panel.Panel;
+
+/**
+ * Implementation of this interface are able to provide panel blocks.
+ */
+public interface PanelProvider {
+
+    /**
+     * Create new panel with given id. This method will be called during page
+     * or parent component rendering - normally in container dispatching thread.
+     * 
+     * @param id Panel id.
+     * @return Panel to be put as widget.
+     */
+    public Panel createPanel(String id);
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesModel.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesModel.java
new file mode 100644
index 0000000..7048766
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesModel.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.preferences;
+
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Model which allows to load preferences.
+ */
+public class PreferencesModel extends LoadableDetachableModel<Preferences> {
+
+    /**
+     * Service to load preferences.
+     */
+    private PreferencesService service;
+
+    /**
+     * Path to preference node.
+     */
+    private String path;
+
+    /**
+     * User name. If null then model is used to display system preferences.
+     */
+    private String user;
+
+    public PreferencesModel(PreferencesService service, Preferences node, String userName) {
+        super(node);
+        this.service = service;
+        this.user = userName;
+
+        this.path = node.absolutePath();
+    }
+
+    public PreferencesModel(PreferencesService service, Preferences node) {
+        this(service, node, null);
+    }
+
+    @Override
+    protected Preferences load() {
+        try {
+            if (user == null) {
+                return resolve(service.getSystemPreferences(), path);
+            }
+            return resolve(service.getUserPreferences(user), path);
+        } catch (BackingStoreException e) {
+            throw new RuntimeException("Cannot load preferences", e);
+        }
+    }
+
+    private Preferences resolve(Preferences preferences, String absolutePath) throws BackingStoreException {
+        if (preferences.nodeExists(absolutePath)) {
+            return preferences.node(absolutePath);
+        }
+
+        throw new IllegalArgumentException("Path " + absolutePath + " doesnt exists");
+    }
+
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPage.java
new file mode 100644
index 0000000..e0a8609
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPage.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.core.preferences;
+
+import java.util.List;
+
+import org.apache.karaf.webconsole.core.page.SinglePage;
+import org.apache.karaf.webconsole.core.panel.PanelProvider;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * Page used to display preferences from various bundles.
+ */
+@PaxWicketMountPoint(mountPoint = "/preferences")
+public class PreferencesPage extends SinglePage {
+
+    @PaxWicketBean(name = "preferencesProviders")
+    private List<PanelProvider> providers;
+
+    public PreferencesPage() throws BackingStoreException {
+        RepeatingView preferencesView = new RepeatingView("preferences");
+
+        for (PanelProvider provider : providers) {
+            MarkupContainer container = new WebMarkupContainer(preferencesView.newChildId());
+            container.add(provider.createPanel("preferencesPanel"));
+            preferencesView.add(container);
+        }
+
+        add(preferencesView);
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.java
new file mode 100644
index 0000000..db02979
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.preferences;
+
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.model.IModel;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Base class to display preferences without edit possibility.
+ */
+public class PreferencesPanel extends Panel {
+
+    public PreferencesPanel(String id, String user, PreferencesService service, IModel<Preferences> model) throws BackingStoreException {
+        super(id, model);
+
+        Preferences preferences = model.getObject();
+
+        add(new Label("path", preferences.absolutePath()));
+
+        RepeatingView repeatingView = new RepeatingView("preferences");
+        for (String key : preferences.keys()) {
+            WebMarkupContainer container = new WebMarkupContainer(repeatingView.newChildId());
+
+            container.add(new Label("key", key));
+            container.add(new Label("value", preferences.get(key, null)));
+            repeatingView.add(container);
+        }
+
+        add(repeatingView);
+
+        repeatingView = new RepeatingView("children");
+        for (String child : preferences.childrenNames()) {
+            WebMarkupContainer container = new WebMarkupContainer(repeatingView.newChildId());
+
+            container.add(new PreferencesPanel("child", user, service, new PreferencesModel(service, preferences.node(child))));
+        }
+        add(repeatingView);
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferences.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferences.java
new file mode 100644
index 0000000..308253b
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferences.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.preferences.util;
+
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * Preferences based on JDK mechanism.
+ */
+public class JdkPreferences implements Preferences {
+
+    private java.util.prefs.Preferences prefs;
+
+    public JdkPreferences(java.util.prefs.Preferences preferences) {
+        this.prefs = preferences;
+    }
+
+    public void put(String key, String value) {
+        prefs.put(key, value);
+    }
+
+    public String get(String key, String def) {
+        return prefs.get(key, def);
+    }
+
+    public void remove(String key) {
+        prefs.remove(key);
+    }
+
+    public void clear() throws BackingStoreException {
+        try {
+            prefs.clear();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to clear", e);
+        }
+    }
+
+    public void putInt(String key, int value) {
+        prefs.putInt(key, value);
+    }
+
+    public int getInt(String key, int def) {
+        return prefs.getInt(key, def);
+    }
+
+    public void putLong(String key, long value) {
+        prefs.putLong(key, value);
+    }
+
+    public long getLong(String key, long def) {
+        return prefs.getLong(key, def);
+    }
+
+    public void putBoolean(String key, boolean value) {
+        prefs.putBoolean(key, value);
+    }
+
+    public boolean getBoolean(String key, boolean def) {
+        return prefs.getBoolean(key, def);
+    }
+
+    public void putFloat(String key, float value) {
+        prefs.putFloat(key, value);
+    }
+
+    public float getFloat(String key, float def) {
+        return prefs.getFloat(key, def);
+    }
+
+    public void putDouble(String key, double value) {
+        prefs.putDouble(key, value);
+    }
+
+    public double getDouble(String key, double def) {
+        return prefs.getDouble(key, def);
+    }
+
+    public void putByteArray(String key, byte[] value) {
+        prefs.putByteArray(key, value);
+    }
+
+    public byte[] getByteArray(String key, byte[] def) {
+        return prefs.getByteArray(key, def);
+    }
+
+    public String[] childrenNames() throws BackingStoreException {
+        try {
+            return prefs.childrenNames();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to get children names", e);
+        }
+    }
+
+    public Preferences parent() {
+        return new JdkPreferences(prefs.parent());
+    }
+
+    public Preferences node(String pathName) {
+        return new JdkPreferences(prefs.node(pathName));
+    }
+
+    public boolean nodeExists(String pathName) throws BackingStoreException {
+        try {
+            return prefs.nodeExists(pathName);
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to check node", e);
+        }
+    }
+
+    public void removeNode() throws BackingStoreException {
+        try {
+            prefs.removeNode();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to remove node", e);
+        }
+    }
+
+    public String name() {
+        return prefs.name();
+    }
+
+    public String absolutePath() {
+        return prefs.absolutePath();
+    }
+
+    public void flush() throws BackingStoreException {
+        try {
+            prefs.flush();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to flush", e);
+        }
+    }
+
+    public void sync() throws BackingStoreException {
+        try {
+            prefs.sync();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to sync", e);
+        }
+    }
+
+    public String[] keys() throws BackingStoreException {
+        try {
+            return prefs.keys();
+        } catch (java.util.prefs.BackingStoreException e) {
+            throw new BackingStoreException("Unable to get keys", e);
+        }
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java
new file mode 100644
index 0000000..da35192
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.preferences.util;
+
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Preferences service created on top of standard JDK implementation.
+ */
+public class JdkPreferencesService implements PreferencesService {
+
+    public Preferences getSystemPreferences() {
+        return new JdkPreferences(java.util.prefs.Preferences.systemRoot());
+    }
+
+    public Preferences getUserPreferences(String name) {
+        return new JdkPreferences(java.util.prefs.Preferences.userRoot());
+    }
+
+    public String[] getUsers() {
+        return new String[] { System.getProperty("user.name") };
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/widget/WidgetProvider.java b/core/src/main/java/org/apache/karaf/webconsole/core/widget/WidgetProvider.java
index 28a040a..abeded2 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/widget/WidgetProvider.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/widget/WidgetProvider.java
@@ -16,22 +16,13 @@
  */
 package org.apache.karaf.webconsole.core.widget;
 
-import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.karaf.webconsole.core.panel.PanelProvider;
 
 /**
  * Widget extension point which may be used in many places. Services registered
  * in OSGi should provide information where it should be put using "intention"
  * property.
  */
-public interface WidgetProvider {
-
-    /**
-     * Create new panel with given id. This method will be called during page
-     * or parent component rendering - normally in container dispatching thread.
-     * 
-     * @param id Panel id.
-     * @return Panel to be put as widget.
-     */
-    Panel getWidgetPanel(String id);
+public interface WidgetProvider extends PanelProvider {
 
 }
diff --git a/core/src/main/resources/OSGI-INF/blueprint/core.xml b/core/src/main/resources/OSGI-INF/blueprint/core.xml
index b2d5ac9..c1ecb01 100644
--- a/core/src/main/resources/OSGI-INF/blueprint/core.xml
+++ b/core/src/main/resources/OSGI-INF/blueprint/core.xml
@@ -23,10 +23,12 @@
 
     <reference-list id="tabs" interface="org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider" availability="optional" />
 
-    <!-- He is not ready yet ... -->
     <reference-list id="widgets" interface="org.apache.karaf.webconsole.core.widget.WidgetProvider" availability="optional"
         filter="(intention=dashboard)" />
 
+    <reference-list id="preferencesProviders" interface="org.apache.karaf.webconsole.core.panel.PanelProvider" availability="optional"
+        filter="(intention=preferences)" />
+
     <service interface="org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider">
         <bean class="org.apache.karaf.webconsole.core.internal.SystemConsoleTabProvider" />
     </service>
@@ -35,7 +37,17 @@
         <bean class="org.apache.karaf.webconsole.core.brand.DefaultBrandProvider" />
     </service>
 
+    <service ref="systemPreferencesPanelProvider" auto-export="interfaces">
+        <service-properties>
+            <entry key="intention" value="preferences" />
+        </service-properties>
+    </service>
+
+    <bean id="systemPreferencesPanelProvider" class="org.apache.karaf.webconsole.core.internal.preferences.SystemPreferencesPanelProvider" />
+
+    <reference id="preferencesService" interface="org.osgi.service.prefs.PreferencesService" />
+
     <reference id="brandProvider" interface="org.apache.karaf.webconsole.core.brand.BrandProvider" 
-	availability="optional" />
+        availability="optional" />
 
 </blueprint>
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.html
new file mode 100644
index 0000000..a810be3
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/internal/preferences/SystemPreferencesPanel.html
@@ -0,0 +1,40 @@
+<?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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Karaf WebConsole</title>
+</head>
+<body>
+
+    <wicket:panel>
+        <h1>System preferences</h1>
+
+        Current avatar
+        <img wicket:id="currentAvatar" />
+
+        <form wicket:id="systemPreferences">
+            Select image to be used as your avatar:
+            <input wicket:id="avatar" type="file" />
+
+            <input wicket:id="submit" type="submit" value="Save" />
+        </form>
+    </wicket:panel>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
index f96c1fe..39a1f85 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
@@ -25,11 +25,14 @@
 <body>
 
     <wicket:extend>
-        <div id="userbox" class="grid_1 prefix_11 suffix_0">
-            <p>
+        <div id="userbox" class="grid_2">
+            <img wicket:id="avatar" class="avatar" alt="User avatar" />
+            <span id="details">
                 Welcome <span wicket:id="username">admin</span>
+
                 <a href="#" wicket:id="logoutLink"><span wicket:id="logoutTranslatedLink"/></a>
-            </p>
+                <a href="#" wicket:id="preferencesLink">Preferences</a>
+            </span>
         </div>
 
         <div class="grid_12">
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/apache-avatar.png b/core/src/main/resources/org/apache/karaf/webconsole/core/page/apache-avatar.png
new file mode 100644
index 0000000..2329412
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/apache-avatar.png
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPage.html
new file mode 100644
index 0000000..dc18f41
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPage.html
@@ -0,0 +1,37 @@
+<?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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Karaf WebConsole</title>
+</head>
+<body>
+
+    <wicket:extend>
+
+        <ul>
+            <li wicket:id="preferences">
+                <div wicket:id="preferencesPanel">
+                    Preference Panel
+                </div>
+            </li>
+        </ul>
+    </wicket:extend>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.html
new file mode 100644
index 0000000..e559184
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/preferences/PreferencesPanel.html
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Karaf WebConsole</title>
+</head>
+<body>
+
+    <wicket:panel>
+        <span wicket:id="path">some/path</span>
+
+        <ul>
+            <li wicket:id="preferences">
+                <span wicket:id="key">key</span>
+                <span wicket:id="value">value</span>
+            </li>
+        </ul>
+
+        <ul>
+            <li wicket:id="children">
+                <div wicket:id="child">child details</div>
+            </li>
+        </ul>
+    </wicket:panel>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/style.css b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
index f1679fa..188d352 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
@@ -30,11 +30,26 @@
     width: 250px;
 }
 
-#userbox span {
+#userbox {
+    float: right;
+    width: 250px;
+}
+
+#userbox img.avatar {
+    padding: 3px;
+    float: left;
+}
+
+#details {
+    display: block;
+    float: left;
+}
+
+#details span {
     font-weight: bold;
 }
 
-#usebox a span {
+#details a span {
     font-weight: normal;
 }
 
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/TestInjector.java b/core/src/test/java/org/apache/karaf/webconsole/core/TestInjector.java
index 4c16a79..4430389 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/TestInjector.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/TestInjector.java
@@ -63,6 +63,11 @@
             String name = field.getName();
             Class<?> type = field.getType();
 
+            PaxWicketBean wicketBean = field.getAnnotation(PaxWicketBean.class);
+            if (wicketBean != null) {
+                name = wicketBean.name();
+            }
+
             if (values.containsKey(name)) {
                 // we have value..
                 final Object value = values.get(name);
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java
index 13e87fd..884eb0d 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.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.core;
 
 import static org.easymock.EasyMock.anyObject;
@@ -9,13 +25,19 @@
 
 import org.apache.karaf.webconsole.core.brand.DefaultBrandProvider;
 import org.apache.karaf.webconsole.core.internal.WebConsoleApplication;
+import org.apache.karaf.webconsole.core.preferences.util.JdkPreferencesService;
 import org.apache.karaf.webconsole.core.security.KarafJaasWebSession;
 import org.apache.wicket.Page;
 import org.apache.wicket.authentication.AuthenticatedWebSession;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.protocol.http.WebApplication;
 import org.junit.Before;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
 
+/**
+ * Base class for webconsole tests.
+ */
 public class WebConsoleTest {
 
     /**
@@ -43,6 +65,7 @@
         // default configurations values.
         Map<String, Object> values = new HashMap<String, Object>();
         values.put("brandProvider", new DefaultBrandProvider());
+        values.put("preferencesService", new JdkPreferencesService());
 
         injector = new TestInjector(values);
         application.addComponentInstantiationListener(injector);
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/dashboard/DashboardPageTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/dashboard/DashboardPageTest.java
index 48042c5..16938d6 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/dashboard/DashboardPageTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/dashboard/DashboardPageTest.java
@@ -23,7 +23,7 @@
 
 import org.apache.karaf.webconsole.core.WebConsoleTest;
 import org.apache.karaf.webconsole.core.brand.DefaultBrandProvider;
-import org.apache.karaf.webconsole.core.dashboard.DashboardPage;
+import org.apache.karaf.webconsole.core.preferences.util.JdkPreferencesService;
 import org.apache.karaf.webconsole.core.test.AlwaysAuthenticatedWebSession;
 import org.apache.karaf.webconsole.core.widget.WidgetProvider;
 import org.apache.wicket.authentication.AuthenticatedWebSession;
@@ -41,7 +41,7 @@
 public class DashboardPageTest extends WebConsoleTest {
 
     static class TestWidgetProvider implements WidgetProvider, Serializable {
-        public Panel getWidgetPanel(String id) {
+        public Panel createPanel(String id) {
             return new EmptyPanel(id);
         }
     }
@@ -55,6 +55,7 @@
 
         values.put("widgets", providers);
         values.put("brandProvider", new DefaultBrandProvider());
+        values.put("preferencesService", new JdkPreferencesService());
 
         injector.setValues(values);
 
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
index 0b68c91..864d0c6 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.karaf.webconsole.core.page;
 
-import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createStrictMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
@@ -33,6 +32,7 @@
 import org.apache.karaf.webconsole.core.WebConsoleTest;
 import org.apache.karaf.webconsole.core.brand.DefaultBrandProvider;
 import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
+import org.apache.karaf.webconsole.core.preferences.util.JdkPreferencesService;
 import org.apache.karaf.webconsole.core.test.AlwaysAuthenticatedWebSession;
 import org.apache.karaf.webconsole.core.test.LinkAnswer;
 import org.apache.karaf.webconsole.core.test.LinksAnswer;
@@ -71,6 +71,7 @@
         Map<String, Object> values = new HashMap<String, Object>();
 
         values.put("brandProvider", new DefaultBrandProvider());
+        values.put("preferencesService", new JdkPreferencesService());
 
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
@@ -101,6 +102,7 @@
         Map<String, Object> values = new HashMap<String, Object>();
 
         values.put("brandProvider", new DefaultBrandProvider());
+        values.put("preferencesService", new JdkPreferencesService());
 
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
@@ -136,6 +138,7 @@
         Map<String, Object> values = new HashMap<String, Object>();
 
         values.put("brandProvider", new DefaultBrandProvider());
+        values.put("preferencesService", new JdkPreferencesService());
 
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
diff --git a/core/x b/core/x
deleted file mode 100644
index e69de29..0000000
--- a/core/x
+++ /dev/null
diff --git a/features/src/main/filtered-resources/features.xml b/features/src/main/filtered-resources/features.xml
index d1dc077..f5320bc 100644
--- a/features/src/main/filtered-resources/features.xml
+++ b/features/src/main/filtered-resources/features.xml
@@ -20,15 +20,16 @@
   <repository>mvn:org.ops4j.pax.wicket/features/${ops4j.paxwicket.version}/xml/features</repository>
 
   <feature name="webconsole-wicket" version="${project.version}" description="Karaf Wicket Webconsole">
-    <feature>webconsole-blueprint</feature>
     <feature>webconsole-core</feature>
     <feature>webconsole-osgi</feature>
+    <feature>webconsole-blueprint</feature>
     <feature>webconsole-karaf</feature>
   </feature>
   <!-- Pax-Wicket Core Feature; loading all required features. Do a feature:install paxwicket and you're ready to go -->
   <feature name="webconsole-core" version="${project.version}" description="Karaf Webconsole Core">
     <details>The Webconsole core package provides the base view required for all bundles</details>
     <feature>wicket-spring</feature>
+    <bundle>mvn:org.apache.felix/org.apache.felix.prefs/${felix-prefs.version}</bundle>
     <bundle>mvn:org.apache.karaf.webconsole/org.apache.karaf.webconsole.core/${project.version}</bundle>
   </feature>
 
diff --git a/karaf/src/main/java/org/apache/karaf/webconsole/karaf/internal/widget/KarafFeaturesWidgetProvider.java b/karaf/src/main/java/org/apache/karaf/webconsole/karaf/internal/widget/KarafFeaturesWidgetProvider.java
index 3792ee1..756e0ea 100644
--- a/karaf/src/main/java/org/apache/karaf/webconsole/karaf/internal/widget/KarafFeaturesWidgetProvider.java
+++ b/karaf/src/main/java/org/apache/karaf/webconsole/karaf/internal/widget/KarafFeaturesWidgetProvider.java
@@ -28,7 +28,7 @@
         this.service = service;
     }
 
-    public Panel getWidgetPanel(String id) {
+    public Panel createPanel(String id) {
         return new FeaturesWidgetPanel(id, service);
     }
 
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/widget/OsgiWidgetProvider.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/widget/OsgiWidgetProvider.java
index 066a25f..f856db8 100644
--- a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/widget/OsgiWidgetProvider.java
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/widget/OsgiWidgetProvider.java
@@ -29,7 +29,7 @@
         
     }
 
-    public Panel getWidgetPanel(String id) {
+    public Panel createPanel(String id) {
         return new OsgiWidgetPanel(id, context);
     }
 
diff --git a/pom.xml b/pom.xml
index 5ad458c..abb7f73 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,6 +29,7 @@
     <properties>
         <jetty.version>6.1.25</jetty.version>
         <felix-metatype.version>1.0.4</felix-metatype.version>
+        <felix-prefs.version>1.0.4</felix-prefs.version>
         <slf4j.version>1.5.8</slf4j.version>
         <log4j.version>1.2.14</log4j.version>
         <ops4j.paxwicket.version>0.8.0-SNAPSHOT</ops4j.paxwicket.version>
@@ -108,4 +109,19 @@
         </repository>
     </repositories>
 
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.metatype</artifactId>
+                <version>${felix-metatype.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.prefs</artifactId>
+                <version>${felix-prefs.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
 </project>
\ No newline at end of file