FELIX-563 Apply patch supplied by Fredrik Kjellberg (Thanks)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@683680 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java
new file mode 100644
index 0000000..06fcc52
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ShellServlet.java
@@ -0,0 +1,214 @@
+/*
+ * 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.internal.misc;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.shell.ShellService;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class ShellServlet extends AbstractWebConsolePlugin implements OsgiManagerPlugin
+{
+ private ServiceTracker shellTracker;
+
+
+ public String getLabel()
+ {
+ return "shell";
+ }
+
+
+ public String getTitle()
+ {
+ return "Shell";
+ }
+
+
+ protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ response.setCharacterEncoding( "utf-8" );
+ response.setContentType( "text/html" );
+
+ PrintWriter pw = response.getWriter();
+
+ try
+ {
+ String command = request.getParameter( "command" );
+
+ pw.print( "<span class=\"consolecommand\">-> " );
+ pw.print( command == null ? "" : escapeHtml( command ) );
+ pw.println( "</span><br />" );
+
+ if ( command != null && !"".equals( command ) )
+ {
+ ShellService shellService = getShellService();
+ if ( shellService != null )
+ {
+ ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+
+ shellService.executeCommand( command, new PrintStream( baosOut, true ), new PrintStream( baosErr,
+ true ) );
+ if ( baosOut.size() > 0 )
+ {
+ pw.print( escapeHtml( new String( baosOut.toByteArray() ) ) );
+ }
+ if ( baosErr.size() > 0 )
+ {
+ pw.print( "<span class=\"error\">" );
+ pw.print( escapeHtml( new String( baosErr.toByteArray() ) ) );
+ pw.println( "</span>" );
+ }
+ }
+ else
+ {
+ pw.print( "<span class=\"error\">" );
+ pw.print( "Error: No shell service available<br />" );
+ pw.println( "</span>" );
+ }
+ }
+ }
+ catch ( Throwable t )
+ {
+ pw.print( "<span class=\"error\">" );
+ StringWriter out = new StringWriter();
+ t.printStackTrace( new PrintWriter( out, true ) );
+ pw.print( escapeHtml( out.toString() ) );
+ pw.println( "</span>" );
+ }
+ }
+
+
+ protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ PrintWriter pw = response.getWriter();
+
+ String appRoot = request.getContextPath() + request.getServletPath();
+ pw.println( "<link href=\"" + appRoot + "/res/ui/shell.css\" rel=\"stylesheet\" type=\"text/css\" />" );
+ pw.println( "<script src=\"" + appRoot + "/res/ui/shell.js\" type=\"text/javascript\"></script>" );
+
+ pw.println( "<br />" );
+
+ pw.println( "<form name=\"shellCommandForm\" method=\"post\" action=\"" + appRoot
+ + "/shell\" title=\"Shell Command\" onsubmit=\"runShellCommand();return false;\">" );
+
+ pw.println( "<div class=\"consolebuttons\">" );
+ pw.println( "<input class=\"submit\" type=\"button\" value=\"Help\" onclick=\"executeCommand('help');\"/>" );
+ pw
+ .println( " <input class=\"submit\" type=\"button\" value=\"Clear\" onclick=\"clearConsole();\"/>" );
+ pw.println( "</div>" );
+
+ pw.println( "<div id=\"consoleframe\" class=\"consoleframe\" onclick=\"shellCommandFocus();\">" );
+ pw.println( "<div id=\"console\" class=\"console\" onclick=\"shellCommandFocus();\">" );
+ pw.println( "</div>" );
+
+ pw.println( "<span class=\"prompt\">" );
+ pw.println( "-> <input type=\"text\" name=\"command\" value=\"\" class=\"command\" autocomplete=\"off\"/>" );
+ pw.println( "</span>" );
+
+ pw.println( "</div>" );
+
+ pw.println( "</form>" );
+
+ pw.println( "<script type=\"text/javascript\">" );
+ pw.println( "shellCommandFocus();" );
+ pw.println( "</script>" );
+ }
+
+
+ protected ShellService getShellService()
+ {
+ return ( ( ShellService ) shellTracker.getService() );
+ }
+
+
+ public void activate( BundleContext bundleContext )
+ {
+ super.activate( bundleContext );
+
+ shellTracker = new ServiceTracker( bundleContext, ShellService.class.getName(), null );
+ shellTracker.open();
+ }
+
+
+ public void deactivate()
+ {
+ if ( shellTracker != null )
+ {
+ shellTracker.close();
+ shellTracker = null;
+ }
+
+ super.deactivate();
+ }
+
+
+ protected String escapeHtml( String text )
+ {
+ StringBuffer sb = new StringBuffer();
+ for ( int i = 0; i < text.length(); i++ )
+ {
+ char ch = text.charAt( i );
+ if ( ch == '<' )
+ {
+ sb.append( "<" );
+ }
+ else if ( ch == '>' )
+ {
+ sb.append( ">" );
+ }
+ else if ( ch == '&' )
+ {
+ sb.append( "&" );
+ }
+ else if ( ch == ' ' )
+ {
+ sb.append( " " );
+ }
+ else if ( ch == '\r' )
+ {
+ }
+ else if ( ch == '\n' )
+ {
+ sb.append( "<br />\r\n" );
+ }
+ else
+ {
+ sb.append( ch );
+ }
+ }
+
+ return ( sb.toString() );
+ }
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 59fbd7c..f438c03 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -48,6 +48,7 @@
import org.apache.felix.webconsole.internal.core.SetStartLevelAction;
import org.apache.felix.webconsole.internal.misc.ConfigurationRender;
import org.apache.felix.webconsole.internal.misc.LicenseServlet;
+import org.apache.felix.webconsole.internal.misc.ShellServlet;
import org.apache.felix.webconsole.internal.obr.BundleRepositoryRender;
import org.apache.felix.webconsole.internal.obr.RefreshRepoAction;
import org.apache.felix.webconsole.internal.system.GCAction;
@@ -129,7 +130,7 @@
{ ComponentConfigurationPrinter.class, ComponentsServlet.class, ConfigManager.class, BundlesServlet.class,
InstallAction.class, SetStartLevelAction.class, ConfigurationRender.class, GCAction.class,
ShutdownAction.class, ShutdownRender.class, VMStatRender.class, BundleRepositoryRender.class,
- LicenseServlet.class, RefreshRepoAction.class };
+ LicenseServlet.class, RefreshRepoAction.class, ShellServlet.class };
private BundleContext bundleContext;
@@ -320,7 +321,7 @@
{
req.setAttribute( ATTR_LABEL_MAP, labelMap );
req.setAttribute( ATTR_APP_ROOT, request.getContextPath() + request.getServletPath() );
-
+
plugin.service( req, res );
}
else
diff --git a/webconsole/src/main/resources/res/ui/shell.css b/webconsole/src/main/resources/res/ui/shell.css
new file mode 100644
index 0000000..111f8c0
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/shell.css
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+div.consolebuttons {
+ text-align: right;
+ border: none;
+ width: 955px;
+ padding-bottom: 2px;
+}
+
+div.consoleframe {
+ font-family: "Courier New", Courier, monospace;
+ font-size: 12px;
+ font-weight: normal;
+ background-color: #f0f0f0;
+ color: #000000;
+ border: 1px solid #999999;
+ width: 955px;
+ height: 500px;
+ overflow: auto;
+}
+
+div.console {
+}
+
+span.consolecommand {
+ white-space: pre;
+}
+
+span.error {
+ color: #ff0000;
+}
+
+span.prompt {
+ padding-left: 0px;
+ padding-top: 2px;
+ padding-bottom: 3px;
+}
+
+input.command {
+ font-family: "Courier New", Courier, monospace;
+ font-size: 12px;
+ font-weight: normal;
+ background-color: #f0f0f0;
+ color: #000000;
+ border: none;
+ width: 900px;
+ margin-left: -1px;
+ margin-top: -1px;
+}
diff --git a/webconsole/src/main/resources/res/ui/shell.js b/webconsole/src/main/resources/res/ui/shell.js
new file mode 100644
index 0000000..a36257c
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/shell.js
@@ -0,0 +1,86 @@
+/*
+ * 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 executeCommand(command) {
+ var xmlhttp = getXmlHttp();
+ if (!xmlhttp) {
+ return;
+ }
+
+ if (xmlhttp.readyState < 4) {
+ xmlhttp.abort();
+ }
+
+ var url = document.location;
+
+ xmlhttp.open("POST", url);
+
+ // set If-Modified-Since way back in the past to prevent
+ // using any content from the cache
+ xmlhttp.setRequestHeader("If-Modified-Since", new Date(0));
+ xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
+
+ xmlhttp.onreadystatechange = updateConsole;
+
+ xmlhttp.send("command=" + encodeURIComponent(command));
+}
+
+function updateConsole() {
+ var xmlhttp = getXmlHttp();
+ if (!xmlhttp || xmlhttp.readyState != 4) {
+ return;
+ }
+
+ var result = xmlhttp.responseText;
+ if (!result) {
+ return;
+ }
+
+ var console = document.getElementById("console");
+
+ console.style.display = "";
+ console.innerHTML = console.innerHTML + result;
+
+ var consoleframe = document.getElementById("consoleframe");
+ consoleframe.scrollTop = console.scrollHeight;
+
+ document.forms["shellCommandForm"].elements["command"].value = "";
+
+ shellCommandFocus();
+}
+
+function clearConsole() {
+ var console = document.getElementById("console");
+
+ console.style.display = "none";
+ console.innerHTML = "";
+
+ var consoleframe = document.getElementById("consoleframe");
+ consoleframe.scrollTop = 0;
+
+ shellCommandFocus();
+}
+
+function shellCommandFocus() {
+ document.forms["shellCommandForm"].elements["command"].focus();
+}
+
+function runShellCommand() {
+ var command = document.forms["shellCommandForm"].elements["command"].value;
+
+ executeCommand(command);
+}