FELIX-574 Start replacing Action and Render interfaces by Servlet interface:
   * Add new AbstractWebConsolePlugin which implementations may extend from
   * Add RenderBridge to register old-style Render as Servlet
FELIX-566 Convert Bundle handling to REST-style

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@662438 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/resources/res/ui/admin.css b/webconsole/src/main/resources/res/ui/admin.css
index 984d9a0..fdb5084 100644
--- a/webconsole/src/main/resources/res/ui/admin.css
+++ b/webconsole/src/main/resources/res/ui/admin.css
@@ -43,7 +43,7 @@
     */
     margin: 0px;
     padding: 5px 0 0 8px;
-    font-size: 400%;
+    font-size: 300%;
     font-weight: bold;
     line-height: 120%;
     height: 95px;
diff --git a/webconsole/src/main/resources/res/ui/bundles.js b/webconsole/src/main/resources/res/ui/bundles.js
new file mode 100644
index 0000000..537577f
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/bundles.js
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function render(/* int */ startlevel, /* Array of Bundle Object */ bundles)
+{
+
+    header();
+
+    installForm( startlevel );
+    
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='7' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    tableHeader();
+
+    if ( !bundles )
+    {
+        document.write( "<tr class='content'>" );
+        document.write( "<td class='content' colspan='6'>No Bundles installed currently</td>" );
+        document.write( "</tr>" );
+    }
+    else
+    {
+        for ( var i = 0; i < bundles.length; i++ )
+        {
+            bundle( bundles[i] );
+        }
+    }
+
+    document.write( "<tr class='content'>" );
+    document.write( "<td colspan='7' class='content'>&nbsp;</th>" );
+    document.write( "</tr>" );
+
+    installForm( startlevel );
+
+    footer();
+}
+
+
+function header()
+{
+    document.write( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
+}
+
+
+function tableHeader()
+{
+    document.write( "<tr class='content'>" );
+    document.write( "<th class='content'>ID</th>" );
+    document.write( "<th class='content' width='100%'>Name</th>" );
+    document.write( "<th class='content'>Status</th>" );
+    document.write( "<th class='content' colspan='4'>Actions</th>" );
+    document.write( "</tr>" );
+}
+
+
+function footer()
+{
+    document.write( "</table>" );
+}
+
+
+function bundle( /* Bundle */ bundle )
+{  
+    document.write( "<tr id='bundle" + bundle.bundleId + "'>" );
+    document.write( bundleInternal( bundle ) );
+    document.write( "</tr>" );
+    document.write( "<tr id='bundle" + bundle.bundleId + "_details'>" );
+    if (bundle.props)
+    {
+        document.write( bundleDetails( bundle.props ) );
+    }
+    document.write( "</tr>" );
+}
+
+   
+/* String */ function bundleInternal( /* Bundle */ bundle )
+{
+    var theBundle = "<td class='content right'>" + bundle.bundleId + "</td>";
+    theBundle += "<td class='content'><a href='javascript:showDetails(" + bundle.bundleId + ")'>" + bundle.name + "</a></td>";
+    theBundle += "<td class='content center'>" + bundle.state + "</td>";
+
+    // no buttons for system bundle
+    if ( bundle.bundleId == 0 )
+    {
+        theBundle += "<td class='content' colspan='4'>&nbsp;</td>";
+    }
+    else
+    {
+        theBundle += actionForm( bundle.hasStart, bundle.bundleId, "start", "Start" );
+        theBundle += actionForm( bundle.hasStop, bundle.bundleId, "stop", "Stop" );
+        theBundle += actionForm( bundle.hasUpdate, bundle.bundleId, "update", "Update" );
+        theBundle += actionForm( bundle.hasUninstall, bundle.bundleId, "uninstall", "Uninstall" );
+    }
+
+    return theBundle;
+}
+
+
+/* String */ function actionForm( /* boolean */ enabled, /* long */ bundleId, /* String */ action, /* String */ actionLabel )
+{
+    var theButton = "<td class='content' align='right'>";
+    theButton += "<input class='submit' type='button' value='" + actionLabel + "'" + ( enabled ? "" : "disabled" ) + " onClick='changeBundle(" + bundleId + ", \"" + action + "\");' />";
+    theButton += "</td>";
+    return theButton;
+}
+
+
+function installForm( /* int */ startLevel )
+{
+    document.write( "<form method='post' enctype='multipart/form-data'>" );
+    document.write( "<tr class='content'>" );
+    document.write( "<td class='content'>&nbsp;</td>" );
+    document.write( "<td class='content'>" );
+    document.write( "<input type='hidden' name='action' value='install' />" );
+    document.write( "<input class='input' type='file' name='bundlefile'>" );
+    document.write( " - Start <input class='checkradio' type='checkbox' name='bundlestart' value='start'>" );
+    document.write( " - Start Level <input class='input' type='input' name='bundlestartelevel' value='" + startLevel + "' width='4'>" );
+    document.write( "</td>" );
+    document.write( "<td class='content' align='right' colspan='5' noWrap>" );
+    document.write( "<input class='submit' style='width:auto' type='submit' value='Install or Update'>" );
+    document.write( "&nbsp;" );
+    document.write( "<input class='submit' style='width:auto' type='submit' value='Refresh Packages' onClick='this.form.action.value=\"refreshPackages\"; return true;'>" );
+    document.write( "</td>" );
+    document.write( "</tr>" );
+    document.write( "</form>" );
+}
+
+
+function changeBundle(/* long */ bundleId, /* String */ action)
+{
+    var parm = "bundles/" + bundleId + "?action=" + action;
+    sendRequest('POST', parm, bundleChanged);
+}
+
+    
+function bundleChanged(obj)
+{
+    var bundleId = obj.bundleId;
+    if (obj.state)
+    {
+        // has status, so draw the line
+        var span = document.getElementById('bundle' + bundleId);
+        if (span)
+        {
+            span.innerHTML = bundleInternal( obj );
+        }
+        
+        if (obj.props)
+        {
+            var span = document.getElementById('bundle' + bundleId + '_details');
+            if (span && span.innerHTML)
+            {
+                span.innerHTML = bundleDetails( obj.props );
+            }
+        }
+        
+    }
+    else
+    {
+        // no status, bundle has been uninstalled
+        var span = document.getElementById('bundle' + bundleId);
+        if (span)
+        {
+            span.parentNode.removeChild(span);
+        }
+        var span = document.getElementById('bundle' + bundleId + '_details');
+        if (span)
+        {
+            span.parentNode.removeChild(span);
+        }
+    }
+    
+    // reload --- should do better and only update the bundle
+    // document.location = document.location;
+}
+
+    
+function showDetails(bundleId) {
+    var span = document.getElementById('bundle' + bundleId + '_details');
+    if (span)
+    {
+        if (span.innerHTML)
+        {
+            span.innerHTML = '';
+        }
+        else
+        {
+            sendRequest('GET', "bundles/" + bundleId + ".json", displayBundleDetails);
+        }
+    }
+}
+
+
+function displayBundleDetails(obj) {
+    var span = document.getElementById('bundle' + obj.bundleId + '_details');
+    if (span)
+    {
+        span.innerHTML = bundleDetails( obj.props );
+    }
+}
+
+
+/* String */ function bundleDetails( props )
+{
+        var innerHtml = '<td class=\"content\">&nbsp;</td><td class=\"content\" colspan=\"6\"><table broder=\"0\">';
+        for (var i=0; i < props.length; i++)
+        {
+            innerHtml += '<tr><td valign=\"top\" noWrap>' + props[i].key + '</td><td valign=\"top\">' + props[i].value + '</td></tr>';
+        }
+        innerHtml += '</table></td>';
+        
+        return innerHtml;
+}
+