Bundle installation form/page.

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1243483 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/behavior/RemoveAttributeBehavior.java b/core/src/main/java/org/apache/karaf/webconsole/core/behavior/RemoveAttributeBehavior.java
new file mode 100644
index 0000000..84054d1
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/behavior/RemoveAttributeBehavior.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.behavior;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.AbstractBehavior;
+import org.apache.wicket.markup.ComponentTag;
+
+/**
+ * Simple behavior to remove some attributes from output markup.
+ */
+public class RemoveAttributeBehavior extends AbstractBehavior {
+
+    private static final long serialVersionUID = 1L;
+
+    private String attribute;
+
+    public RemoveAttributeBehavior(String attribute) {
+        this.attribute = attribute;
+    }
+
+    public void onComponentTag(Component component, ComponentTag tag) {
+        tag.getAttributes().remove(attribute);
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/form/LabelBorder.java b/core/src/main/java/org/apache/karaf/webconsole/core/form/LabelBorder.java
index e56dfe7..22ed228 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/form/LabelBorder.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/form/LabelBorder.java
@@ -20,6 +20,8 @@
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.border.Border;
 import org.apache.wicket.markup.html.form.FormComponent;
+import org.apache.wicket.markup.html.form.SimpleFormComponentLabel;
+import org.apache.wicket.markup.html.panel.ComponentFeedbackPanel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 
@@ -28,18 +30,14 @@
     private static final long serialVersionUID = 1L;
     private final FormComponent<?> component;
 
-    public LabelBorder(String id, String fieldLabel, FormComponent<?> component) {
-        this(id, Model.of(fieldLabel), component);
-    }
-
-    public LabelBorder(String id, IModel<?> fieldLabel, FormComponent<?> component) {
+    public LabelBorder(String id, FormComponent<?> component) {
         super(id);
         this.component = component;
         getBodyContainer().add(component);
 
-        add(new Label("label", fieldLabel).setRenderBodyOnly(true));
+        add(new SimpleFormComponentLabel("label", component));
         add(new Label("help", ""));
-        add(new Label("error", ""));
+        add(new ComponentFeedbackPanel("error", component));
     }
 
     public void setHelp(String message) {
@@ -55,7 +53,6 @@
         super.onBeforeRender();
 
         if (component.getFeedbackMessage() != null) {
-            addOrReplace(new Label("error", "" + component.getFeedbackMessage().getMessage()));
             add(new AttributeAppender("class", Model.of("error"), " "));
         }
     }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/form/MapEditForm.java b/core/src/main/java/org/apache/karaf/webconsole/core/form/MapEditForm.java
index 90568cf..7f707ee 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/form/MapEditForm.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/form/MapEditForm.java
@@ -16,6 +16,8 @@
  */
 package org.apache.karaf.webconsole.core.form;
 
+import static org.apache.wicket.model.Model.of;
+
 import java.util.Map;
 
 import org.apache.wicket.Component;
@@ -48,13 +50,10 @@
         add(repeatingView);
     }
 
-    @SuppressWarnings("unchecked")
     protected Component populateItem(String componentId, K key, IModel<V> value) {
-        FormComponent<V> field = new TextField<V>("value", value, (Class<V>) value.getObject().getClass());
-        LabelBorder border = new LabelBorder(componentId, ""+ key, field);
-//        border.add(new Label("label", "" + key));
-//        border.add();
-        border.setHelp("Value for " + key);
+        FormComponent<V> field = new TextField<V>("value", value);
+        field.setLabel(of(key.toString()));
+        LabelBorder border = new LabelBorder(componentId, field);
         return border;
     }
 }
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/form/LabelBorder.html b/core/src/main/resources/org/apache/karaf/webconsole/core/form/LabelBorder.html
index 7ed52cb..62c8e6e 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/form/LabelBorder.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/form/LabelBorder.html
@@ -16,9 +16,7 @@
    limitations under the License.
 -->
 <wicket:border xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <label class="control-label">
-        <span wicket:id="label"></span>
-    </label>
+    <label class="control-label" wicket:id="label"></label>
     <div class="controls">
         <wicket:body />
         <span wicket:id="help" class="help-inline"></span>
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.java
new file mode 100644
index 0000000..e34d372
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.java
@@ -0,0 +1,46 @@
+/*
+ * 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.install;
+
+import static org.apache.wicket.model.Model.of;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.model.IModel;
+import org.ops4j.pax.wicket.api.PaxWicketMountPoint;
+
+/**
+ * Page with bundle installation form.
+ */
+@PaxWicketMountPoint(mountPoint = "/osgi/bundle/add")
+public class InstallBundlePage extends OsgiPage {
+
+    public InstallBundlePage() {
+        IModel<WicketInstallModel> model = of(new WicketInstallModel());
+
+        Form<WicketInstallModel> form = new Form<WicketInstallModel>("install", model);
+        form.add(new InstallBundlePanel("bundle", model));
+
+        form.add(new InstallBundleSubmitLink("confirm"));
+        form.add(new BookmarkablePageLink<BundlePage>("cancel", BundlePage.class));
+
+        add(form);
+    }
+
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.java
new file mode 100644
index 0000000..a5c6c69
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.java
@@ -0,0 +1,90 @@
+/*
+ * 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.install;
+
+import static org.apache.wicket.model.Model.of;
+
+import org.apache.karaf.webconsole.core.behavior.RemoveAttributeBehavior;
+import org.apache.karaf.webconsole.core.form.LabelBorder;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.RequiredTextField;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+
+/**
+ * Bundle installation form wrapper.
+ */
+public class InstallBundlePanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+    private TextField<String> location;
+    private CheckBox upload;
+    private FileUploadField file;
+
+    public InstallBundlePanel(String id, IModel<WicketInstallModel> model) {
+        super(id);
+
+        Form<WicketInstallModel> form = new Form<WicketInstallModel>("form", new CompoundPropertyModel<WicketInstallModel>(model));
+        location = new RequiredTextField<String>("location");
+        location.setLabel(of("Bundle location"));
+        LabelBorder border = new LabelBorder("locationGroup", location);
+        form.add(border);
+
+        upload = new AjaxCheckBox("upload") {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onUpdate(AjaxRequestTarget target) {
+                if (target != null) {
+                    if (upload.getModelObject()) {
+                        onChecked();
+                    } else {
+                        onUnchecked();
+                    }
+                    target.addComponent(file);
+                }
+            }
+        };
+        upload.setLabel(of("Specify file to install"));
+        border = new LabelBorder("uploadGroup", upload);
+        form.add(border);
+
+        file = new FileUploadField("file");
+        file.setLabel(of("Bundle file"));
+        file.add(new SimpleAttributeModifier("disabled", "disabled"));
+        file.setOutputMarkupId(true);
+        border = new LabelBorder("fileGroup", file);
+        form.add(border);
+
+        add(form);
+    }
+
+    protected void onChecked() {
+        file.add(new RemoveAttributeBehavior("disabled"));
+    }
+
+    protected void onUnchecked() {
+        file.add(new SimpleAttributeModifier("disabled", "disabled"));
+    }
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundleSubmitLink.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundleSubmitLink.java
new file mode 100644
index 0000000..e5285c8
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundleSubmitLink.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle.install;
+
+import org.apache.karaf.webconsole.osgi.core.bundle.list.BundlePage;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.form.SubmitLink;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Bundle installation link. Requires form with {@link WicketInstallModel}.
+ */
+public class InstallBundleSubmitLink extends SubmitLink {
+    private static final long serialVersionUID = 1L;
+
+    @PaxWicketBean(name = "blueprintBundleContext")
+    private BundleContext context;
+
+    private transient Logger logger = LoggerFactory.getLogger(InstallBundleSubmitLink.class);
+
+    public InstallBundleSubmitLink(String id) {
+        super(id);
+    }
+
+    @Override
+    public void onSubmit() {
+        WicketInstallModel modelObject = (WicketInstallModel) getForm().getModelObject();
+
+        try {
+            if (modelObject.isUpload()) {
+                context.installBundle(modelObject.getLocation(), modelObject.getInputStream());
+            } else {
+                context.installBundle(modelObject.getLocation());
+            }
+            Session.get().info("Bundle " + modelObject.getLocation() + " installed");
+            RequestCycle.get().setResponsePage(BundlePage.class);
+        } catch (Exception e) {
+            logger.error("Error during installation", e);
+            Session.get().error("Can not install bundle " + e.getMessage());
+        }
+    }
+}
diff --git a/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/WicketInstallModel.java b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/WicketInstallModel.java
new file mode 100644
index 0000000..2c7e3e4
--- /dev/null
+++ b/osgi/core/src/main/java/org/apache/karaf/webconsole/osgi/core/bundle/install/WicketInstallModel.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.osgi.core.bundle.install;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+
+/**
+ * Model for installation form.
+ */
+public class WicketInstallModel implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String location;
+    private boolean upload = false;
+    private FileUpload file;
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public boolean isUpload() {
+        return upload;
+    }
+
+    public void setUpload(boolean upload) {
+        this.upload = upload;
+    }
+
+    public void setFile(FileUpload file) {
+        this.file = file;
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return file.getInputStream();
+    }
+
+}
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 589003c..ea31a27 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
@@ -22,17 +22,20 @@
 import java.util.List;
 
 import org.apache.karaf.webconsole.core.table.PropertyColumnExt;
+import org.apache.karaf.webconsole.osgi.core.bundle.install.InstallBundlePage;
 import org.apache.karaf.webconsole.osgi.core.shared.BundleDataProvider;
 import org.apache.karaf.webconsole.osgi.core.shared.OsgiPage;
 import org.apache.karaf.webconsole.osgi.core.shared.State;
 import org.apache.karaf.webconsole.osgi.core.spi.IActionProvider;
 import org.apache.karaf.webconsole.osgi.core.spi.IColumnProvider;
 import org.apache.karaf.webconsole.osgi.core.spi.IDecorationProvider;
+import org.apache.wicket.Page;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
@@ -90,6 +93,8 @@
         });
 
         add(new DefaultDataTable<Bundle>("bundles", columns, new BundleDataProvider(context), 100));
+
+        add(new BookmarkablePageLink<Page>("install", InstallBundlePage.class));
     }
 
 }
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.html
new file mode 100644
index 0000000..507e6b6
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePage.html
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <h1>Install bundle</h1>
+
+    <form wicket:id="install">
+        <div wicket:id="bundle">
+        </div>
+
+        <div class="form-actions">
+            <button type="submit" class="btn btn-primary" wicket:id="confirm">Install</button>
+            <a class="btn" wicket:id="cancel">Cancel</a>
+        </div>
+    </form>
+</wicket:extend>
\ No newline at end of file
diff --git a/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.html b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.html
new file mode 100644
index 0000000..aeaeb4f
--- /dev/null
+++ b/osgi/core/src/main/resources/org/apache/karaf/webconsole/osgi/core/bundle/install/InstallBundlePanel.html
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <form wicket:id="form">
+        <fieldset>
+            <legend>Install bundle</legend>
+
+            <div wicket:id="locationGroup" class="control-group">
+                <input type="text" class="span8" wicket:id="location" />
+            </div>
+            <div wicket:id="uploadGroup" class="control-group">
+                <input type="checkbox" wicket:id="upload" />
+            </div>
+            <div wicket:id="fileGroup" class="control-group">
+               <input type="file" wicket:id="file" />
+            </div>
+        </fieldset>
+    </form>
+</wicket:panel>
\ No newline at end of file
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 c8651f3..b982ead 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
@@ -16,8 +16,19 @@
    limitations under the License.
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <h1>Bundles</h1>
+    <div class="row-fluid">
+        <h1 class="pull-left">Bundles</h1>
 
-    <table wicket:id="bundles" class="table table-striped table-condensed" />
+        <div class="btn-group pull-right">
+            <a class="btn btn-primary" wicket:id="install">
+                <i class="icon-plus icon-white"></i>
+                Install bundle
+            </a>
+        </div>
+    </div>
+
+    <div class="row-fluid">
+        <table wicket:id="bundles" class="table table-striped table-condensed" />
+    </div>
 
 </wicket:extend>