/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.server.console.war.services; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import org.eclipse.osgi.framework.console.ConsoleSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import de.fhg.igd.osgi.util.OsgiUtils; /** * A REST service offering access to the OSGI console. The service accepts GET * requests containing the command and returns the command's result. * * @author Michel Kraemer */ @Controller @RequestMapping public class ConsoleController { /** * The OSGi console's prompt */ private static final String PROMPT = "osgi> "; /** * Can be used to send commands to the console session */ private PrintWriter _output; /** * Can be used to read command results from the console session */ private InputStream _input; /** * The OSGi console session */ private WebConsole _console; /** * An OSGi console */ private static class WebConsole extends ConsoleSession { private final InputStream _in; private final OutputStream _out; public WebConsole(InputStream in, OutputStream out) { _in = in; _out = out; } @Override protected void doClose() { // nothing to do here } @Override public InputStream getInput() { return _in; } @Override public OutputStream getOutput() { return _out; } } /** * Initializes this bean. Creates the console session * * @throws IOException if the initial prompt could not be read */ public void init() throws IOException { InputStream in = makeConsoleInput(); OutputStream out = makeConsoleOutput(); _console = new WebConsole(in, out); OsgiUtils.registerService(ConsoleSession.class, _console); // read initial prompt readLines(); } /** * Destroys this bean. Closes the console session */ public void destroy() { if (_console != null) { _console.close(); } } /** * Creates an InputStream that can be used in the console service to read * the commands. The input stream will be connected via a pipe with * {@link #_output}, so commands can be written to the output stream and * will be read by the console service. * * @return the input stream */ private InputStream makeConsoleInput() { PipedInputStream result = new PipedInputStream(1024 * 1024); try { OutputStream output = new PipedOutputStream(result); _output = new PrintWriter(new OutputStreamWriter(output)); } catch (IOException e) { throw new IllegalStateException("Could not create console pipe"); } return result; } /** * Creates an InputStream that can be used by the console service to write * command results. The output stream will be connected via a pipe with * {@link #_input}, so results can be read from that input stream. * * @return the output stream */ private OutputStream makeConsoleOutput() { PipedInputStream input = new PipedInputStream(1024 * 1024); _input = input; try { return new PipedOutputStream(input); } catch (IOException e) { throw new IllegalStateException("Could not create console pipe"); } } /** * Reads bytes from {@link #_input} until it finds the OSGi {@link #PROMPT}. * Truncates the prompt and returns the string read. * * @return the string or null if the console input stream ended * @throws IOException if the string could not be read */ private String readLines() throws IOException { int b = _input.read(); if (b == -1) { return null; } else { String result = new String(new byte[] { (byte) b }); byte[] buf = new byte[1024 * 64]; int len; while ((len = _input.read(buf, 0, buf.length)) > 0) { result += new String(buf, 0, len); if (result.endsWith(PROMPT)) { break; } } if (result.endsWith(PROMPT)) { result = result.substring(0, result.length() - 6); } return result; } } /** * Handles OSGi console commands * * @param command the command * @param response used to return the command's results * @throws IOException if the command could not be executed */ @RequestMapping(value = "/{command}") public void get(@PathVariable String command, HttpServletResponse response) throws IOException { // send command _output.write(command + "\r\n"); _output.flush(); response.setContentType("text/plain"); String lines = readLines(); if (lines == null) { response.getWriter().println("End of console stream"); } else { response.getOutputStream().write(lines.getBytes()); } } }