FELIX-1988 Apply 10.deployment_plugin.patch by Valentin Valchev (thanks)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@911379 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java
index 19c1041..2c096ce 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/deppack/DepPackServlet.java
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Map;
import javax.servlet.ServletException;
@@ -27,56 +28,49 @@
import org.apache.commons.fileupload.FileItem;
import org.apache.felix.webconsole.AbstractWebConsolePlugin;
-import org.apache.felix.webconsole.WebConsoleConstants;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
import org.apache.felix.webconsole.WebConsoleUtil;
-import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
import org.apache.felix.webconsole.internal.Util;
import org.json.JSONException;
import org.json.JSONWriter;
-import org.osgi.service.component.ComponentContext;
import org.osgi.service.deploymentadmin.DeploymentAdmin;
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.deploymentadmin.DeploymentPackage;
-public class DepPackServlet extends BaseWebConsolePlugin
+/**
+ * DepPackServlet provides a plugin for managing deployment admin packages.
+ */
+public class DepPackServlet extends SimpleWebConsolePlugin implements OsgiManagerPlugin
{
- public static final String LABEL = "deppack";
+ private static final String LABEL = "deppack";
+ private static final String TITLE = "Deployment Packages";
+ private static final String CSS[] = { "/res/ui/deployment.css" };
- public static final String TITLE = "Deployment Packages";
-
+ //
private static final String ACTION_DEPLOY = "deploydp";
-
private static final String ACTION_UNINSTALL = "uninstalldp";
-
private static final String PARAMETER_PCK_FILE = "pckfile";
+ // templates
+ private final String TEMPLATE;
- public String getLabel()
+ /** Default constructor */
+ public DepPackServlet()
{
- return LABEL;
+ super(LABEL, TITLE, CSS);
+
+ // load templates
+ TEMPLATE = readTemplateFile( "/templates/deployment.html" );
}
- public String getTitle()
- {
- return TITLE;
- }
-
-
- protected void activate( ComponentContext context )
- {
- this.activate( context.getBundleContext() );
- }
-
-
- protected void deactivate( ComponentContext context )
- {
- this.deactivate();
- }
-
-
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
{
// get the uploaded data
@@ -138,7 +132,7 @@
}
- private FileItem getFileItem( Map params, String name, boolean isFormField )
+ private static final FileItem getFileItem( Map params, String name, boolean isFormField )
{
FileItem[] items = ( FileItem[] ) params.get( name );
if ( items != null )
@@ -157,42 +151,39 @@
}
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException
{
- PrintWriter pw = response.getWriter();
-
- String appRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_APP_ROOT );
- pw.println( "<script src='" + appRoot + "/res/ui/packages.js' language='JavaScript'></script>" );
-
- pw.println( "<h1>Deployment Admin</h1>" );
final DeploymentAdmin admin = ( DeploymentAdmin ) this.getService( DeploymentAdmin.class.getName() );
- if ( admin == null )
- {
- pw.println( "<p><em>Deployment Admin is not installed.</em></p>" );
- return;
- }
- final DeploymentPackage[] packages = admin.listDeploymentPackages();
- Util.startScript( pw );
- pw.println( "var packageListData = " );
- JSONWriter jw = new JSONWriter( pw );
+ StringWriter w = new StringWriter();
+ PrintWriter w2 = new PrintWriter(w);
+ JSONWriter jw = new JSONWriter( w2 );
try
{
jw.object();
-
- jw.key( "data" );
-
- jw.array();
-
- for ( int i = 0; i < packages.length; i++ )
+ if ( null == admin )
{
- packageInfoJson( jw, packages[i] );
+ jw.key( "error" );
+ jw.value( true );
}
+ else
+ {
+ final DeploymentPackage[] packages = admin.listDeploymentPackages();
+ jw.key( "data" );
- jw.endArray();
+ jw.array();
+ for ( int i = 0; i < packages.length; i++ )
+ {
+ packageInfoJson( jw, packages[i] );
+ }
+ jw.endArray();
+ }
jw.endObject();
}
@@ -201,13 +192,15 @@
throw new IOException( je.toString() );
}
- pw.println( ";" );
- pw.println( "renderPackage( packageListData );" );
- Util.endScript( pw );
+ // prepare variables
+ DefaultVariableResolver vars = ( ( DefaultVariableResolver ) WebConsoleUtil.getVariableResolver( request ) );
+ vars.put( "__data__", w.toString() );
+
+ response.getWriter().print(TEMPLATE);
}
- private void packageInfoJson( JSONWriter jw, DeploymentPackage pack ) throws JSONException
+ private static final void packageInfoJson( JSONWriter jw, DeploymentPackage pack ) throws JSONException
{
jw.object();
jw.key( "id" );
diff --git a/webconsole/src/main/resources/res/ui/deployment.css b/webconsole/src/main/resources/res/ui/deployment.css
new file mode 100644
index 0000000..5c569c7
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/deployment.css
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+.pkgname { cursor:pointer }
+.pkgname span { float:left }
diff --git a/webconsole/src/main/resources/res/ui/deployment.js b/webconsole/src/main/resources/res/ui/deployment.js
new file mode 100644
index 0000000..7dbe6ec
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/deployment.js
@@ -0,0 +1,171 @@
+/*
+ * 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 fixId(id) { return id.replace('.', '_'); }
+
+function data( /* Array of Object */ dataArray ) { // render components
+ if (dataArray.length == 1) {
+ entry( dataArray[0], true );
+ } else {
+ for ( var idx in dataArray ) {
+ entry( dataArray[idx] );
+ }
+ }
+}
+
+function entry( /* Object */ dataEntry, /* boolean */ singleEntry ) {
+ var id = fixId(dataEntry.id);
+ var trElement = tr( 'ui-state-active', { 'id': 'entry' + id });
+
+ // entry brief
+ entryInternal( trElement, dataEntry, singleEntry );
+ plugin_table.append(trElement);
+
+ // dataEntry detailed properties
+ trElement = tr( 'ui-helper-hidden', {
+ 'id' : 'entry' + id + '_details'
+ });
+ if (dataEntry.props) {
+ getDataEntryDetails( trElement, dataEntry.props );
+ }
+ plugin_table.append(trElement);
+}
+
+function entryInternal( /* Element */ parent, /* Object */ dataEntry, /* boolean */ singleEntry ) {
+ var id = dataEntry.id;
+ var _id = fixId(id);
+
+ parent.appendChild( td( null, null, [ text( id ) ] ) );
+ parent.appendChild( td( null,
+ {
+ 'onclick': 'toggleDetails("#entry' + _id + '")',
+ 'class': 'pkgname'
+ },
+ [
+ createElement( 'span', 'ui-icon ui-icon-triangle-1-e', { id: 'entry' + _id + '_icon'} ),
+ text(dataEntry.name)
+ ]
+ )
+ );
+ parent.appendChild( td( null, null, [ text( dataEntry.state ) ] ) );
+
+ for ( var aidx in dataEntry.actions ) {
+ var action = dataEntry.actions[aidx];
+ parent.appendChild( actionButton( action.enabled, id, action.link, action.name ) );
+ }
+}
+
+
+/* Element */ function actionButton( /* boolean */ enabled, /* long */ id, /* String */ op, /* String */ opLabel ) {
+ var buttonTd = td( "content", { align: "right" } );
+ if ( op ) {
+ switch (opLabel) {
+ case "Uninstall" : opLabel = i18n.uninstall; break;
+ }
+ var input = createElement( "input", null, {
+ type: 'button',
+ value: opLabel,
+ onclick: 'changeDataEntryState("' + id + '", "' + op + '");'
+ });
+ if (!enabled) {
+ input.setAttribute( "disabled", true );
+ $(input).addClass('ui-state-disabled');
+ }
+ buttonTd.appendChild( input );
+ } else {
+ addText( buttonTd, "\u00a0" );
+ }
+ return buttonTd;
+}
+
+
+function getDataEntryDetails( /* Element */ parent, /* Array of Object */ details )
+{
+ parent.appendChild( addText( td( "content"), "\u00a0" ) );
+
+ var tdEl = td( null, { colspan: 4 } );
+ parent.appendChild( tdEl );
+
+ var tableEl = createElement( "table", null, { border: 0 } );
+ tdEl.appendChild( tableEl );
+
+ var tbody = createElement( "tbody" );
+ tableEl.appendChild( tbody );
+ for (var idx in details) {
+ var prop = details[idx];
+ var trEl = tr();
+ var key = prop.key;
+ switch (key) {
+ case 'Package Name': key = i18n.package_name; break;
+ case 'Version' : key = i18n.version; break;
+ case 'Bundles' : key = i18n.bundles; break;
+ }
+ trEl.appendChild( addText( td( null, { noWrap: true } ), key ) );
+
+ var proptd = td();
+ trEl.appendChild( proptd );
+ $(proptd).html( prop.value ? prop.value : "\u00a0");
+
+ tbody.appendChild( trEl );
+ }
+ }
+
+
+function changeDataEntryState(/* long */ id, /* String */ action) {
+ var parm = pluginRoot + "/" + id + "?action=" + action;
+ $.post(parm, null, function() { // always reload
+ document.location.reload();
+ }, "text");
+}
+
+
+function toggleDetails(name) {
+ var icon = $(name + '_icon');
+ var details = $(name + '_details');
+ var show = icon.attr('show');
+ if (typeof show == 'undefined') show = '';
+ icon.attr('show', show ? '' : 'true');
+
+ if (show == 'true') {
+ icon.removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
+ details.addClass('ui-helper-hidden');
+ } else {
+ icon.removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s');
+ details.removeClass('ui-helper-hidden');
+ }
+}
+
+var plugin_table = false;
+$(document).ready(function() {
+ plugin_table = $('#plugin_table');
+ var /* Array of Data Objects */ bundleData = packageListData;
+ if (bundleData.error) {
+ $('.statline').text(i18n.status_no_serv);
+ $('#dps1').addClass('ui-helper-hidden');
+ } else if (!bundleData.data || bundleData.data.length == 0) {
+ $('.statline').text(i18n.status_no_data);
+ $('#dps1').removeClass('ui-helper-hidden');
+ $('#dps2').addClass('ui-helper-hidden');
+ } else {
+ data( bundleData.data );
+ $('.statline').text(i18n.status_ok);
+ $('#dps1').removeClass('ui-helper-hidden');
+ $('#dps2').removeClass('ui-helper-hidden');
+ initStaticWidgets(plugin_table);
+ }
+});
+
diff --git a/webconsole/src/main/resources/templates/deployment.html b/webconsole/src/main/resources/templates/deployment.html
new file mode 100644
index 0000000..525738d
--- /dev/null
+++ b/webconsole/src/main/resources/templates/deployment.html
@@ -0,0 +1,52 @@
+<script type="text/javascript" src="res/ui/deployment.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+var i18n = {
+ status_no_data : "${deployment.status.no_data}",
+ status_no_serv : "${deployment.status.no_service}",
+ status_ok : "${deployment.status.ok}",
+ package_name : "${deployment.package.name}",
+ version : "${version}",
+ bundles : "${deployment.bundles}",
+ uninstall : "${deployment.uninstall}"
+}
+var packageListData = ${__data__};
+// ]]>
+</script>
+
+<p class="statline"> </p>
+
+<div id="dps1"> <!-- will be hidden if no DP service available -->
+<!-- top header -->
+<form method="post" enctype="multipart/form-data" >
+ <div class="ui-widget-header ui-corner-top buttonGroup" style="text-align: right">
+ <input name="action" type="hidden" value="deploydp" />
+ <input name="pckfile" type="file" size="50" />
+ <input type="submit" value="${deployment.install_update}" />
+ </div>
+</form>
+
+<div id="dps2"> <!-- will be hidden if no data available -->
+ <table id="plugin_table" class="nicetable">
+ <thead>
+ <tr>
+ <th>${id}</th>
+ <th width="100%">${deployment.details}</th>
+ <th>${version}</th>
+ <th colspan="1">${deployment.actions}</th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+ </table>
+
+ <!-- bottom header -->
+ <form method="post" enctype="multipart/form-data" >
+ <div class="ui-widget-header ui-corner-bottom buttonGroup" style="text-align: right">
+ <input name="action" type="hidden" value="deploydp" />
+ <input name="pckfile" type="file" size="50" />
+ <input type="submit" value="${deployment.install_update}" />
+ </div>
+ </form>
+</div><!--dps2-->
+</div><!--dps1-->