Java tutorial
/******************************************************************************* * Copyright (c) 2012 IBM and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.ptp.internal.remote.terminal; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.ptp.internal.remote.terminal.messages.Messages; import org.eclipse.remote.core.IRemoteCommandShellService; import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.remote.core.IRemoteConnectionHostService; import org.eclipse.remote.core.IRemoteFileService; import org.eclipse.remote.core.IRemoteProcess; import org.eclipse.remote.core.IRemoteProcessBuilder; import org.eclipse.remote.core.IRemoteProcessService; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.tm.terminal.remote.IRemoteTerminalParser; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; public class RemoteTerminalParser implements IRemoteTerminalParser { protected static Display getStandardDisplay() { Display display = Display.getCurrent(); if (display == null) { display = Display.getDefault(); } return display; } final static Pattern pattern = Pattern.compile("~~EPTP:(\\w*)~~(?:EDID=([\\w\\.]+)~~)?(.*)"); //$NON-NLS-1$ private IRemoteConnection fRemoteConnection; private IRemoteProcess fProcess; /** * Process special terminal actions * * @param type * @param str */ private void doAction(String type, final String str, final String arg) { if (type.equals("Radio")) { //$NON-NLS-1$ doRadioAction(str); } else if (type.equals("Choice")) { //$NON-NLS-1$ doChoiceAction(str, arg); } else if (type.equals("OpenFile")) { // open file //$NON-NLS-1$ openFile(str, arg); } } /** * The param "str" should be a list of files delimited by "~~". The * user will be shown a choice dialog, allowing the user to pick one * file to open. This selects one file from a list obtained by a shell * wild card. * * @param str */ private void doChoiceAction(final String str, final String arg) { final String[] choices = str.split("\\s*~~\\s*"); //$NON-NLS-1$ getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { try { final Dialog dialog = new Dialog(getStandardDisplay().getActiveShell()) { private Combo combo; private String[] comboChoices; @Override public void buttonPressed(int buttonId) { int n = combo.getSelectionIndex(); if (buttonId == 0 && n >= 0 && n < comboChoices.length) { openFile(comboChoices[n], arg); } close(); } @Override protected void configureShell(Shell shell) { shell.setText(Messages.CHOOSE_FILE); super.configureShell(shell); } @Override protected Control createDialogArea(Composite parent) { Composite container = (Composite) super.createDialogArea(parent); combo = new Combo(container, SWT.NONE); combo.setItems(choices); comboChoices = choices; Point pt = combo.computeSize(SWT.DEFAULT, SWT.DEFAULT); combo.setSize(pt.x, 5 * pt.y); return container; } }; dialog.open(); } catch (Exception t) { Activator.log(t); } } }); } /** * Creates a dialog with a radio button that will perform one shell command * from a list. The string ~~ is used to delimit commands, and ::~ is used * to separate user-displayed text from the command itself. Thus, a script * containing: * * <pre> * #!/bin/bash * echo "~~EPTP:Radio~~ List Files::~ls -F~~Current Dir::~pwd" * </pre> * * Will produce a menu allowing the user to select from "List Files" and * "Current Dir". The former will perform an "ls -F", the latter will * perform a "pwd" command. * * @param str */ private void doRadioAction(final String str) { final String[] choices = str.split("\\s*~~\\s*"); //$NON-NLS-1$ getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { try { final Dialog dialog = new Dialog(getStandardDisplay().getActiveShell()) { private final Map<String, String> smap = new HashMap<String, String>(); private final List<Button> buttons = new ArrayList<Button>(); @Override public void buttonPressed(int buttonId) { if (buttonId == 0) { for (Button b : buttons) { if (b.getSelection()) { String value = smap.get(b.getText()); try { OutputStream out = fProcess.getOutputStream(); out.write((value + "\n").getBytes()); //$NON-NLS-1$ out.flush(); } catch (IOException ioe) { } } } } close(); } @Override protected void configureShell(Shell shell) { shell.setText(Messages.CHOOSE_FILE); super.configureShell(shell); } @Override protected Control createDialogArea(Composite parent) { Composite container = (Composite) super.createDialogArea(parent); for (String choice : choices) { String[] keyvalue = choice.split("::~"); //$NON-NLS-1$ if (keyvalue.length == 2) { Button b = new Button(container, SWT.RADIO); b.setText(keyvalue[0]); smap.put(keyvalue[0], keyvalue[1]); buttons.add(b); } } return container; } }; dialog.open(); } catch (Exception t) { Activator.log(t); } } }); } /* * (non-Javadoc) * * @see org.eclipse.tm.terminal.remote.IRemoteTerminalParser#initialize(org.eclipse.remote.core.IRemoteConnection) */ @Override public IRemoteProcess initialize(IRemoteConnection connection) throws IOException { fRemoteConnection = connection; MachineManager.MachineInfo minfo = null; if (connection.hasService(IRemoteCommandShellService.class)) { IRemoteCommandShellService shellSvc = connection.getService(IRemoteCommandShellService.class); fProcess = shellSvc.getCommandShell(IRemoteProcessBuilder.ALLOCATE_PTY); } else { minfo = MachineManager.initializeMachine(connection); // Now that we know what SHELL is, throw away the builder and create a new one. List<String> shellCommand = new ArrayList<String>(); shellCommand.add(minfo.shell); shellCommand.add("-l"); //$NON-NLS-1$ IRemoteProcessService procSvc = connection.getService(IRemoteProcessService.class); IRemoteProcessBuilder processBuilder = procSvc.getProcessBuilder(shellCommand); fProcess = processBuilder.start(IRemoteProcessBuilder.ALLOCATE_PTY); } OutputStream outputStream = fProcess.getOutputStream(); // Tell history files where to write commands IRemoteConnectionHostService hostSvc = connection.getService(IRemoteConnectionHostService.class); MachineManager.setOutputStream(hostSvc.getHostname(), outputStream); IEclipsePreferences defaultPrefs = InstanceScope.INSTANCE.getNode(Activator.getUniqueIdentifier()); String startup = defaultPrefs.get(TerminalPrefsInitializer.SHELL_STARTUP_COMMAND, TerminalPrefsInitializer.SHELL_STARTUP_DEFAULT); if (minfo != null) { if (minfo.isCsh) { // convert to csh/tcsh syntax startup = startup.replaceFirst("ptprc.sh", "ptprc.csh"); //$NON-NLS-1$//$NON-NLS-2$ } else if (minfo.isBash) { // convert to bash syntax startup = startup.replaceFirst("ptprc.csh", "ptprc.sh"); //$NON-NLS-1$//$NON-NLS-2$ } } outputStream.write((startup + "\n").getBytes()); //$NON-NLS-1$ outputStream.flush(); return fProcess; } /** * Open a file on the remote machine. In this way, the user can * more easily take advantage of eclipse editing for all his/her files. * * Different logic applies inside a synched project than outside of it. * Opening a remote file involves synching, and would duplicate the work * of the synched project. It also might do it in a slightly inconsistent * way and if both a remote and local view of the same synched file was * open it might lead to confusion. * * @param file * - the file to open */ public void openFile(final String file, final String suffix) { IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (final IProject prj : projects) { final URI remoteURI = Util.getLocationURI(prj); if (remoteURI != null) { if (file.startsWith(remoteURI.getPath())) { // Found! getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage(); try { String loc = file.substring(remoteURI.getPath().length() + 1); IFile file = prj.getFile(loc); IDE.openEditor(page, file); } catch (PartInitException e) { Activator.log(e); } } }); return; } } } getStandardDisplay().asyncExec(new Runnable() { @Override public void run() { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); try { IEditorDescriptor editorDesc = IDE.getEditorDescriptor(file); IRemoteFileService fileSvc = fRemoteConnection.getService(IRemoteFileService.class); URI uri = fileSvc.toURI(file); String autoEditorId = editorDesc.getId(); String editorId = autoEditorId; if (suffix != null) { IEditorDescriptor suffixDesc = IDE.getEditorDescriptor("file." + suffix); //$NON-NLS-1$ if (suffixDesc != null) { editorId = suffixDesc.getId(); } } try { IDE.openEditor(page, uri, editorId, true); } catch (Exception e) { // Some editors are not supported remotely. Default to text editor. IEditorDescriptor suffixDesc = IDE.getEditorDescriptor("file.txt"); //$NON-NLS-1$ if (suffixDesc != null) { editorId = suffixDesc.getId(); } IDE.openEditor(page, uri, editorId, true); } } catch (PartInitException e) { Activator.log(e); } } }); return; } /* * (non-Javadoc) * * @see org.eclipse.tm.terminal.remote.IRemoteTerminalParser#parse(byte[]) */ @Override public boolean parse(byte[] buf) { // support advanced option, editor id String str = new String(buf); Matcher match = pattern.matcher(str); if (match.find()) { String cmd = match.group(1); if (match.groupCount() == 3) { String location = match.group(3); String suffix = match.group(2); doAction(cmd, location, suffix); } else { String location = match.group(2); doAction(cmd, location, null); } return false; } return true; } }