FELIX-1988 Apply 12.bundles_plugin.patch by Valentin Valchev (thanks)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@911439 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
index 007a6e6..2a1df16 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
@@ -17,42 +17,70 @@
package org.apache.felix.webconsole.internal.core;
-import java.io.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
import java.text.MessageFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.bundlerepository.*;
+import org.apache.felix.bundlerepository.R4Attribute;
+import org.apache.felix.bundlerepository.R4Export;
+import org.apache.felix.bundlerepository.R4Import;
+import org.apache.felix.bundlerepository.R4Package;
import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.felix.webconsole.WebConsoleUtil;
-import org.apache.felix.webconsole.internal.*;
import org.apache.felix.webconsole.internal.Logger;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
import org.apache.felix.webconsole.internal.Util;
-import org.json.*;
-import org.osgi.framework.*;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentConstants;
-import org.osgi.service.log.LogService;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.startlevel.StartLevel;
/**
- * The <code>BundlesServlet</code> TODO
+ * The <code>BundlesServlet</code> provides the bundles plugins, used to display
+ * the list of bundles, installed on the framework. It also adds ability to control
+ * the lifecycle of the bundles, like start, stop, uninstall, install.
*/
-public class BundlesServlet extends BaseWebConsolePlugin implements ConfigurationPrinter
+public class BundlesServlet extends SimpleWebConsolePlugin implements OsgiManagerPlugin, ConfigurationPrinter
{
+ /** the label of the bundles plugin - used by other plugins to reference to plugin details */
public static final String NAME = "bundles";
-
- public static final String LABEL = "Bundles";
-
- public static final String BUNDLE_ID = "bundleId";
+ private static final String TITLE = "Bundles";
+ private static final String CSS[] = { "/res/ui/bundles.css" };
// bootdelegation property entries. wildcards are converted to package
// name prefixes. whether an entry is a wildcard or not is set as a flag
@@ -66,7 +94,24 @@
private boolean[] bootPkgWildcards;
private ServiceRegistration configurationPrinter;
+
+ // templates
+ private final String TEMPLATE_MAIN;
+ private final String TEMPLATE_UPLOAD;
+ /** Default constructor */
+ public BundlesServlet()
+ {
+ super(NAME, TITLE, CSS);
+
+ // load templates
+ TEMPLATE_MAIN = readTemplateFile( "/templates/bundles.html" );
+ TEMPLATE_UPLOAD = readTemplateFile( "/templates/bundles_upload.html" );
+ }
+
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#activate(org.osgi.framework.BundleContext)
+ */
public void activate( BundleContext bundleContext )
{
super.activate( bundleContext );
@@ -92,6 +137,9 @@
}
+ /**
+ * @see org.apache.felix.webconsole.SimpleWebConsolePlugin#deactivate()
+ */
public void deactivate()
{
if ( configurationPrinter != null )
@@ -104,20 +152,11 @@
}
- public String getLabel()
- {
- return NAME;
- }
-
-
- public String getTitle()
- {
- return LABEL;
- }
-
-
//---------- ConfigurationPrinter
+ /**
+ * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)
+ */
public void printConfiguration( PrintWriter pw )
{
try
@@ -175,13 +214,16 @@
}
catch ( Exception e )
{
- getLog().log( LogService.LOG_ERROR, "Problem rendering Bundle details for configuration status", e );
+ log( "Problem rendering Bundle details for configuration status", e );
}
}
//---------- BaseWebConsolePlugin
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException
{
@@ -209,6 +251,9 @@
super.doGet( request, response );
}
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
{
final RequestInfo reqInfo = new RequestInfo(req);
@@ -239,7 +284,7 @@
}
catch ( BundleException be )
{
- getLog().log( LogService.LOG_ERROR, "Cannot start", be );
+ log( "Cannot start", be );
}
}
else if ( "stop".equals( action ) )
@@ -252,7 +297,7 @@
}
catch ( BundleException be )
{
- getLog().log( LogService.LOG_ERROR, "Cannot stop", be );
+ log( "Cannot stop", be );
}
}
else if ( "refresh".equals( action ) )
@@ -278,7 +323,7 @@
}
catch ( BundleException be )
{
- getLog().log( LogService.LOG_ERROR, "Cannot uninstall", be );
+ log( "Cannot uninstall", be );
}
}
}
@@ -314,7 +359,7 @@
"/" + ServicesServlet.LABEL + "/";
}
- private Bundle getBundle( String pathInfo )
+ Bundle getBundle( String pathInfo )
{
// only use last part of the pathInfo
pathInfo = pathInfo.substring( pathInfo.lastIndexOf( '/' ) + 1 );
@@ -373,53 +418,39 @@
buf.append(msg);
}
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
// get request info from request attribute
final RequestInfo reqInfo = getRequestInfo(request);
- final PrintWriter pw = response.getWriter();
- final String appRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_APP_ROOT );
+ final int startLevel = getStartLevel().getInitialBundleStartLevel();
- Util.startScript( pw );
- pw.println( "var imgRoot = '" + appRoot + "/res/imgs';");
- pw.println( "var startLevel = " + getStartLevel().getInitialBundleStartLevel() + ";");
- pw.println( "var drawDetails = " + reqInfo.bundleRequested + ";");
- pw.println( "var currentBundle = " + (reqInfo.bundleRequested && reqInfo.bundle != null ? String.valueOf(reqInfo.bundle.getBundleId()) : "null") + ";");
- Util.endScript( pw );
-
- Util.script(pw, appRoot, "bundles.js");
+ // prepare variables
+ DefaultVariableResolver vars = ( ( DefaultVariableResolver ) WebConsoleUtil.getVariableResolver( request ) );
+ vars.put( "startLevel", String.valueOf(startLevel));
+ vars.put( "drawDetails", reqInfo.bundleRequested ? Boolean.TRUE : Boolean.FALSE );
+ vars.put( "currentBundle", (reqInfo.bundleRequested && reqInfo.bundle != null ? String.valueOf(reqInfo.bundle.getBundleId()) : "null"));
if ( "upload".equals(reqInfo.pathInfo) )
{
- renderUploadForm(pw, appRoot);
+ response.getWriter().print(TEMPLATE_UPLOAD);
}
else
{
- pw.println( "<div id='plugin_content'/>");
- Util.startScript( pw );
- pw.print( "renderBundles(");
final String pluginRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT );
final String servicesRoot = getServicesRoot ( request );
- writeJSON(pw, reqInfo.bundle, pluginRoot, servicesRoot );
- pw.println(");" );
- Util.endScript( pw );
+ StringWriter w = new StringWriter();
+ PrintWriter w2 = new PrintWriter(w);
+ writeJSON(w2, reqInfo.bundle, pluginRoot, servicesRoot );
+ vars.put( "__bundles__", w.toString());
+
+ response.getWriter().print(TEMPLATE_MAIN);
}
}
- private void renderUploadForm( final PrintWriter pw, final String appRoot ) throws IOException
- {
- Util.script(pw, appRoot, "jquery.multifile-1.4.6.min.js");
- pw.println(" <div id='plugin_content'><div class='contentheader'>Upload / Install Bundles</div>");
- pw.println( "<form method='post' enctype='multipart/form-data' action='../'>");
- pw.println( "<input type='hidden' name='action' value='install'/>");
- pw.println( "<div class='contentline'><div class='contentleft'>Start Bundle</div><div class='contentright'><input class='checkradio' type='checkbox' name='bundlestart' value='start'/></div></div>");
- pw.println( "<div class='contentline'><div class='contentleft'>Start Level</div><div class='contentright'><input class='input' type='input' name='bundlestartlevel' value='" + getStartLevel().getInitialBundleStartLevel() + "' size='4'/></div></div>");
- pw.println( "<div class='contentline'><input class='fileinput multi' accept='jar' type='file' name='bundlefile'/></div>");
- pw.println( "<div class='contentline'><input type='submit' value='Install or Update'/></div>");
- pw.println( "</form></div");
- }
-
private void renderJSON( final HttpServletResponse response, final Bundle bundle, final String pluginRoot, final String servicesRoot )
throws IOException
{
@@ -442,7 +473,8 @@
final String servicesRoot, final boolean fullDetails ) throws IOException
{
final Bundle[] allBundles = this.getBundles();
- final String statusLine = this.getStatusLine(allBundles);
+ final Object[] status = getStatusLine(allBundles);
+ final String statusLine = (String) status[5];
final Bundle[] bundles = ( bundle != null ) ? new Bundle[]
{ bundle } : allBundles;
Util.sort( bundles );
@@ -455,6 +487,12 @@
jw.key( "status" );
jw.value( statusLine );
+
+ // add raw status
+ jw.key( "s" );
+ jw.array();
+ for ( int i = 0; i < 5; i++ ) jw.value(status[i]);
+ jw.endArray();
jw.key( "data" );
@@ -477,8 +515,9 @@
}
- private String getStatusLine(final Bundle[] bundles)
+ private Object[] getStatusLine(final Bundle[] bundles)
{
+ Object[] ret = new Object[6];
int active = 0, installed = 0, resolved = 0, fragments = 0;
for ( int i = 0; i < bundles.length; i++ )
{
@@ -534,7 +573,13 @@
}
buffer.append('.');
}
- return buffer.toString();
+ ret[0] = new Integer(bundles.length);
+ ret[1] = new Integer(active);
+ ret[2] = new Integer(fragments);
+ ret[3] = new Integer(resolved);
+ ret[4] = new Integer(installed);
+ ret[5] = buffer.toString();
+ return ret;
}
private void bundleInfo( JSONWriter jw, Bundle bundle, boolean details, final String pluginRoot, final String servicesRoot )
@@ -580,7 +625,7 @@
}
- protected Bundle[] getBundles()
+ private final Bundle[] getBundles()
{
return getBundleContext().getBundles();
}
@@ -622,12 +667,12 @@
jw.endObject();
}
- private boolean isFragmentBundle( Bundle bundle)
+ private final boolean isFragmentBundle( Bundle bundle)
{
return getPackageAdmin().getBundleType( bundle ) == PackageAdmin.BUNDLE_TYPE_FRAGMENT;
}
- private boolean hasStart( Bundle bundle )
+ private final boolean hasStart( Bundle bundle )
{
if ( isFragmentBundle(bundle) )
{
@@ -637,7 +682,7 @@
}
- private boolean hasStop( Bundle bundle )
+ private final boolean hasStop( Bundle bundle )
{
if ( isFragmentBundle(bundle) )
{
@@ -647,7 +692,7 @@
}
- private boolean hasUninstall( Bundle bundle )
+ private static final boolean hasUninstall( Bundle bundle )
{
return bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.RESOLVED
|| bundle.getState() == Bundle.ACTIVE;
@@ -655,7 +700,7 @@
}
- private void bundleDetails( JSONWriter jw, Bundle bundle, final String pluginRoot, final String servicesRoot)
+ private final void bundleDetails( JSONWriter jw, Bundle bundle, final String pluginRoot, final String servicesRoot)
throws JSONException
{
Dictionary headers = bundle.getHeaders();
@@ -700,7 +745,7 @@
}
- private Integer getStartLevel( Bundle bundle )
+ private final Integer getStartLevel( Bundle bundle )
{
StartLevel sl = getStartLevel();
return ( sl != null ) ? new Integer( sl.getBundleStartLevel( bundle ) ) : null;
@@ -754,7 +799,7 @@
}
else
{
- WebConsoleUtil.keyVal( jw, "Exported Packages", "None" );
+ WebConsoleUtil.keyVal( jw, "Exported Packages", "---" );
}
exports = packageAdmin.getExportedPackages( ( Bundle ) null );
@@ -859,7 +904,7 @@
}
else
{
- WebConsoleUtil.keyVal( jw, "Exported Packages", "None" );
+ WebConsoleUtil.keyVal( jw, "Exported Packages", "---" );
}
}
@@ -924,7 +969,7 @@
else
{
// add description if there are no imports
- val.put( "None" );
+ val.put( "---" );
}
WebConsoleUtil.keyVal( jw, "Imported Packages", val );
@@ -1296,8 +1341,30 @@
}
- public static RequestInfo getRequestInfo(final HttpServletRequest request)
+ static final RequestInfo getRequestInfo(final HttpServletRequest request)
{
- return (RequestInfo)request.getAttribute(BundlesServlet.class.getName());
+ return (RequestInfo)request.getAttribute( BundlesServlet.class.getName() );
+ }
+
+ private final PackageAdmin getPackageAdmin()
+ {
+ return ( PackageAdmin ) getService( PackageAdmin.class.getName() );
+ }
+
+ private final StartLevel getStartLevel()
+ {
+ return ( StartLevel ) getService( StartLevel.class.getName() );
+ }
+
+ // TODO: may remove later, when BaseWebConsolePlugin is made to extend SimpleWebConsolePlugin
+ private Logger log;
+ Logger getLog()
+ {
+ if ( log == null )
+ {
+ log = new Logger( getBundleContext() );
+ }
+
+ return log;
}
}
diff --git a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index b89c29f..20de138 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -35,7 +35,11 @@
bundle=Bundle
version=Version
help=Help
-
+start=Start
+stop=Stop
+save=Save
+reset=Reset
+delete=Delete
# VMStat plugin
vmstat.stopped=Framework has been stopped.
@@ -91,4 +95,73 @@
# Shell plugin
shell.clear=Clear
-shell.status=Use the command prompt to execute shell commands.
\ No newline at end of file
+shell.status=Use the command prompt to execute shell commands.
+
+# Bundles plugin
+bundles.statline=Bundle information: {0} bundles in total, {1} bundles active, {2} active fragments, {3} bundles resolved, {4} bundles installed.
+bundles.install_or_update=Install or Update
+bundles.install_update=Install/Update...
+bundles.refreshPkg=Refresh Packages
+bundles.name=Name
+bundles.name.symb=Symbolic Name
+bundles.status=Status
+bundles.actions=Actions
+# bundle details
+bundles.location=Bundle Location
+bundles.lastMod=Last Modification
+bundles.doc=Bundle Documentation
+bundles.vendor=Vendor
+bundles.copyright=Copyright
+bundles.description=Description
+bundles.startlevel=Start Level
+bundles.classpath=Bundle Classpath
+bundles.pkg.exported=Exported Packages
+bundles.pkg.imported=Imported Packages
+bundles.pkg.importingBundles=Importing Bundles
+bundles.manifest.headers=Manifest Headers
+bundles.hosts=Host Bundles
+bundles.framents=Fragments Attached
+# actions
+bundles.update=Update
+bundles.uninstall=Uninstall
+bundles.refreshImports=Refresh Package Imports
+# upload form
+bundles.upload.caption=Upload / Install Bundles
+bundles.upload.start=Start Bundle
+bundles.upload.level=Start Level
+
+
+# Components plugin
+scr.status.no_service=Apache Felix Declarative Service required for this function!
+scr.status.no_components=No components installed currently!
+scr.status.ok=Number of installed components: {0}
+scr.action.enable=Enable
+scr.action.disable=Disable
+scr.action.configure=Configure
+scr.prop.bundle=Bundle
+scr.prop.defstate=Default State
+scr.prop.activation=Activation
+scr.prop.properties=Properties
+scr.serv.type=Service Type
+scr.serv=Services
+scr.title.actions=Actions
+scr.title.status=Status
+scr.title.name=Name
+
+
+# Configuration plugin
+config.status.ok=Configuration Admin Service is running.
+config.status.missing=Configuration Admin Service is not installed/running.
+config.properties=Properties
+config.properties.enter=Enter Name-Value pairs of configuration properties
+config.info.title=Configuration Information
+config.info.pid=Persistent Identity (PID)
+config.info.fpid=Factory Persistent Identifier (Factory PID)
+config.info.binding=Configuration Binding
+config.info.unbound=Unbound or new configuration
+config.unbind.btn=Unbind
+config.unbind.tip=Unbind Configuration from Bundle
+config.del.ask=Are you sure to delete this configuration ?
+config.del.config=Configuration:
+config.del.bundle=Bundle:
+config.unbind.ask=Are you sure to unbind this configuration ?
diff --git a/webconsole/src/main/resources/res/lib/support.js b/webconsole/src/main/resources/res/lib/support.js
index 86e7620..427d0db 100644
--- a/webconsole/src/main/resources/res/lib/support.js
+++ b/webconsole/src/main/resources/res/lib/support.js
@@ -81,12 +81,8 @@
});
/* A helper function, used together with tablesorter, when the cells contains mixed text and links. As example:
-
elem.tablesorter({
- headers: {
- 0: {textExtraction: mixedLinksExtraction},
- 2: {sorter: false}
- }
+ textExtraction: mixedLinksExtraction
});
*/
function mixedLinksExtraction(node) {
diff --git a/webconsole/src/main/resources/res/ui/bundles.css b/webconsole/src/main/resources/res/ui/bundles.css
new file mode 100644
index 0000000..5824bd6
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/bundles.css
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#optionalData {
+ margin: 0;
+ padding: 0;
+}
+
+ul.icons {margin: 0; padding: 0;}
+ul.icons li {margin: 1px; position: relative; padding: 1px 0; cursor: pointer; float: left; list-style: none;}
+ul.icons span.ui-icon {float: left; margin: 0 1px;}
+
+.col_Status { width: 50px; }
+.col_Actions { width: 121px; }
diff --git a/webconsole/src/main/resources/res/ui/bundles.js b/webconsole/src/main/resources/res/ui/bundles.js
index cef5de4..2660b74 100644
--- a/webconsole/src/main/resources/res/ui/bundles.js
+++ b/webconsole/src/main/resources/res/ui/bundles.js
@@ -14,72 +14,57 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-function renderStatusLine() {
- $("#plugin_content").append( "<div class='fullwidth'><div class='statusline'/></div>" );
-}
-
-function renderView( /* Array of String */ columns, /* String */ buttons ) {
- renderStatusLine();
- renderButtons(buttons);
- var txt = "<div class='table'><table id='plugin_table' class='tablelayout'><thead><tr>";
- for ( var name in columns ) {
- txt = txt + "<th class='col_" + columns[name] + "'>" + columns[name] + "</th>";
- }
- txt = txt + "</tr></thead><tbody></tbody></table></div>";
- $("#plugin_content").append( txt );
- renderButtons(buttons);
- renderStatusLine();
-}
-
-function renderButtons( buttons ) {
- $("#plugin_content").append( "<form method='post' enctype='multipart/form-data'><div class='fullwidth'><div class='buttons'>" +
- buttons + "</div></div></form>" );
-}
function renderData( eventData ) {
- $(".statusline").empty().append(eventData.status);
- $("#plugin_table > tbody > tr").remove();
+ var s = eventData.s;
+ $(".statline").html(i18n.statline.msgFormat(s[0], s[1], s[2], s[3], s[4]));
+ $("#plugin_table > tbody > tr").remove();
for ( var idx in eventData.data ) {
- if ( currentBundle == null || !drawDetails || currentBundle == eventData.data[idx].id) {
+ if ( currentBundle == null || !drawDetails || currentBundle == eventData.data[idx].id) {
entry( eventData.data[idx] );
- }
+ }
}
- $("#plugin_table").trigger("update");
if ( drawDetails && eventData.data.length == 1 ) {
- renderDetails(eventData.data[0]);
+ renderDetails(eventData.data[0]);
} else if ( currentBundle != null ) {
- var id = currentBundle;
- hideDetails(id);
- showDetails(id);
+ var id = currentBundle;
+ hideDetails(id);
+ showDetails(id);
}
+ initStaticWidgets();
}
function entry( /* Object */ dataEntry ) {
var trElement = tr( null, { id: "entry" + dataEntry.id } );
entryInternal( trElement, dataEntry );
- $("#plugin_table > tbody").append(trElement);
+ $("#plugin_table > tbody").append(trElement);
}
function actionButton( /* Element */ parent, /* string */ id, /* Obj */ action ) {
- if ( !action.enabled ) {
- return;
- }
- var enabled = action.enabled;
- var op = action.link;
- var opLabel = action.name;
- var img = action.image;
-
- var input = createElement( "input", null, {
- type: 'image',
- style: {"margin-left": "10px"},
- title: opLabel,
- alt: opLabel,
- src: imgRoot + '/bundle_' + img + '.png'
- });
- $(input).click(function() {changeDataEntryState(id, op)});
-
+ if ( !action.enabled ) {
+ return;
+ }
+ var enabled = action.enabled;
+ var op = action.link;
+ var opLabel = action.name;
+ var img = action.image;
+ // fixup JQuery UI icons
+ if(img == "start" ) img = "play";
+ if(img == "update") img = "transferthick-e-w";
+ if(img == "delete") img = "trash";
+
+ // apply i18n
+ opLabel = i18n[opLabel] ? i18n[opLabel] : opLabel;
+
+ var input = createElement('li', 'dynhover', {
+ title: opLabel
+ });
+ $(input)
+ .html('<span class="ui-icon ui-icon-'+img+'"></span>')
+ .click(function() {changeDataEntryState(id, op)});
+
if (!enabled) {
- $(input).attr("disabled", true);
+ $(input).attr("disabled", true).addClass("ui-state-disabled");
}
parent.appendChild( input );
}
@@ -88,23 +73,20 @@
var id = dataEntry.id;
var name = dataEntry.name;
var state = dataEntry.state;
-
- var inputElement = createElement("img", "rightButton", {
- src: appRoot + "/res/imgs/arrow_right.png",
- style: {border: "none"},
- id: 'img' + id,
- title: "Details",
- alt: "Details",
- width: 14,
- height: 14
+
+ // right arrow
+ var inputElement = createElement('span', 'ui-icon ui-icon-triangle-1-e', {
+ title: "Details",
+ id: 'img' + id,
+ style: {display: "inline-block"}
});
$(inputElement).click(function() {showDetails(id)});
var titleElement;
if ( drawDetails ) {
- titleElement = text(name);
+ titleElement = text(name);
} else {
titleElement = createElement ("a", null, {
- href: window.location.pathname + "/" + id
+ href: window.location.pathname + "/" + id
});
titleElement.appendChild(text(name));
}
@@ -115,147 +97,126 @@
parent.appendChild( td( null, null, [ text( dataEntry.symbolicName ) ] ) );
parent.appendChild( td( null, null, [ text( state ) ] ) );
var actionsTd = td( null, null );
- var div = createElement("div", null, {
- style: { "text-align" : "left"}
- });
+ var div = createElement('ul', 'icons ui-widget');
actionsTd.appendChild(div);
for ( var a in dataEntry.actions ) {
- actionButton( div, id, dataEntry.actions[a] );
+ actionButton( div, id, dataEntry.actions[a] );
}
parent.appendChild( actionsTd );
}
function loadData() {
- $.get(pluginRoot + "/.json", null, function(data) {
- renderData(data);
- }, "json");
+ $.get(pluginRoot + "/.json", null, function(data) {
+ renderData(data);
+ }, "json");
}
function changeDataEntryState(/* long */ id, /* String */ action) {
- $.post(pluginRoot + "/" + id, {"action":action}, function(data) {
- renderData(data);
- }, "json");
+ $.post(pluginRoot + "/" + id, {"action":action}, function(data) {
+ renderData(data);
+ }, "json");
}
function refreshPackages() {
- $.post(window.location.pathname, {"action": "refreshPackages"}, function(data) {
- renderData(data);
- }, "json");
+ $.post(window.location.pathname, {"action": "refreshPackages"}, function(data) {
+ renderData(data);
+ }, "json");
}
function showDetails( id ) {
- currentBundle = id;
+ currentBundle = id;
$.get(pluginRoot + "/" + id + ".json", null, function(data) {
- renderDetails(data.data[0]);
+ renderDetails(data.data[0]);
}, "json");
}
function hideDetails( id ) {
- currentBundle = null;
- $("#img" + id).each(function() {
- $("#pluginInlineDetails" + id).remove();
- $(this).attr("src", appRoot + "/res/imgs/arrow_right.png");
- $(this).attr("title", "Details");
- $(this).attr("alt", "Details");
- $(this).unbind('click').click(function() {showDetails(id)});
- });
+ currentBundle = null;
+ $("#img" + id).each(function() {
+ $("#pluginInlineDetails" + id).remove();
+ $(this).
+ removeClass('ui-icon-triangle-1-w').//left
+ removeClass('ui-icon-triangle-1-s').//down
+ addClass('ui-icon-triangle-1-e').//right
+ attr("title", "Details").
+ unbind('click').click(function() {showDetails(id)});
+ });
}
function renderDetails( data ) {
- $("#entry" + data.id + " > td").eq(1).append("<div id='pluginInlineDetails" + data.id + "'/>");
- $("#img" + data.id).each(function() {
- if ( drawDetails ) {
- $(this).attr("src", appRoot + "/res/imgs/arrow_left.png");
- $(this).attr("title", "Back");
- $(this).attr("alt", "Back");
- var ref = window.location.pathname;
- ref = ref.substring(0, ref.lastIndexOf('/'));
- $(this).unbind('click').click(function() {window.location = ref;});
- } else {
- $(this).attr("src", appRoot + "/res/imgs/arrow_down.png");
- $(this).attr("title", "Hide Details");
- $(this).attr("alt", "Hide Details");
- $(this).unbind('click').click(function() {hideDetails(data.id)});
- }
- });
- $("#pluginInlineDetails" + data.id).append("<table border='0'><tbody></tbody></table>");
+ $("#entry" + data.id + " > td").eq(1).append("<div id='pluginInlineDetails" + data.id + "'/>");
+ $("#img" + data.id).each(function() {
+ if ( drawDetails ) {
+ var ref = window.location.pathname;
+ ref = ref.substring(0, ref.lastIndexOf('/'));
+ $(this).
+ removeClass('ui-icon-triangle-1-e').//right
+ removeClass('ui-icon-triangle-1-s').//down
+ addClass('ui-icon-triangle-1-w').//left
+ attr("title", "Back").
+ unbind('click').click(function() {window.location = ref});
+ } else {
+ $(this).
+ removeClass('ui-icon-triangle-1-w').//left
+ removeClass('ui-icon-triangle-1-e').//right
+ addClass('ui-icon-triangle-1-s').//down
+ attr("title", "Hide Details").
+ unbind('click').click(function() {hideDetails(data.id)});
+ }
+ });
+ $("#pluginInlineDetails" + data.id).append("<table border='0'><tbody></tbody></table>");
var details = data.props;
for (var idx in details) {
var prop = details[idx];
-
- var txt = "<tr><td class='aligntop' noWrap='true' style='border:0px none'>" + prop.key + "</td><td class='aligntop' style='border:0px none'>";
+ var key = i18n[prop.key] ? i18n[prop.key] : prop.key;
+
+ var txt = "<tr><td class='aligntop' noWrap='true' style='border:0px none'>" + key + "</td><td class='aligntop' style='border:0px none'>";
if (prop.value) {
- if ( prop.key == 'Bundle Documentation' ) {
- txt = txt + "<a href='" + prop.value + "' target='_blank'>" + prop.value + "</a>";
- } else {
- if ( $.isArray(prop.value) ) {
- var i = 0;
- for(var pi in prop.value) {
- var value = prop.value[pi];
- if (i > 0) { txt = txt + "<br/>"; }
- var span;
- if (value.substring(0, 6) == "INFO: ") {
- txt = txt + "<span style='color: grey;'>!!" + value.substring(5) + "</span>";
- } else if (value.substring(0, 7) == "ERROR: ") {
- txt = txt + "<span style='color: red;'>!!" + value.substring(6) + "</span>";
- } else {
- txt = txt + value;
- }
- i++;
- }
- } else {
- txt = txt + prop.value;
- }
- }
+ if ( prop.key == 'Bundle Documentation' ) {
+ txt = txt + "<a href='" + prop.value + "' target='_blank'>" + prop.value + "</a>";
+ } else {
+ if ( $.isArray(prop.value) ) {
+ var i = 0;
+ for(var pi in prop.value) {
+ var value = prop.value[pi];
+ if (i > 0) { txt = txt + "<br/>"; }
+ txt = txt + value;
+ i++;
+ }
+ } else {
+ txt = txt + prop.value;
+ }
+ }
} else {
- txt = txt + "\u00a0";
+ txt = txt + "\u00a0";
}
txt = txt + "</td></tr>";
$("#pluginInlineDetails" + data.id + " > table > tbody").append(txt);
- }
+ }
}
-function renderBundles(data) {
- $(document).ready(function(){
- renderView( ["Id", "Name", "Version", "Symbolic Name", "Status", "Actions"],
- "<input type='hidden' name='action' value='install'/>" +
- "<input type='hidden' name='bundlestart' value='start'/>" +
- "<input type='hidden' name='bundlestartlevel' value='" + startLevel + "'/>" +
- "<input class='fileinput' type='file' name='bundlefile' style='margin-left:10px'/>" +
- "<input type='submit' value='Install or Update' style='margin-left:10px'/>" +
- "<button class='reloadButton' type='button' name='reload' style='margin-left:60px'>Reload</button>" +
- "<button class='installButton' type='button' name='install'>Install/Update...</button>" +
- "<button class='refreshPackages' type='button' name='refresh'>Refresh Packages</button>"
- );
- $(".refreshPackages").click(refreshPackages);
- $(".reloadButton").click(loadData);
- $(".installButton").click(function() {
- document.location = pluginRoot + "/upload";
- });
- renderData(data);
-
- var extractMethod = function(node) {
- var link = node.getElementsByTagName("a");
- if ( link && link.length == 1 ) {
- return link[0].innerHTML;
- }
- return node.innerHTML;
- };
- // check for cookie
- var cv = $.cookies.get("webconsolebundlelist");
- var lo = (cv ? cv.split(",") : [1,0]);
- $("#plugin_table").tablesorter({
- headers: {
- 0: { sorter:"digit"},
- 5: { sorter: false }
- },
- sortList: [lo],
- textExtraction:extractMethod
- });
- $("#plugin_table").bind("sortEnd", function() {
- var table = $("#plugin_table").eq(0).attr("config");
- $.cookies.set("webconsolebundlelist", table.sortList.toString());
- });
- });
-}
+$(document).ready(function(){
+ $(".refreshPackages").click(refreshPackages);
+ $(".reloadButton").click(loadData);
+ $(".installButton").click(function() {
+ document.location = pluginRoot + "/upload";
+ });
+ renderData(__bundles__);
+
+ // check for cookie
+ var cv = $.cookies.get("webconsolebundlelist");
+ var lo = (cv ? cv.split(",") : [1,0]);
+ $("#plugin_table").tablesorter({
+ headers: {
+ 0: { sorter:"digit" },
+ 5: { sorter: false }
+ },
+ textExtraction:mixedLinksExtraction,
+ sortList: cv ? [lo] : false
+ }).bind("sortEnd", function() {
+ var table = $("#plugin_table").eq(0).attr("config");
+ $.cookies.set("webconsolebundlelist", table.sortList.toString());
+ });
+});
+
diff --git a/webconsole/src/main/resources/templates/bundles.html b/webconsole/src/main/resources/templates/bundles.html
new file mode 100644
index 0000000..4221f30
--- /dev/null
+++ b/webconsole/src/main/resources/templates/bundles.html
@@ -0,0 +1,86 @@
+<script type="text/javascript" src="${appRoot}/res/ui/bundles.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+var startLevel = ${startLevel};
+var drawDetails = ${drawDetails};
+var currentBundle = ${currentBundle};
+var __bundles__ = ${__bundles__};
+var i18n = {
+ 'Symbolic Name' : '${bundles.name.symb}',
+ 'Version' : '${version}',
+ 'Bundle Location' : '${bundles.location}',
+ 'Last Modification' : '${bundles.lastMod}',
+ 'Bundle Documentation': '${bundles.doc}',
+ 'Vendor' : '${bundles.vendor}',
+ 'Copyright' : '${bundles.copyright}',
+ 'Description' : '${bundles.description}',
+ 'Start Level' : '${bundles.startlevel}',
+ 'Bundle Classpath' : '${bundles.classpath}',
+ 'Exported Packages' : '${bundles.pkg.exported}',
+ 'Imported Packages' : '${bundles.pkg.imported}',
+ 'Importing Bundles' : '${bundles.pkg.importingBundles}',
+ 'Manifest Headers' : '${bundles.manifest.headers}',
+ 'Host Bundles' : '${bundles.hosts}',
+ 'Fragments Attached' : '${bundles.framents}',
+ 'Vendor' : '${bundles.vendor}',
+ // actions
+ 'Start' : '${start}',
+ 'Stop' : '${stop}',
+ 'Update' : '${bundles.update}',
+ 'Uninstall' : '${bundles.uninstall}',
+ 'Refresh Package Imports' : '${bundles.refreshImports}',
+ //
+ statline : '${bundles.statline}'
+}
+// ]]>
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <input name="action" value="install" type="hidden" />
+ <input name="bundlestart" value="start" type="hidden" />
+ <input name="bundlestartlevel" value="5" type="hidden" />
+ <input name="bundlefile" style="margin-left: 10px;" type="file" />
+ <input value="${bundles.install_or_update}" style="margin-left: 10px;" type="submit" />
+ <button class="reloadButton" type="button" name="reload" style="margin-left: 60px;">${reload}</button>
+ <button class="installButton" type="button" name="install">${bundles.install_update}</button>
+ <button class="refreshPackages" type="button" name="refresh">${bundles.refreshPkg}</button>
+ </div>
+</form>
+
+<table id="plugin_table" class="tablesorter nicetable noauto">
+ <thead>
+ <tr>
+ <th class="col_Id">${id}</th>
+ <th class="col_Name">${bundles.name}</th>
+ <th class="col_Version">${version}</th>
+ <th class="col_Symbolic_Name">${bundles.name.symb}</th>
+ <th class="col_Status">${bundles.status}</th>
+ <th class="col_Actions">${bundles.actions}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td colspan="6"> </td></tr>
+ </tbody>
+</table>
+
+<!-- bottom header -->
+<form method="post" enctype="multipart/form-data" action="">
+ <div class="ui-widget-header ui-corner-bottom buttonGroup">
+ <input name="action" value="install" type="hidden" />
+ <input name="bundlestart" value="start" type="hidden" />
+ <input name="bundlestartlevel" value="5" type="hidden" />
+ <input name="bundlefile" style="margin-left: 10px;" type="file" />
+ <input value="${bundles.install_or_update}" style="margin-left: 10px;" type="submit" />
+ <button class="reloadButton" type="button" name="reload" style="margin-left: 60px;">${reload}</button>
+ <button class="installButton" type="button" name="install">${bundles.install_update}</button>
+ <button class="refreshPackages" type="button" name="refresh">${bundles.refreshPkg}</button>
+ </div>
+</form>
+
+<!-- status line -->
+<p class="statline"> </p>
diff --git a/webconsole/src/main/resources/templates/bundles_upload.html b/webconsole/src/main/resources/templates/bundles_upload.html
new file mode 100644
index 0000000..18f9b52
--- /dev/null
+++ b/webconsole/src/main/resources/templates/bundles_upload.html
@@ -0,0 +1,33 @@
+<!--<script type="text/javascript" src="res/ui/bundles.js"></script>-->
+<script type="text/javascript" src="res/lib/jquery.multifile-1.4.6.js"></script>
+
+<form method="post" enctype="multipart/form-data" action="../" style="width:50%">
+
+ <!-- top heading -->
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <input type="hidden" name="action" value="install"/>
+ ${bundles.upload.caption}
+ </div>
+
+ <table class="nicetable">
+ <tr>
+ <td style="text-align:right">${bundles.upload.start}</td>
+ <td><input type="checkbox" name="bundlestart" value="start"/></td>
+ </tr>
+ <tr>
+ <td style="text-align:right">${bundles.upload.level}</td>
+ <td><input class="input" type="text" name="bundlestartlevel" id="bundlestartlevel" value="${startLevel}" size="4"/></td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td>
+ <input class="multi" accept="jar" type="file" name="bundlefile"/>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" style="text-align:center">
+ <input type="submit" value="${bundles.install_or_update}"/>
+ </td>
+ </tr>
+ </table>
+</form>