Add ActionsPanel, buttons in column Actions of Features table, Generate dynamically the content of the actionspanel according to component type, Change link in the Actions column according to status of features

git-svn-id: https://svn.apache.org/repos/asf/karaf/sandbox/pieber/karaf-webconsole/trunk@1159102 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/osgi/pom.xml b/osgi/pom.xml
index 51d49e2..881fad5 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -20,7 +20,11 @@
             <artifactId>org.apache.karaf.webconsole.core</artifactId>
             <version>${project.version}</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+            <version>2.2.2</version>
+        </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
@@ -69,6 +73,8 @@
                             <!-- and servlet api -->
                             javax.servlet,
                             javax.servlet.http
+                            <!-- karaf -->
+                            org.apache.karaf.features
                         </Import-Package>
                     </instructions>
                 </configuration>
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.java
new file mode 100644
index 0000000..4c12348
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.java
@@ -0,0 +1,32 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+public class ActionsPanel extends Panel {
+
+        private ComponentType type;
+        private IModel<?> model;
+        private static final String CONTENT_ID = "content";
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+
+            if (type.name() == "FEATURES") {
+                addOrReplace(getFeaturesActionsPanel());
+            }
+        }
+
+        public ActionsPanel(String componentId, final IModel<ExtendedFeature> model, ComponentType type) {
+            super(componentId, model);
+            this.type = type;
+            this.model = model;
+        }
+
+        private Component getFeaturesActionsPanel() {
+            return new FeaturesActionsPanel(CONTENT_ID,model);
+        }
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ComponentType.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ComponentType.java
new file mode 100644
index 0000000..9131945
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ComponentType.java
@@ -0,0 +1,5 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+public enum ComponentType {
+    FEATURES, BUNDLES, REPOSITORIES, EVENTS
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java
new file mode 100644
index 0000000..496c9fc
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/ExtendedFeature.java
@@ -0,0 +1,112 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Feature;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class extending Feature class to provide additional info
+ * like Repository name, ...
+ */
+class ExtendedFeature implements Feature, Serializable {
+
+    public enum State {
+        INSTALLED, UNINSTALLED;
+
+        @Override
+        public String toString() {
+            //only capitalize the first letter
+            String s = super.toString();
+            return s.substring(0, 1) + s.substring(1).toLowerCase();
+        }
+    }
+
+    protected State state;
+    protected String repository;
+    protected Feature feature;
+
+
+    //
+    // Constructors
+    //
+
+    public ExtendedFeature(State state, String repository, Feature feature) {
+        this.state = state;
+        this.repository = repository;
+        this.feature = feature;
+    }
+
+
+    //
+    // Feature interface
+    //
+
+
+    public List<BundleInfo> getBundles() {
+        return this.feature.getBundles();
+    }
+
+
+    public Map<String, Map<String, String>> getConfigurations() {
+        return this.feature.getConfigurations();
+    }
+
+    public List<ConfigFileInfo> getConfigurationFiles() {
+        return this.feature.getConfigurationFiles();
+    }
+
+    public String getId() {
+        return this.feature.getId();
+    }
+
+
+    public String getName() {
+        return this.feature.getName();
+    }
+
+
+    public String getVersion() {
+        return this.feature.getVersion();
+    }
+
+    public String getResolver() {
+        return this.feature.getResolver();
+    }
+
+    public List<Feature> getDependencies() {
+        return null;
+    }
+
+    public String getDescription() {
+        return this.feature.getDescription();
+    }
+
+    public String getDetails() {
+        return this.feature.getDetails();
+    }
+
+
+    //
+    // Additional methods
+    //
+
+
+    public String getRepository() {
+        return this.repository;
+    }
+
+
+    public State getState() {
+        return this.state;
+    }
+
+    public int getStartLevel() {
+        return 0;
+    }
+
+}
+
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.java
new file mode 100644
index 0000000..a6d6d7e
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.java
@@ -0,0 +1,88 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+
+public class FeaturesActionsPanel extends Panel {
+
+    @PaxWicketBean(name = "featuresService")
+    private FeaturesService featuresService;
+    private ExtendedFeature extendedFeature;
+
+    private static ResourceReference INSTALL_IMG = new ResourceReference(FeaturesActionsPanel.class, "images/feature_install.png");
+    private static ResourceReference UNINSTALL_IMG = new ResourceReference(FeaturesActionsPanel.class, "images/feature_uninstall.png");
+
+    public FeaturesActionsPanel(String componentId, IModel<?> model) {
+
+        super(componentId);
+
+        this.extendedFeature = (ExtendedFeature)model.getObject();
+
+        Link link = new Link("link") {
+
+            @Override
+            public void onClick() {
+
+                try {
+                    switch (extendedFeature.getState()) {
+                        case INSTALLED:
+                            featuresService.uninstallFeature(extendedFeature.getName());
+                            break;
+                        case UNINSTALLED:
+                            featuresService.installFeature(extendedFeature.getName());
+                            break;
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        };
+
+        add(link);
+
+        // add image to the link
+        link.add(new Image("actionButton", getImage(extendedFeature.getState())));
+
+
+    }
+
+
+    protected ResourceReference getImage(final ExtendedFeature.State action) {
+        final ResourceReference image;
+        switch (action) {
+            case INSTALLED :
+                image = UNINSTALL_IMG;
+                break;
+            case UNINSTALLED :
+                image = INSTALL_IMG;
+                break;
+            default:
+                image = INSTALL_IMG;
+                break;
+        }
+
+        return image;
+    }
+
+    /*
+
+             SubmitLink removeLink = new SubmitLink("install", form) {
+                 @Override
+                 public void onSubmit()
+                 {
+                     ExtendedFeature extendedFeature = (ExtendedFeature)ActionPanel.this.getDefaultModelObject();
+                     info("Install feature" + extendedFeature);
+                     // call features service
+                 }
+             };
+             removeLink.setDefaultFormProcessing(false);
+             add(removeLink);*/
+
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java
new file mode 100644
index 0000000..3d17514
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.java
@@ -0,0 +1,118 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+import java.util.*;
+
+/**
+ * Features
+ */
+public class FeaturesPage extends BasePage {
+
+    @PaxWicketBean(name = "featuresService")
+    private FeaturesService featuresService;
+
+    public FeaturesPage() throws Exception {
+
+        // Create a form for external Submit link
+        Form<?> form = new Form("form");
+
+        Repository[] repositories = featuresService.listRepositories();
+        Feature[] features;
+        List<ExtendedFeature> model = new ArrayList<ExtendedFeature>();
+
+        for (Repository r : repositories) {
+            features = r.getFeatures();
+            for (Feature f : features) {
+                ExtendedFeature.State state =
+                        featuresService.isInstalled(f) ? ExtendedFeature.State.INSTALLED : ExtendedFeature.State.UNINSTALLED;
+                ExtendedFeature extendedFeature = new ExtendedFeature(state, r.getName(), f);
+
+                // add extended feature to Wicket model
+                model.add(extendedFeature);
+            }
+        }
+
+
+        IModel state = Model.of("state");
+        IModel version = Model.of("version");
+        IModel name = Model.of("name");
+        IModel repository = Model.of("repository");
+        IModel description = Model.of("description");
+
+        List<IColumn<ExtendedFeature>> columns = new ArrayList<IColumn<ExtendedFeature>>();
+        columns.add(new PropertyColumn<ExtendedFeature>(new StringResourceModel("table.version", this, version), "version", "version"));
+        columns.add(new PropertyColumn<ExtendedFeature>(new StringResourceModel("table.name", this, state), "name", "name"));
+        columns.add(new PropertyColumn<ExtendedFeature>(new StringResourceModel("table.repository", this, repository), "repository", "repository"));
+        columns.add(new PropertyColumn<ExtendedFeature>(new StringResourceModel("table.description", this, description), "description", "description"));
+        columns.add(new PropertyColumn<ExtendedFeature>(new StringResourceModel("table.state", this, state), "state", "state"));
+        columns.add(new AbstractColumn<ExtendedFeature>(new ResourceModel("table.actions")) {
+            public void populateItem(Item<ICellPopulator<ExtendedFeature>> cellItem, String componentId, IModel<ExtendedFeature> model) {
+               cellItem.add(new ActionsPanel(componentId, model, ComponentType.FEATURES));
+            }
+        });
+
+        add(new DefaultDataTable<ExtendedFeature>("features", columns, new FeaturesProvider(model), 20));
+
+    }
+
+
+    static class FeaturesProvider extends SortableDataProvider<ExtendedFeature> {
+
+        List<ExtendedFeature> model;
+
+        public FeaturesProvider(List model) {
+            this.model = model;
+            setSort("name", true);
+        }
+
+        public Iterator<? extends ExtendedFeature> iterator(int first, int count) {
+            List<ExtendedFeature> data = new ArrayList<ExtendedFeature>(model);
+            Collections.sort(data, new Comparator<ExtendedFeature>() {
+
+                public int compare(ExtendedFeature o1, ExtendedFeature o2) {
+                    int dir = getSort().isAscending() ? 1 : -1;
+
+                    if ("name".equals(getSort().getProperty())) {
+                        return dir * (o1.getName().compareTo(o2.getName()));
+                    } else if ("repository".equals(getSort().getProperty())) {
+                        return dir * (o1.getRepository().compareTo(o2.getRepository()));
+                    } else if ("state".equals(getSort().getProperty())) {
+                        return dir * (o1.getState().compareTo(o2.getState()));
+                    } else {
+                        return dir * (o1.getName().compareTo(o2.getName()));
+                    }
+                }
+            });
+            return data.subList(first, Math.min(first + count, data.size()))
+                    .iterator();
+        }
+
+        public int size() {
+            return model.size();
+        }
+
+        public IModel<ExtendedFeature> model(ExtendedFeature object) {
+            return Model.of(object);
+        }
+
+    }
+
+
+}
diff --git a/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.java b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.java
new file mode 100644
index 0000000..a332624
--- /dev/null
+++ b/osgi/src/main/java/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.java
@@ -0,0 +1,48 @@
+package org.apache.karaf.webconsole.osgi.internal;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+
+public class UninstallFeaturesPanel extends Panel {
+
+        private FeaturesService featuresService;
+
+        public UninstallFeaturesPanel(String id, final IModel<ExtendedFeature> model, final FeaturesService featuresService) {
+
+            super(id, model);
+
+            Link link = new Link("uninstall") {
+
+                @Override
+                public void onClick() {
+                    try {
+                        featuresService.uninstallFeature(model.getObject().getName());
+                    } catch (Exception e) {
+                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                    }
+                }
+            };
+
+            // add image to the link
+            link.add(new Image("featuresUninstallButton", new ResourceReference(this.getClass(), "images/feature_uninstall.png")));
+
+            /*SubmitLink removeLink = new SubmitLink("install", form) {
+				@Override
+				public void onSubmit()
+				{
+					ExtendedFeature extendedFeature = (ExtendedFeature)ActionPanel.this.getDefaultModelObject();
+					info("Install feature" + extendedFeature);
+					// call features service
+				}
+			};
+			removeLink.setDefaultFormProcessing(false);
+			add(removeLink);*/
+
+        }
+
+}
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.html
new file mode 100644
index 0000000..5646616
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/ActionsPanel.html
@@ -0,0 +1,3 @@
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <div wicket:id="content"></div>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.html
new file mode 100644
index 0000000..b4bcf7a
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesActionsPanel.html
@@ -0,0 +1,5 @@
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <a href="#" wicket:id="link">
+        <img wicket:id="actionButton" alt="feature install button"/>
+    </a>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html
new file mode 100644
index 0000000..9e47d5d
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.html
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <wicket:head>
+        <title>Karaf Wicket console - Features page</title>
+    </wicket:head>
+
+    <body>
+        <wicket:extend>
+            <h1>Features</h1>
+            <table wicket:id="features" class="dataview"/>
+        </wicket:extend>
+    </body>
+</html>
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.properties b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.properties
new file mode 100644
index 0000000..6b7f57b
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage.properties
@@ -0,0 +1,7 @@
+# Features properties
+table.state = state
+table.name = Name
+table.version = Version
+table.repository = Repository
+table.description = Description
+table.actions = Actions
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_de.properties b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_de.properties
new file mode 100644
index 0000000..5b80cef
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_de.properties
@@ -0,0 +1,7 @@
+# Features properties
+table.state = Status
+table.name = Name
+table.version = Version
+table.repository = Repository
+table.description = Beschreibung
+table.actions = Actions
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_fr.properties b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_fr.properties
new file mode 100644
index 0000000..fc660f0
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/FeaturesPage_fr.properties
@@ -0,0 +1,7 @@
+# PropriŽtŽs des Features
+table.state = Etat
+table.name = Nom
+table.version = Version
+table.repository = R\u00E9pertoire
+table.description = Description
+table.actions = Actions
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.html b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.html
new file mode 100644
index 0000000..c0aaa8f
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/UninstallFeaturesPanel.html
@@ -0,0 +1,5 @@
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <a href="#" wicket:id="uninstall">
+        <img wicket:id="featuresUninstallButton" alt="feature uninstall button"/>
+    </a>
+</wicket:panel>
\ No newline at end of file
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_install.png b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_install.png
new file mode 100644
index 0000000..f8c8ec6
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_install.png
Binary files differ
diff --git a/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_uninstall.png b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_uninstall.png
new file mode 100644
index 0000000..2bd4963
--- /dev/null
+++ b/osgi/src/main/resources/org/apache/karaf/webconsole/osgi/internal/images/feature_uninstall.png
Binary files differ