Refactor of osgi/core module:
- restructured list of bundles with new icons instead of labels
- separate links for every operation instead of annonymous classes inside BundleActionsPanel
- first translations

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1291052 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/table/ActionsPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/table/ActionsPanel.java
index 5fc5987..38e1ef9 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/table/ActionsPanel.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/table/ActionsPanel.java
@@ -64,4 +64,13 @@
         return Collections.emptyList();
     }
 
+    /**
+     * Gets model
+     * 
+     * @return model
+     */
+    @SuppressWarnings("unchecked")
+    public final IModel<T> getModel() {
+        return (IModel<T>) getDefaultModel();
+    }
 }
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.properties b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.properties
deleted file mode 100644
index 1e98788..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# Login properties
-logout.link=Logout
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage_fr.properties b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage_fr.properties
deleted file mode 100644
index af7f830..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage_fr.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# Login properties
-logout.link=Se d\u00E9connecter
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/table/ActionsPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/table/ActionsPanel.html
index 238ad93..81bb5f3 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/table/ActionsPanel.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/table/ActionsPanel.html
@@ -20,7 +20,7 @@
         <ul>
             <li wicket:id="actions">
                 <a wicket:id="action">
-                    <span wicket:id="label">label</span>
+                    <span wicket:id="label"></span>
                 </a>
             </li>
         </ul>
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
index e249ec3..074774c 100644
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundleActionsPanel.java
@@ -21,19 +21,19 @@
 
 import org.apache.karaf.webconsole.core.table.ActionsPanel;
 import org.apache.karaf.webconsole.osgi.core.bundle.SingleBundlePage;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.RefreshLink;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.ResolveLink;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.StartLink;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.StopLink;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.UninstallLink;
+import org.apache.karaf.webconsole.osgi.core.bundle.list.link.UpdateLink;
 import org.apache.karaf.webconsole.osgi.core.shared.State;
 import org.apache.karaf.webconsole.osgi.core.spi.IActionProvider;
-import org.apache.wicket.PageParameters;
-import org.apache.wicket.RequestCycle;
-import org.apache.wicket.Session;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
 import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.model.IModel;
-import org.ops4j.pax.wicket.api.PaxWicketBean;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
  * Action panel for bundles list.
@@ -41,8 +41,7 @@
 @SuppressWarnings("rawtypes")
 public class BundleActionsPanel extends ActionsPanel<Bundle> {
 
-    @PaxWicketBean(name = "packageAdmin")
-    private PackageAdmin admin;
+    private static final long serialVersionUID = 1L;
 
     public BundleActionsPanel(String componentId, final IModel<Bundle> model, List<IActionProvider> actionProviders) {
         super(componentId, model);
@@ -59,14 +58,11 @@
 
     @Override
     protected List<Link> getLinks(Bundle object, String linkId, String labelId) {
-        PageParameters params = new PageParameters();
-        params.put("bundleId", object.getBundleId());
-
         List<Link> links = new ArrayList<Link>();
 
         // details link
-        Link link = new BookmarkablePageLink<SingleBundlePage>(linkId, SingleBundlePage.class, params);
-        link.add(new Label("label", "Details"));
+        Link link = SingleBundlePage.createLink(linkId, object);
+        link.add(new Label("label", "").add(new SimpleAttributeModifier("class", "icon-info-sign")));
 
         links.add(link);
 
@@ -75,90 +71,54 @@
             links.add(createStopLink(linkId, labelId));
             break;
         case INSTALLED:
+            // here we do not have break, because start operation will try to
+            // resolve imports too
+            links.add(createResolveLink(linkId, labelId));
         case RESOLVED:
             links.add(createStartLink(linkId, labelId));
         }
 
         links.add(createRefreshLink(linkId, labelId));
+        links.add(createUpdateLink(linkId, labelId));
         links.add(createUninstallLink(linkId, labelId));
 
         return links;
     }
 
     private Link createUninstallLink(String linkId, String labelId) {
-        Link link = new Link(linkId) {
-            @Override
-            public void onClick() {
-                Bundle bundle = (Bundle) BundleActionsPanel.this.getDefaultModelObject();
-
-                try {
-                    bundle.uninstall();
-
-                    Session.get().info("Bundle " + bundle.getSymbolicName() + " uninstalled");
-                    RequestCycle.get().setResponsePage(BundlePage.class);
-                } catch (BundleException e) {
-                    // TODO Auto-generated catch block
-                    e.printStackTrace();
-                }
-            }
-            
-        };
-        link.add(new Label(labelId, "Uninstall"));
+        Link link = new UninstallLink(linkId, getModel());
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-eject")));
         return link;
     }
 
     private Link createRefreshLink(String linkId, String labelId) {
-        Link link = new Link(linkId) {
-            @Override
-            public void onClick() {
-                Bundle bundle = (Bundle) BundleActionsPanel.this.getDefaultModelObject();
+        Link link = new RefreshLink(linkId, getModel());
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-refresh")));
+        return link;
+    }
 
-                admin.refreshPackages(new Bundle[] {bundle});
-                Session.get().info("Bundle " + bundle.getSymbolicName() + " refreshed");
-                RequestCycle.get().setResponsePage(BundlePage.class);
-            }
-            
-        };
-        link.add(new Label(labelId, "Refresh"));
+    private Link createUpdateLink(String linkId, String labelId) {
+        Link link = new UpdateLink(linkId, getModel());
+        //link.add(new SimpleAttributeModifier("title", getLocalizer().getString("bundle.update.link", this, getModel())));
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-retweet")));
+        return link;
+    }
+
+    private Link createResolveLink(String linkId, String labelId) {
+        Link link = new ResolveLink(linkId, getModel());
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-step-forward")));
         return link;
     }
 
     private Link createStartLink(String linkId, String labelId) {
-        Link link = new Link(linkId) {
-            @Override
-            public void onClick() {
-                Bundle bundle = (Bundle) BundleActionsPanel.this.getDefaultModelObject();
-
-                try {
-                    bundle.start();
-                    Session.get().info("Bundle " + bundle.getSymbolicName() + " started");
-                    RequestCycle.get().setResponsePage(BundlePage.class);
-                } catch (BundleException e) {
-                    // TODO Auto-generated catch block
-                    e.printStackTrace();
-                }
-            }
-            
-        };
-        link.add(new Label(labelId, "Start"));
+        Link link = new StartLink(linkId, getModel());
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-play")));
         return link;
     }
 
     private Link createStopLink(String linkId, String labelId) {
-        Link link = new Link(linkId) {
-            public void onClick() {
-                Bundle bundle = (Bundle) BundleActionsPanel.this.getDefaultModelObject();
-                try {
-                    bundle.stop();
-                    Session.get().info("Bundle " + bundle.getSymbolicName() + " stopped");
-                    RequestCycle.get().setResponsePage(BundlePage.class);
-                } catch (BundleException e) {
-                    // TODO Auto-generated catch block
-                    e.printStackTrace();
-                }
-            }
-        };
-        link.add(new Label(labelId, "Stop"));
+        Link link = new StopLink(linkId, getModel());
+        link.add(new Label(labelId, "").add(new SimpleAttributeModifier("class", "icon-pause")));
         return link;
     }
 }
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
index ea31a27..e138416 100644
--- a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.java
@@ -44,6 +44,9 @@
 import org.osgi.framework.Bundle;
 import org.osgi.service.startlevel.StartLevel;
 
+/**
+ * Bundle list page.
+ */
 @PaxWicketMountPoint(mountPoint = "/osgi/bundle")
 public class BundlePage extends OsgiPage {
 
@@ -62,18 +65,24 @@
     public BundlePage() {
         List<IColumn<Bundle>> columns = new ArrayList<IColumn<Bundle>>();
         columns.add(new AbstractColumn<Bundle>(of("")) {
+            private static final long serialVersionUID = 1L;
+
             public void populateItem(Item<ICellPopulator<Bundle>> cellItem, final String componentId, final IModel<Bundle> rowModel) {
                 cellItem.add(new DecorationPanel(componentId, rowModel, decorationProviders));
             }
         });
         columns.add(new PropertyColumnExt<Bundle>("Bundle Id", "bundleId"));
         columns.add(new AbstractColumn<Bundle>(of("State")) {
+            private static final long serialVersionUID = 1L;
+
             public void populateItem(Item<ICellPopulator<Bundle>> cellItem, final String componentId, final IModel<Bundle> rowModel) {
                 cellItem.add(new Label(componentId, State.of(rowModel.getObject().getState()).name()));
             }
             
         });
         columns.add(new AbstractColumn<Bundle>(of("Start level")) {
+            private static final long serialVersionUID = 1L;
+
             public void populateItem(Item<ICellPopulator<Bundle>> cellItem, final String componentId, final IModel<Bundle> rowModel) {
                 cellItem.add(new Label(componentId, of(startLevel.getBundleStartLevel(rowModel.getObject()))));
             }
@@ -87,6 +96,8 @@
         columns.add(new PropertyColumnExt<Bundle>("Name", "symbolicName"));
         columns.add(new PropertyColumnExt<Bundle>("Version", "version.toString"));
         columns.add(new AbstractColumn<Bundle>(Model.of("Operations")) {
+            private static final long serialVersionUID = 1L;
+
             public void populateItem(Item<ICellPopulator<Bundle>> cellItem, final String componentId, final IModel<Bundle> rowModel) {
                 cellItem.add(new BundleActionsPanel(componentId, rowModel, actionProviders));
             }
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 df06406..22cd231 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
@@ -30,6 +30,8 @@
 
 public class DecorationPanel extends Panel {
 
+    private static final long serialVersionUID = 1L;
+
     public DecorationPanel(String id, IModel<Bundle> model, List<IDecorationProvider> decorationProviders) {
         super(id, model);
 
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/RefreshLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/RefreshLink.java
new file mode 100644
index 0000000..bb9f1d3
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/RefreshLink.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.osgi.core.bundle.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Bundle refresh link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class RefreshLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
+
+    public RefreshLink(String id, IModel<Bundle> model) {
+        super(id, model);
+    }
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            admin.refreshPackages(new Bundle[] { bundle });
+            Session.get().info(getLocalizer().getString("bundle.refresh", this, getModel()));
+        } catch (Exception e) {
+            Session.get().info(getLocalizer().getString("bundle.refresh.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/ResolveLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/ResolveLink.java
new file mode 100644
index 0000000..b48c5a1
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/ResolveLink.java
@@ -0,0 +1,58 @@
+/*
+ * 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.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Bundle resolve link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class ResolveLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    @PaxWicketBean(name = "packageAdmin")
+    private PackageAdmin admin;
+
+    public ResolveLink(String id, IModel<Bundle> model) {
+        super(id, model);
+    }
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            admin.resolveBundles(new Bundle[] { bundle });
+            Session.get().info(getLocalizer().getString("bundle.resolve", this, getModel()));
+        } catch (Exception e) {
+            Session.get().info(getLocalizer().getString("bundle.resolve.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StartLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StartLink.java
new file mode 100644
index 0000000..150c5ff
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StartLink.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Bundle start link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class StartLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    public StartLink(String id, IModel<Bundle> model) {
+        super(id, model);}
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            bundle.start();
+            Session.get().info(getLocalizer().getString("bundle.start", this, getModel()));
+        } catch (BundleException e) {
+            Session.get().error(getLocalizer().getString("bundle.start.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StopLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StopLink.java
new file mode 100644
index 0000000..6feb2c6
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/StopLink.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Bundle stop link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class StopLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    public StopLink(String id, IModel<Bundle> model) {
+        super(id, model);}
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            bundle.stop();
+            Session.get().info(getLocalizer().getString("bundle.stop", this, getModel()));
+        } catch (BundleException e) {
+            Session.get().error(getLocalizer().getString("bundle.stop.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UninstallLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UninstallLink.java
new file mode 100644
index 0000000..2d9f3c9
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UninstallLink.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Bundle uninstallation link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class UninstallLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    public UninstallLink(String id, IModel<Bundle> model) {
+        super(id, model);}
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            bundle.uninstall();
+            Session.get().info(getLocalizer().getString("bundle.uninstall", this, getModel()));
+        } catch (BundleException e) {
+            Session.get().error(getLocalizer().getString("bundle.uninstall.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UpdateLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UpdateLink.java
new file mode 100644
index 0000000..8cc4944
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/list/link/UpdateLink.java
@@ -0,0 +1,55 @@
+/*
+ * 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.list.link;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.authorization.Action;
+import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeAction;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+
+/**
+ * Bundle update link.
+ */
+@AuthorizeAction(action = Action.RENDER, roles = {"admin"})
+public class UpdateLink extends Link<Bundle> {
+
+    private static final long serialVersionUID = 1L;
+
+    public UpdateLink(String id, IModel<Bundle> model) {
+        super(id, model);
+    }
+
+    @Override
+    public void onClick() {
+        Bundle bundle = getModelObject();
+
+        try {
+            bundle.update();
+            Session.get().info(getLocalizer().getString("bundle.update", this, getModel()));
+        } catch (BundleException e) {
+            Session.get().error(getLocalizer().getString("bundle.update.fail", this, Model.of(e)));
+        }
+        RequestCycle.get().setResponsePage(BundlePage.class);
+    }
+
+}
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html
index b982ead..15b2271 100644
--- a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/list/BundlePage.html
@@ -17,12 +17,12 @@
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
     <div class="row-fluid">
-        <h1 class="pull-left">Bundles</h1>
+        <h1 class="pull-left"><wicket:message key="bundle" /></h1>
 
         <div class="btn-group pull-right">
             <a class="btn btn-primary" wicket:id="install">
                 <i class="icon-plus icon-white"></i>
-                Install bundle
+                <wicket:message key="bundle.install" />
             </a>
         </div>
     </div>
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
new file mode 100644
index 0000000..0a8351e
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/package.properties
@@ -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. 
+
+bundle Bundle
+bundle.install Install new bundle
+
+bundle.start Bundle $\{symbolicName\} ($\{bundleId\}) started
+bundle.start.fail Can not start bundle, exception occured ${message}
+
+bundle.stop Bundle $\{symbolicName\} ($\{bundleId\}) stopped
+bundle.stop.fail Can not stop bundle, exception occured ${message}
+
+bundle.update Bundle $\{symbolicName\} ($\{bundleId\}) updated
+bundle.update.fail Can not update bundle: ${message}
+
+bundle.uninstall Bundle $\{symbolicName\} ($\{bundleId\}) uninstalled
+bundle.uninstall.fail Can not uninstall bundle, exception occured ${message}
+
+bundle.refresh Bundle $\{symbolicName\} ($\{bundleId\}) refreshed
+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