Author: davidb Date: Thu Jul 2 11:09:06 2015 New Revision: 1688806 URL: http://svn.apache.org/r1688806 Log: FELIX-4947 Webconsole plugin for OSGi Subsystems
Initial commit with basic functionality working. This plugin was highly inspired by the existing web console bundles page. Added: felix/trunk/webconsole-plugins/subsystems/ felix/trunk/webconsole-plugins/subsystems/pom.xml felix/trunk/webconsole-plugins/subsystems/src/ felix/trunk/webconsole-plugins/subsystems/src/main/ felix/trunk/webconsole-plugins/subsystems/src/main/java/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java felix/trunk/webconsole-plugins/subsystems/src/main/resources/ felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/ felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/ felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/ felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js Added: felix/trunk/webconsole-plugins/subsystems/pom.xml URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/pom.xml?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/pom.xml (added) +++ felix/trunk/webconsole-plugins/subsystems/pom.xml Thu Jul 2 11:09:06 2015 @@ -0,0 +1,109 @@ +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.felix</groupId> + <artifactId>felix-parent</artifactId> + <version>2.1</version> + <relativePath>../../../pom/pom.xml</relativePath> + </parent> + + <artifactId>org.apache.felix.webconsole.plugins.subsystems</artifactId> + <packaging>bundle</packaging> + <version>1.0.0-SNAPSHOT</version> + + <name>Apache Felix Web Console Subsystes Plugin</name> + <description> + This is a plugin for the Apache Felix OSGi web console to integrate with OSGi Subsystems. + </description> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>2.3.4</version> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName> + ${project.artifactId} + </Bundle-SymbolicName> + <Bundle-Activator> + org.apache.felix.webconsole.plugins.subsystem.internal.Activator + </Bundle-Activator> + <Private-Package> + org.apache.felix.webconsole.plugins.subsystem.* + </Private-Package> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.6</source> + <target>1.6</target> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.4</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.2.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20070829</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <version>5.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <version>5.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.webconsole</artifactId> + <version>4.2.0</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> Added: felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java (added) +++ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/Activator.java Thu Jul 2 11:09:06 2015 @@ -0,0 +1,116 @@ +/* + * 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.felix.webconsole.plugins.subsystem.internal; + +import org.apache.felix.webconsole.SimpleWebConsolePlugin; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator +{ + private SimpleWebConsolePlugin plugin; + + public void start(BundleContext context) throws Exception + { + plugin = new WebConsolePlugin(context).register(); + } + + public void stop(BundleContext context) throws Exception + { + plugin = null; + } + + /* + public synchronized URLStreamHandlerService addingService(ServiceReference<URLStreamHandlerService> reference) + { + SimpleWebConsolePlugin p = plugin; + if (p == null) + { + URLStreamHandlerService svc = bundleContext.getService(reference); + plugin = new WebConsolePlugin(svc).register(bundleContext); + } + return bundleContext.getService(reference); + } + + public void modifiedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service) + { + // Unused + } + + public synchronized void removedService(ServiceReference<URLStreamHandlerService> reference, URLStreamHandlerService service) + { + if (plugin != null) + { + plugin.unregister(); + plugin = null; + } + } + */ +} + +//public class Activator implements BundleActivator +//{ +// private SubsystemPluginServlet plugin; +// +// public void start(final BundleContext context) throws Exception +// { +// plugin = new SubsystemPluginServlet(); +// +//// // now we create the listener +//// this.eventListener = new EventListener(this.plugin, context); +//// +//// // and the optional features handler +//// this.featuresHandler = new OptionalFeaturesHandler(this.plugin, context); +// +// // finally we register the plugin +// final Dictionary props = new Hashtable(); +// props.put( Constants.SERVICE_DESCRIPTION, "Subsystems Plugin for the Apache Felix Web Console" ); +// props.put( "felix.webconsole.label", "subsystems"); +// props.put( "felix.webconsole.title", "Subsystems"); +//// props.put( "felix.webconsole.css", "/events/res/ui/events.css"); +// props.put( "felix.webconsole.category", "OSGi"); +// context.registerService(Servlet.class.getName(), +// plugin, +// props); +// } +// +// /** +// * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) +// */ +// public void stop(final BundleContext context) throws Exception +// { +//// if ( this.pluginRegistration != null ) +//// { +//// this.pluginRegistration.unregister(); +//// this.pluginRegistration = null; +//// } +//// if ( this.eventListener != null ) +//// { +//// this.eventListener.destroy(); +//// eventListener = null; +//// } +//// if ( this.featuresHandler != null) +//// { +//// this.featuresHandler.destroy(); +//// this.featuresHandler = null; +//// } +//// if ( this.plugin != null ) { +//// this.plugin.destroy(); +//// this.plugin = null; +//// } +// } +//} Added: felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java (added) +++ felix/trunk/webconsole-plugins/subsystems/src/main/java/org/apache/felix/webconsole/plugins/subsystem/internal/WebConsolePlugin.java Thu Jul 2 11:09:06 2015 @@ -0,0 +1,431 @@ +/* + * 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.felix.webconsole.plugins.subsystem.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItem; +import org.apache.felix.webconsole.AbstractWebConsolePlugin; +import org.apache.felix.webconsole.DefaultVariableResolver; +import org.apache.felix.webconsole.SimpleWebConsolePlugin; +import org.apache.felix.webconsole.WebConsoleUtil; +import org.json.JSONException; +import org.json.JSONWriter; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; +import org.osgi.service.subsystem.Subsystem; +import org.osgi.service.subsystem.SubsystemConstants; + +public class WebConsolePlugin extends SimpleWebConsolePlugin +{ + private static final long serialVersionUID = 4329827842860201817L; + private static final String UNABLE_TO_FIND_TARGET_SUBSYSTEM = "Unable to find target subsystem"; + + private static final String LABEL = "subsystems"; + private static final String TITLE = "Subsystems"; + private static final String CATEGORY = "OSGi"; + private static final String CSS[] = { "/res/ui/bundles.css" }; // yes, it's correct! + private static final String RES = "/" + LABEL + "/res/"; + + private final BundleContext bundleContext; + private final String template; + + public WebConsolePlugin(BundleContext bc) + { + super(LABEL, TITLE, CSS); + bundleContext = bc; + + template = readTemplateFile("/res/plugin.html"); + } + + @Override + public String getCategory() + { + return CATEGORY; + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String path = request.getPathInfo(); + // don't process if this is request to load a resource + if (!path.startsWith(RES)) + { + RequestInfo reqInfo = new RequestInfo(request); + if (reqInfo.extension.equals("json")) + { + renderResult(response, reqInfo); + + // nothing more to do + return; + } + } + super.doGet(request, response); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + String action = WebConsoleUtil.getParameter(req, "action"); + if ("install".equals(action)) + { + installSubsystem(req); + + if (req.getRequestURI().endsWith("/install")) { + // just send 200/OK, no content + resp.setContentLength( 0 ); + } else { + // redirect to URL + resp.sendRedirect(req.getRequestURI()); + } + + return; + } + else + { + boolean success = false; + RequestInfo reqInfo = new RequestInfo(req); + if ("start".equals(action)) + { + startSubsystem(reqInfo.id); + success = true; + } + else if ("stop".equals(action)) + { + stopSubsystem(reqInfo.id); + success = true; + } + else if ("uninstall".equals(action)) + { + uninstallSubsystem(reqInfo.id); + success = true; + } + else + { + super.doPost(req, resp); + } + + if (success) + { + renderResult(resp, reqInfo); + } + } + } + + private void installSubsystem(HttpServletRequest req) throws IOException + { + @SuppressWarnings("rawtypes") + Map params = (Map) req.getAttribute( AbstractWebConsolePlugin.ATTR_FILEUPLOAD ); + + FileItem[] subsystemItems = getFileItems(params, "subsystemfile"); + + for (final FileItem subsystemItem : subsystemItems) + { + File tmpFile = null; + try + { + // copy the data to a file for better processing + tmpFile = File.createTempFile("installSubsystem", ".tmp"); + subsystemItem.write(tmpFile); + } + catch (Exception e) + { + log(LogService.LOG_ERROR, "Problem accessing uploaded subsystem file: " + subsystemItem.getName(), e); + + // remove the temporary file + if (tmpFile != null) + { + tmpFile.delete(); + tmpFile = null; + } + } + + if (tmpFile != null) + { + final File file = tmpFile; + // TODO support install in other subsystems than the root one + // TODO currently this means that when installing more than one subsystem they + // will be installed concurrently. Not sure if this is the best idea. + // However the client UI does not support selecting more than one file, so + // from a practical point of view this is currently not an issue. + asyncSubsystemOperation(0, new SubsystemOperation() + { + @Override + public void exec(Subsystem ss) + { + try + { + InputStream is = new FileInputStream(file); + try + { + ss.install("inputstream:" + subsystemItem.getName(), is); + } + finally + { + is.close(); + file.delete(); + } + } + catch (IOException e) + { + log(LogService.LOG_ERROR, "Problem installing subsystem", e); + } + } + }); + } + } + } + + private void startSubsystem(long id) throws IOException + { + asyncSubsystemOperation(id, new SubsystemOperation() + { + // Lamba, where art thou. So close yet so far away... + @Override + public void exec(Subsystem ss) + { + ss.start(); + } + }); + } + + private void stopSubsystem(long id) throws IOException + { + asyncSubsystemOperation(id, new SubsystemOperation() + { + @Override + public void exec(Subsystem ss) + { + ss.stop(); + } + }); + } + + private void uninstallSubsystem(long id) throws IOException + { + asyncSubsystemOperation(id, new SubsystemOperation() + { + @Override + public void exec(Subsystem ss) + { + ss.uninstall(); + } + }); + } + + private void asyncSubsystemOperation(long id, final SubsystemOperation op) throws IOException + { + try + { + Collection<ServiceReference<Subsystem>> refs = + bundleContext.getServiceReferences(Subsystem.class, + "(" + SubsystemConstants.SUBSYSTEM_ID_PROPERTY + "=" + id + ")"); + + if (refs.size() < 1) + throw new IOException(UNABLE_TO_FIND_TARGET_SUBSYSTEM); + + final ServiceReference<Subsystem> ref = refs.iterator().next(); + new Thread(new Runnable() { + @Override + public void run() + { + Subsystem ss = bundleContext.getService(ref); + try + { + op.exec(ss); + } + finally + { + bundleContext.ungetService(ref); + } + } + }).start(); + } + catch (InvalidSyntaxException e) + { + throw new IOException(e); + } + } + + @SuppressWarnings("rawtypes") + private FileItem[] getFileItems(Map params, String name) + { + final List<FileItem> files = new ArrayList<FileItem>(); + FileItem[] items = (FileItem[]) params.get( name ); + if ( items != null ) + { + for ( int i = 0; i < items.length; i++ ) + { + if (!items[i].isFormField() && items[i].getSize() > 0) + { + files.add(items[i]); + } + } + } + + return files.toArray( new FileItem[files.size()] ); + } + + @Override + @SuppressWarnings("unchecked") + protected void renderContent(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + RequestInfo reqInfo = getRequestInfo(req); + + StringWriter w = new StringWriter(); + PrintWriter w2 = new PrintWriter(w); + renderResult(w2, reqInfo); + + // prepare variables + DefaultVariableResolver vars = ((DefaultVariableResolver) WebConsoleUtil.getVariableResolver(req)); + vars.put("__data__", w.toString()); + + res.getWriter().print(template); + } + + private void renderResult(HttpServletResponse response, RequestInfo reqInfo) throws IOException + { + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + renderResult(response.getWriter(), reqInfo); + } + + private void renderResult(PrintWriter pw, RequestInfo reqInfo) throws IOException + { + JSONWriter jw = new JSONWriter(pw); + try + { + jw.object(); + + List<Subsystem> subsystems = getSubsystems(); + + jw.key("status"); + jw.value(subsystems.size()); + + jw.key("data"); + jw.array(); + for (Subsystem ss : subsystems) + { + subsystem(jw, ss); + } + jw.endArray(); + + jw.endObject(); + } + catch (JSONException je) + { + throw new IOException(je); + } + } + + private void subsystem(JSONWriter jw, Subsystem ss) throws JSONException + { + jw.object(); + + jw.key("id"); + jw.value(ss.getSubsystemId()); + jw.key("name"); + jw.value(ss.getSymbolicName()); + jw.key("version"); + jw.value(ss.getVersion()); + jw.key("state"); + jw.value(ss.getState()); + + jw.endObject(); + } + + private List<Subsystem> getSubsystems() throws IOException + { + try + { + List<Subsystem> l = new ArrayList<Subsystem>(); + for (ServiceReference<Subsystem> ref : bundleContext.getServiceReferences(Subsystem.class, null)) + { + l.add(bundleContext.getService(ref)); + } + return l; + } + catch (InvalidSyntaxException e) + { + throw new IOException(e); + } + } + + public SimpleWebConsolePlugin register() + { + return register(bundleContext); + } + + static RequestInfo getRequestInfo(HttpServletRequest request) + { + return (RequestInfo) request.getAttribute(WebConsolePlugin.class.getName()); + } + + class RequestInfo + { + public final long id; + public final Object extension; + + protected RequestInfo(HttpServletRequest req) + { + String info = req.getPathInfo(); + // remove label and starting slash + info = info.substring(getLabel().length() + 1); + + // get extension + if (info.endsWith(".json")) + { + extension = "json"; + info = info.substring(0, info.length() - 5); + } + else + { + extension = "html"; + } + + if (info.startsWith("/")) + info = info.substring(1); + + if ("".equals(info)) + id = -1; + else + id = Long.parseLong(info); + + req.setAttribute(WebConsolePlugin.this.getClass().getName(), this); + } + } + + interface SubsystemOperation + { + void exec(Subsystem ss); + } +} Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties (added) +++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/OSGI-INF/l10n/bundle.properties Thu Jul 2 11:09:06 2015 @@ -0,0 +1,32 @@ +#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. + +# +# Web Console strings for reference all strings here are commented. +# This file may be used to produce a translation of the strings +# +# Note that properties files are ISO-8859-1 encoded. To provide translations +# for languages requiring different character encodings, you may use the +# native2ascii Maven Plugin from http://mojo.codehaus.org/native2ascii-maven-plugin/ +# to translate the natively encoded files to ISO-8859-1 during bundle build +# +# Translations requiring non-ISO-8859-1 encoding are placed in the +# src/main/native2ascii/OSGI-INF/l10n folder and are converted using said +# plugin while building the bundle +# + +# Components plugin +subsystems.name=Subsystem Name + Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html (added) +++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.html Thu Jul 2 11:09:06 2015 @@ -0,0 +1,92 @@ +<!-- + 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. +--> +<script type="text/javascript" src="${pluginRoot}/res/plugin.js"></script> +<script type="text/javascript"> +// <![CDATA[ +var ssData = ${__data__}; +// ]]> +</script> +<p class="statline"> </p> + + +<div id="subsystems"> <!-- data available --> + <!-- top header --> + <form method='post' enctype='multipart/form-data' action="${pluginRoot}"> + <div class="ui-widget-header ui-corner-top buttonGroup"> + <button class='installButton' type='button'>${install}</button> + </div> + </form> + + <table id="plugin_table" class="tablesorter nicetable noauto"> + <thead> + <tr> + <th class="col_Id">${id}</th> + <th class="col_Name">${subsystems.name}</th> + <th class="col_Version">${version}</th> + <th class="col_Status">Status</th> + <th class="col_Actions">Actions</th> + </tr> + </thead> + <tbody> + <tr> + <td> </td> <!-- id --> + <td> <!-- name with arrow --> + <div class="bIcon ui-icon ui-icon-triangle-1-e" style="float:left" title="Details"> </div> + </td> + <td> </td> <!-- version --> + <td> </td> <!-- status --> + <td> + <ul class="icons"> + <li class="dynhover ui-helper-hidden" title="${start}"><span class="ui-icon ui-icon-play"> </span></li> + <li class="dynhover ui-helper-hidden" title="${stop}"><span class="ui-icon ui-icon-stop"> </span></li> + <li class="dynhover" title="${bundles.uninstall}"><span class="ui-icon ui-icon-trash"> </span></li> + </ul> + </td> + </tr> + </tbody> + </table> +</div> <!-- end data available --> + +<!-- bottom header --> +<form method='post' enctype='multipart/form-data' action="${pluginRoot}"> + <div class="ui-widget-header ui-corner-bottom buttonGroup"> + <button class='installButton' type='button'>${install}</button> + </div> +</form> + +<!-- status line --> +<p class="statline"> </p> + +<div id="uploadDialog" class="ui-helper-hidden" title="Upload / Install Subsystem"> + <form method="post" enctype="multipart/form-data" action="${pluginRoot}"> + <table class="nicetable"> + <tr> + <td style="text-align:right">Start Subsystem</td> + <td> + <input type="hidden" name="action" value="install"/> + <input type="checkbox" name="subsystemstart" value="start"/> + </td> + </tr> + <tr> + <td> + <td> </td> + <input class="multi" accept="jar|zip|esa" type="file" name="subsystemfile" /> + </td> + </tr> + </table> + </form> +</div> Added: felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js?rev=1688806&view=auto ============================================================================== --- felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js (added) +++ felix/trunk/webconsole-plugins/subsystems/src/main/resources/res/plugin.js Thu Jul 2 11:09:06 2015 @@ -0,0 +1,95 @@ +/* + * 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 renderData( subsystemData ) { + tableBody.empty(); + for (var idx in subsystemData.data) { + entry( subsystemData.data[idx] ); + } +} + +function entry( dataEntry ) { + var id = dataEntry.id; + var name = dataEntry.name; + var _ = tableEntryTemplate.clone().appendTo(tableBody).attr('id', 'entry' + id); + + _.find('td:eq(0)').text(id); + _.find('td:eq(1)').text(name); + _.find('td:eq(2)').text(dataEntry.version); + _.find('td:eq(3)').text(dataEntry.state); + + // setup buttons + if (dataEntry.state === "ACTIVE") { + _.find('li:eq(1)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'stop') }); + } else { + _.find('li:eq(0)').removeClass('ui-helper-hidden').click(function() { changeDataEntryState(id, 'start') }); + } + _.find('li:eq(2)').click(function() { changeDataEntryState(id, 'uninstall') }); +} + +function changeDataEntryState(id, action) { + $.post(pluginRoot + '/' + id, {'action': action}, function(data) { + renderData(data); + + // This is a total hack, but it's the only way in which I could get the + // table to re-sort itself. TODO remove the next line and find a proper way. + window.location.reload(); + }, 'json'); +} + +var tableBody = false; +var tableEntryTemplate = false; +var pluginTable = false; +var uploadDialog = false; + +$(document).ready(function(){ + $('.installButton').click(function() { + uploadDialog.dialog('open'); + return false; + }); + + pluginTable = $('#plugin_table'); + tableBody = pluginTable.find('tbody'); + tableEntryTemplate = tableBody.find('tr').clone(); + + // upload dialog + var uploadDialogButtons = {}; + uploadDialogButtons["Install"] = function() { + $(this).find('form').submit(); + } + uploadDialog = $('#uploadDialog').dialog({ + autoOpen: false, + modal : true, + width : '50%', + buttons : uploadDialogButtons + }); + + renderData(ssData); + + $('.reloadButton').click(document.location.reload); + + pluginTable.tablesorter({ + headers: { + 0: { sorter:'digit'}, + 4: { sorter: false } + }, + sortList: [[1,0]], + textExtraction:mixedLinksExtraction + }); +}); +