/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ /** * */ package org.xmind.core.command.transfer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.osgi.util.NLS; import org.xmind.core.command.Command; import org.xmind.core.command.ICommand; import org.xmind.core.command.ICommandService; import org.xmind.core.command.IReturnValueConsumer; import org.xmind.core.command.ReturnValue; import org.xmind.core.command.arguments.Attributes; import org.xmind.core.command.binary.IBinaryStore; import org.xmind.core.internal.command.remote.Messages; import org.xmind.core.internal.command.remote.RemoteCommandPlugin; /** * A basic handler that handles incoming command requests from an input stream * and writes the return value to an output stream. * * @author Frank Shaka */ public class IncomingCommandHandler { private static final String DEBUG_OPTION = "/debug/incomingCommandHandler"; //$NON-NLS-1$ private static boolean DEBUGGING = RemoteCommandPlugin.getDefault() .isDebugging(DEBUG_OPTION); private Object remoteLocation = "(unknown location)"; //$NON-NLS-1$ private String pluginId = RemoteCommandPlugin.PLUGIN_ID; /** * */ public IncomingCommandHandler() { } /** * For debugging purpose only. * * @param location * the remote location representation */ public void setRemoteLocation(Object location) { if (location == null) { location = "(unknown location)"; //$NON-NLS-1$ } this.remoteLocation = location; } public Object getRemoteLocation() { return remoteLocation; } public void setPluginId(String pluginId) { if (pluginId == null) pluginId = RemoteCommandPlugin.PLUGIN_ID; this.pluginId = pluginId; } public String getPluginId() { return pluginId; } public IStatus handleIncomingCommand(IProgressMonitor monitor, InputStream input, OutputStream output) { ChunkReader reader = new ChunkReader(input); try { ChunkWriter writer = new ChunkWriter(output); try { return handleIncomingCommand(monitor, reader, writer); } finally { try { writer.close(); } catch (IOException e) { RemoteCommandPlugin.log(null, e); } } } finally { try { reader.close(); } catch (IOException e) { RemoteCommandPlugin.log(null, e); } } } public IStatus handleIncomingCommand(IProgressMonitor monitor, ChunkReader reader, ChunkWriter writer) { monitor.beginTask(null, 100); // Read command: monitor.subTask(Messages.IncomingCommandHandler_ReadCommand); IProgressMonitor readMonitor = new SubProgressMonitor(monitor, 10); ICommand command; try { command = readCommand(readMonitor, reader); } catch (Throwable e) { return createReadingErrorStatus(e); } if (command == null || monitor.isCanceled()) return Status.CANCEL_STATUS; readMonitor.done(); try { // Execute command: monitor.subTask(NLS.bind( Messages.IncomingCommandHandler_ExcuteCommand, command)); IProgressMonitor executeMonitor = new SubProgressMonitor(monitor, 90); IStatus returnValue = executeCommand(executeMonitor, command, writer); if (returnValue != null && !returnValue.isOK()) return returnValue; if (monitor.isCanceled()) return Status.CANCEL_STATUS; executeMonitor.done(); monitor.done(); return returnValue; } finally { IBinaryStore binaryStore = command.getBinaryStore(); if (binaryStore != null) binaryStore.clear(); } } private ICommand readCommand(IProgressMonitor monitor, ChunkReader reader) throws IOException { monitor.beginTask(null, 100); if (DEBUGGING) System.out.println("Start reading command from " //$NON-NLS-1$ + remoteLocation); // Read command: String uri = reader.readText(); if (uri == null) // No command available return null; if (DEBUGGING) System.out.println("Request received: " + uri); //$NON-NLS-1$ if (monitor.isCanceled()) return null; monitor.worked(50); // Read file arguments: String argumentType = reader.readText(); if (monitor.isCanceled()) return null; IBinaryStore files = null; IProgressMonitor filesMonitor = new SubProgressMonitor(monitor, 40); if (CommandTransferUtil.MARKER_FILES.equals(argumentType)) { files = CommandTransferUtil.readFiles(filesMonitor, reader); if (DEBUGGING) System.out.println("Files received: " + files); //$NON-NLS-1$ } if (monitor.isCanceled()) return null; filesMonitor.done(); // Build command: ICommand command = Command.parseURI(uri, files); if (monitor.isCanceled()) return null; monitor.done(); return command; } private IStatus executeCommand(IProgressMonitor monitor, ICommand command, final ChunkWriter writer) { // Retrieve command handling service: ICommandService commandService = RemoteCommandPlugin.getDefault() .getCommandService(); if (commandService == null) { try { writeReturnValue(monitor, new Status(IStatus.ERROR, getPluginId(), "No command handling service available."), //$NON-NLS-1$ writer); } catch (IOException e) { RemoteCommandPlugin.log(null, e); } return new Status(IStatus.WARNING, getPluginId(), "No command handling service available."); //$NON-NLS-1$ } if (monitor.isCanceled()) { try { writeReturnValue(monitor, Status.CANCEL_STATUS, writer); } catch (IOException e) { RemoteCommandPlugin.log(null, e); } return Status.CANCEL_STATUS; } // Execute command locally: IStatus returnValue = commandService.execute(monitor, command, new IReturnValueConsumer() { public IStatus consumeReturnValue(IProgressMonitor monitor, IStatus returnValue) { try { writeReturnValue(monitor, returnValue, writer); if (monitor.isCanceled()) return Status.CANCEL_STATUS; return Status.OK_STATUS; } catch (Throwable e) { return createWritingErrorStatus(e); } } }); if (monitor.isCanceled()) return Status.CANCEL_STATUS; monitor.done(); return returnValue; } /** * @param monitor * @param returnValue * @param writer * @return */ private void writeReturnValue(IProgressMonitor monitor, IStatus returnValue, ChunkWriter writer) throws IOException { if (DEBUGGING) System.out.println("Command executed: " + returnValue); //$NON-NLS-1$ monitor.beginTask(null, 100); monitor.subTask(Messages.IncomingCommandHandler_WriteReponseBack); // Write status: writer.writeText(String.valueOf(returnValue.getSeverity())); monitor.worked(10); // Write plugin ID: writer.writeText(returnValue.getPlugin() == null ? "" : returnValue.getPlugin()); //$NON-NLS-1$ monitor.worked(10); // Write plugin-specific code: writer.writeText(String.valueOf(returnValue.getCode())); monitor.worked(10); // Write message: writer.writeText(returnValue.getMessage()); monitor.worked(10); // Write return value: SubProgressMonitor writeValueMonitor = new SubProgressMonitor(monitor, 40); writeValue(writeValueMonitor, writer, returnValue); if (writeValueMonitor.isCanceled()) return; writeValueMonitor.done(); writer.writeText(""); //$NON-NLS-1$ monitor.worked(10); writer.flush(); monitor.worked(10); monitor.done(); } private void writeValue(IProgressMonitor monitor, ChunkWriter writer, IStatus returnValue) throws IOException { if (returnValue.isOK()) { if (returnValue instanceof ReturnValue) { Object value = ((ReturnValue) returnValue).getValue(); if (value instanceof Attributes) { Attributes attrs = (Attributes) value; monitor.beginTask(null, attrs.size()); writer.writeText(CommandTransferUtil.MARKER_PROPERTIES); Iterator<String> names = attrs.keys(); while (names.hasNext()) { String name = names.next(); writer.writeText(CommandTransferUtil.encode(name)); writer.writeText(CommandTransferUtil.encode(attrs .getString(name, ""))); //$NON-NLS-1$ monitor.worked(1); } } else if (value instanceof String[]) { String[] strings = (String[]) value; monitor.beginTask(null, strings.length); writer.writeText(CommandTransferUtil.MARKER_VALUES); for (int i = 0; i < strings.length; i++) { writer.writeText(CommandTransferUtil.encode(strings[i])); monitor.worked(1); } } else if (value instanceof IBinaryStore) { IBinaryStore files = (IBinaryStore) value; writer.writeText(CommandTransferUtil.MARKER_FILES); CommandTransferUtil.writeFiles(monitor, files, writer); } } } } protected IStatus createReadingErrorStatus(Throwable e) { // if (e instanceof EOFException) { // return new Status( // IStatus.WARNING, // getPluginId(), // Messages.IncomingCommandHandler_ConnectionClose, // e); // } return new Status(IStatus.ERROR, getPluginId(), null, e); } protected IStatus createWritingErrorStatus(Throwable e) { return new Status(IStatus.ERROR, getPluginId(), null, e); } }