diff options
Diffstat (limited to 'plugins/org.eclipse.tcf.rse/src')
28 files changed, 4548 insertions, 0 deletions
diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Activator.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Activator.java new file mode 100644 index 000000000..794836daa --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Activator.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.tm.tcf.rse"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + public ImageDescriptor getImageDescriptorFromPath(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFService.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFService.java new file mode 100644 index 000000000..79f1e4624 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFService.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Adapted from org.eclipse.rse.internal.services.ssh.ISshService + * Copyright (c) 2006, 2010 Wind River Systems, Inc. + * 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 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [170910] Adopt RSE ITerminalService API for SSH + * Intel Corporation - [329654] Make all sub services operate against TCF connector service + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +/** + * Markup Interface for services using the TCFConnectorService. + * + * By implementing this interface, services can be recognized + * as operating against an TCFConnectorService. The interface + * is used as the key in a table for looking up the connector + * service when needed. + */ +public interface ITCFService { +}
\ No newline at end of file diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSessionProvider.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSessionProvider.java new file mode 100644 index 000000000..a39e892c2 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSessionProvider.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010 Intel Corporation. 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 + * + * Contributors: + * Intel Corporation - initial API and implementation + ******************************************************************************/ + +package org.eclipse.tm.internal.tcf.rse; + +import org.eclipse.rse.services.files.RemoteFileException; +import org.eclipse.tm.tcf.protocol.IChannel; + +public interface ITCFSessionProvider { + public static final int ERROR_CODE = 100; // filed error code + public static final int SUCCESS_CODE = 150; // login pass code + public static final int CONNECT_CLOSED = 200; // code for end of login attempts + public static final int TCP_CONNECT_TIMEOUT = 10; //seconds - TODO: Make configurable + + public IChannel getChannel(); + public String getSessionUserId(); + public String getSessionPassword(); + public String getSessionHostName(); + public boolean isSubscribed(); + public void subscribe() throws RemoteFileException; +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSubSystem.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSubSystem.java new file mode 100644 index 000000000..30bc23f90 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/ITCFSubSystem.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import org.eclipse.rse.core.subsystems.ISubSystem; + +/** + * Subsystem can implement this interface to indicate that it can share TCF connection with + * other subsystems on same host. + */ +public interface ITCFSubSystem extends ISubSystem { + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.java new file mode 100644 index 000000000..2ea0c0645 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Intel Corp. - Add TCF Connection Descriptions and File System Style + * Liping Ke(Intel Corp.) - Add TCF Terminal/Shell Services Descriptions + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + + public static String SysMonitor_AllProcesses; + public static String SysMonitor_Process; + + // PROCESS PROPERTIES + public static String PROCESS_ID_LABEL; + public static String PROCESS_PID_LABEL; + public static String PROCESS_NAME_LABEL; + public static String PROCESS_CWD_LABEL; + public static String PROCESS_ROOT_LABEL; + public static String PROCESS_UID_LABEL; + public static String PROCESS_USERNAME_LABEL; + public static String PROCESS_GID_LABEL; + public static String PROCESS_GROUPNAME_LABEL; + public static String PROCESS_PPID_LABEL; + public static String PROCESS_PGRP_LABEL; + public static String PROCESS_STATE_LABEL; + public static String PROCESS_TRACERPID_LABEL; + public static String PROCESS_VMSIZE_LABEL; + public static String PROCESS_VMRSS_LABEL; + public static String PROCESS_SESSION_LABEL; + public static String PROCESS_TTY_LABEL; + public static String PROCESS_TGID_LABEL; + public static String PROCESS_FLAGS_LABEL; + public static String PROCESS_MINFLT_LABEL; + public static String PROCESS_CMINFLT_LABEL; + public static String PROCESS_MAJFLT_LABEL; + public static String PROCESS_CMAJFLT_LABEL; + public static String PROCESS_UTIME_LABEL; + public static String PROCESS_STIME_LABEL; + public static String PROCESS_CUTIME_LABEL; + public static String PROCESS_CSTIME_LABEL; + public static String PROCESS_PC_UTIME_LABEL; + public static String PROCESS_PC_STIME_LABEL; + public static String PROCESS_PRIORITY_LABEL; + public static String PROCESS_NICE_LABEL; + public static String PROCESS_ITREALVALUE_LABEL; + public static String PROCESS_STARTTIME_LABEL; + public static String PROCESS_RLIMIT_LABEL; + public static String PROCESS_CODESTART_LABEL; + public static String PROCESS_CODEEND_LABEL; + public static String PROCESS_STACKSTART_LABEL; + public static String PROCESS_SIGNALS_LABEL; + public static String PROCESS_SIGBLOCK_LABEL; + public static String PROCESS_SIGIGNORE_LABEL; + public static String PROCESS_SIGCATCH_LABEL; + public static String PROCESS_WCHAN_LABEL; + public static String PROCESS_NSWAP_LABEL; + public static String PROCESS_CNSWAP_LABEL; + public static String PROCESS_EXITSIGNAL_LABEL; + public static String PROCESS_PROCESSOR_LABEL; + public static String PROCESS_RTPRIORITY_LABEL; + public static String PROCESS_POLICY_LABEL; + + public static String PROCESS_ID_TOOLTIP; + public static String PROCESS_PID_TOOLTIP; + public static String PROCESS_NAME_TOOLTIP; + public static String PROCESS_CWD_TOOLTIP; + public static String PROCESS_ROOT_TOOLTIP; + public static String PROCESS_UID_TOOLTIP; + public static String PROCESS_USERNAME_TOOLTIP; + public static String PROCESS_GID_TOOLTIP; + public static String PROCESS_GROUPNAME_TOOLTIP; + public static String PROCESS_PPID_TOOLTIP; + public static String PROCESS_PGRP_TOOLTIP; + public static String PROCESS_STATE_TOOLTIP; + public static String PROCESS_TRACERPID_TOOLTIP; + public static String PROCESS_VMSIZE_TOOLTIP; + public static String PROCESS_VMRSS_TOOLTIP; + public static String PROCESS_SESSION_TOOLTIP; + public static String PROCESS_TTY_TOOLTIP; + public static String PROCESS_TGID_TOOLTIP; + public static String PROCESS_FLAGS_TOOLTIP; + public static String PROCESS_MINFLT_TOOLTIP; + public static String PROCESS_CMINFLT_TOOLTIP; + public static String PROCESS_MAJFLT_TOOLTIP; + public static String PROCESS_CMAJFLT_TOOLTIP; + public static String PROCESS_UTIME_TOOLTIP; + public static String PROCESS_STIME_TOOLTIP; + public static String PROCESS_PC_UTIME_TOOLTIP; + public static String PROCESS_PC_STIME_TOOLTIP; + public static String PROCESS_CUTIME_TOOLTIP; + public static String PROCESS_CSTIME_TOOLTIP; + public static String PROCESS_PRIORITY_TOOLTIP; + public static String PROCESS_NICE_TOOLTIP; + public static String PROCESS_ITREALVALUE_TOOLTIP; + public static String PROCESS_STARTTIME_TOOLTIP; + public static String PROCESS_RLIMIT_TOOLTIP; + public static String PROCESS_CODESTART_TOOLTIP; + public static String PROCESS_CODEEND_TOOLTIP; + public static String PROCESS_STACKSTART_TOOLTIP; + public static String PROCESS_SIGNALS_TOOLTIP; + public static String PROCESS_SIGBLOCK_TOOLTIP; + public static String PROCESS_SIGIGNORE_TOOLTIP; + public static String PROCESS_SIGCATCH_TOOLTIP; + public static String PROCESS_WCHAN_TOOLTIP; + public static String PROCESS_NSWAP_TOOLTIP; + public static String PROCESS_CNSWAP_TOOLTIP; + public static String PROCESS_EXITSIGNAL_TOOLTIP; + public static String PROCESS_PROCESSOR_TOOLTIP; + public static String PROCESS_RTPRIORITY_TOOLTIP; + public static String PROCESS_POLICY_TOOLTIP; + + public static String PROCESS_VMSIZE_VALUE; + public static String PROCESS_VMRSS_VALUE; + public static String IS_UNIX_STYLE; + + public static String TCFConnectorService_Name; + public static String TCFConnectorService_Description; + public static String TCFFileService_CopyingFiles; + public static String TCFFileService_DeletingFiles; + public static String TCFFileService_FileNotFoundMessage; + public static String TCFFileService_UserCancellation; + public static String TCFFileService_UserCancellation1; + public static String TCFFileService_UserDeleteCancellation; + public static String TCFFileService_UserDeleteCancellation1; + public static String PropertySet_Description; + + public static String TCFPlugin_Unexpected_Exception; + public static String TCFTerminalService_Description; + public static String TCFTerminalService_Name; + public static String TCFShellService_Description; + public static String TCFShellService_Name; + + static { + // initialize resource bundle + NLS.initializeMessages(Messages.class.getName(), Messages.class); + } + + private Messages() { + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.properties b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.properties new file mode 100644 index 000000000..fee3cc5f4 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/Messages.properties @@ -0,0 +1,137 @@ +################################################################################ +# Copyright (c) 2007, 2010 Wind River Systems, Inc. +# 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 +# +# Contributors: +# Wind River Systems - initial API and implementation +# Intel Corp. - Add TCF Connection Descriptions and File System Style +# Liping Ke(Intel Corp.) - Add TCF Terminal/shell service Descriptions +################################################################################ + +# NLS_MESSAGEFORMAT_VAR +# NLS_ENCODING=UTF-8 + +SysMonitor_AllProcesses=All Processes +SysMonitor_Process=Process + +PROCESS_ID_LABEL=Context ID +PROCESS_PID_LABEL=Process ID +PROCESS_NAME_LABEL=Executable Name +PROCESS_CWD_LABEL=CWD +PROCESS_ROOT_LABEL=FS Root +PROCESS_UID_LABEL=User ID +PROCESS_USERNAME_LABEL=Username +PROCESS_GID_LABEL=Group ID +PROCESS_GROUPNAME_LABEL=Groupname +PROCESS_PPID_LABEL=Parent PID +PROCESS_PGRP_LABEL=Proucess Group +PROCESS_STATE_LABEL=State +PROCESS_TRACERPID_LABEL=Tracer PID +PROCESS_VMSIZE_LABEL=VM Size +PROCESS_VMRSS_LABEL=VM RSS +PROCESS_SESSION_LABEL=Session +PROCESS_TTY_LABEL=TTY +PROCESS_TGID_LABEL=Task Group ID +PROCESS_FLAGS_LABEL=Flags +PROCESS_MINFLT_LABEL=Minor Faults +PROCESS_CMINFLT_LABEL=Children Minor Faults +PROCESS_MAJFLT_LABEL=Major Faults +PROCESS_CMAJFLT_LABEL=Children Major Faults +PROCESS_UTIME_LABEL=User Time +PROCESS_STIME_LABEL=System Time +PROCESS_CUTIME_LABEL=Children User Time +PROCESS_CSTIME_LABEL=Children System Time +PROCESS_PC_UTIME_LABEL=% User Time +PROCESS_PC_STIME_LABEL=% System Time +PROCESS_PRIORITY_LABEL=Priority +PROCESS_NICE_LABEL=Nice +PROCESS_ITREALVALUE_LABEL=Interval Timer +PROCESS_STARTTIME_LABEL=Start Time +PROCESS_RLIMIT_LABEL=RSS Limit +PROCESS_CODESTART_LABEL=Code Start +PROCESS_CODEEND_LABEL=Code End +PROCESS_STACKSTART_LABEL=Stack Start +PROCESS_SIGNALS_LABEL=Pending Signals +PROCESS_SIGBLOCK_LABEL=Blocked Signals +PROCESS_SIGIGNORE_LABEL=Ignored Signals +PROCESS_SIGCATCH_LABEL=Caught Signals +PROCESS_WCHAN_LABEL=Wait Channel +PROCESS_NSWAP_LABEL=Swaped Pages +PROCESS_CNSWAP_LABEL=Children Swapped Pages +PROCESS_EXITSIGNAL_LABEL=Exit Signal +PROCESS_PROCESSOR_LABEL=Processor +PROCESS_RTPRIORITY_LABEL=Real Time Priority +PROCESS_POLICY_LABEL=Scheduling Policy + +PROCESS_ID_TOOLTIP=TCF context ID of the process +PROCESS_PID_TOOLTIP=The system ID number of the process +PROCESS_NAME_TOOLTIP=The executable associated with the process +PROCESS_CWD_TOOLTIP=Current working directory of the process +PROCESS_ROOT_TOOLTIP=Current file system root of the process +PROCESS_UID_TOOLTIP=The user ID of the owner of the process +PROCESS_USERNAME_TOOLTIP=The username of the owner of the process +PROCESS_GID_TOOLTIP=The group ID of the owner of the process +PROCESS_GROUPNAME_TOOLTIP=The groupname of the owner of the process +PROCESS_PPID_TOOLTIP=The process ID of the parent of the process +PROCESS_PGRP_TOOLTIP=The process group ID +PROCESS_STATE_TOOLTIP=The state in which the process currently is +PROCESS_TRACERPID_TOOLTIP=The tracer process ID of the process +PROCESS_VMSIZE_TOOLTIP=The amount of virtual memory taken up by this process +PROCESS_VMRSS_TOOLTIP=The amount of virtual memory resident set size of this process (actual RAM taken up by the process) +PROCESS_SESSION_TOOLTIP=The session ID of the process +PROCESS_TTY_TOOLTIP=The TTY the process uses +PROCESS_TGID_TOOLTIP=The task group to which process belongs +PROCESS_FLAGS_TOOLTIP=The kernel flags word of the process. +PROCESS_MINFLT_TOOLTIP=The number of minor faults the process has made which have not required loading a memory page from disk. +PROCESS_CMINFLT_TOOLTIP=The number of minor faults that the process's waited-for children have made. +PROCESS_MAJFLT_TOOLTIP=The number of major faults the process has made which have required loading a memory page from disk. +PROCESS_CMAJFLT_TOOLTIP=Children Major Faults +PROCESS_UTIME_TOOLTIP=User Time +PROCESS_STIME_TOOLTIP=System Time +PROCESS_CUTIME_TOOLTIP=Children User Time +PROCESS_CSTIME_TOOLTIP=Children System Time +PROCESS_PC_UTIME_TOOLTIP=% User Time +PROCESS_PC_STIME_TOOLTIP=% System Time +PROCESS_PRIORITY_TOOLTIP=Priority +PROCESS_NICE_TOOLTIP=Nice +PROCESS_ITREALVALUE_TOOLTIP=Interval Timer +PROCESS_STARTTIME_TOOLTIP=Start Time +PROCESS_RLIMIT_TOOLTIP=RSS Limit +PROCESS_CODESTART_TOOLTIP=Code Start +PROCESS_CODEEND_TOOLTIP=Code End +PROCESS_STACKSTART_TOOLTIP=Stack Start +PROCESS_SIGNALS_TOOLTIP=Pending Signals +PROCESS_SIGBLOCK_TOOLTIP=Blocked Signals +PROCESS_SIGIGNORE_TOOLTIP=Ignored Signals +PROCESS_SIGCATCH_TOOLTIP=Caught Signals +PROCESS_WCHAN_TOOLTIP=Wait Channel +PROCESS_NSWAP_TOOLTIP=Swaped Pages +PROCESS_CNSWAP_TOOLTIP=Children Swapped Pages +PROCESS_EXITSIGNAL_TOOLTIP=Exit Signal +PROCESS_PROCESSOR_TOOLTIP=Processor +PROCESS_RTPRIORITY_TOOLTIP=Real Time Priority +PROCESS_POLICY_TOOLTIP=Scheduling Policy + +TCFConnectorService_Name=TCF Connector Service +TCFConnectorService_Description=Target Communication Framework +TCFFileService_CopyingFiles=Copying remote files\! +TCFFileService_DeletingFiles=Deleting selected folders or files\! +TCFFileService_FileNotFoundMessage=Failed to find the file to be copied file or directory\! +TCFFileService_UserCancellation=User cancelled the copy operation\! +TCFFileService_UserCancellation1=User cancelled the copy operation\! +TCFFileService_UserDeleteCancellation=User cancelled the delete operation\! +TCFFileService_UserDeleteCancellation1=User cancelled the delete operation\! +PropertySet_Description=TCF login properties. Set these according to your remote system's login prompts. + +TCFPlugin_Unexpected_Exception=Unexpected {0}: {1} +TCFTerminalService_Name=TCF Terminal Service +TCFTerminalService_Description=TCF Terminal Service Description +TCFShellService_Name=TCF Shell Service +TCFShellService_Description=TCF Shell Service Description + +PROCESS_VMSIZE_VALUE={0} KB +PROCESS_VMRSS_VALUE={0} KB +IS_UNIX_STYLE=true
\ No newline at end of file diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorService.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorService.java new file mode 100644 index 000000000..905ca1563 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorService.java @@ -0,0 +1,390 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Martin Oberhuber (Wind River) - [269682] Get port from RSE Property + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Anna Dushistova (MontaVista) - [285373] TCFConnectorService should send CommunicationsEvent.BEFORE_CONNECT and CommunicationsEvent.BEFORE_DISCONNECT + * Liping Ke (Intel Corp.)- [326490] Add authentication to the TCF Connector Service and attach stream subs/unsubs method + * Jeff Johnston (RedHat) - [350752] TCFConnectorService doesn't recognize connections with SSL transport + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.model.IPropertySet; +import org.eclipse.rse.core.model.PropertyType; +import org.eclipse.rse.core.model.SystemSignonInformation; +import org.eclipse.rse.core.subsystems.CommunicationsEvent; +import org.eclipse.rse.services.files.RemoteFileException; +import org.eclipse.rse.ui.subsystems.StandardConnectorService; +import org.eclipse.tm.tcf.core.AbstractPeer; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.IService; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.IFileSystem; +import org.eclipse.tm.tcf.services.ILocator; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.services.ISysMonitor; +import org.eclipse.tm.tcf.services.ITerminals; +import org.eclipse.tm.tcf.util.TCFTask; + + +public class TCFConnectorService extends StandardConnectorService implements ITCFSessionProvider{ + + public static final String PROPERTY_SET_NAME = "TCF Connection Settings"; //$NON-NLS-1$ + public static final String PROPERTY_LOGIN_REQUIRED = "Login.Required"; //$NON-NLS-1$ + public static final String PROPERTY_PWD_REQUIRED="Pwd.Required"; //$NON-NLS-1$ + public static final String PROPERTY_LOGIN_PROMPT = "Login.Prompt"; //$NON-NLS-1$ + public static final String PROPERTY_PASSWORD_PROMPT = "Password.Prompt"; //$NON-NLS-1$ + public static final String PROPERTY_COMMAND_PROMPT = "Command.Prompt"; //$NON-NLS-1$ + + private IChannel channel; + private Throwable channel_error; + private final List<Runnable> wait_list = new ArrayList<Runnable>(); + + private boolean poll_timer_started; + + private boolean bSubscribed = false; + + /* subscribe the stream service on this TCP connection */ + private IStreams.StreamsListener streamListener = new IStreams.StreamsListener() { + public void created(String stream_type, String stream_id, + String context_id) { + } + /** + * Called when a stream is disposed. + * + * @param stream_type + * - source type of the stream. + * @param stream_id + * - ID of the stream. + */ + public void disposed(String stream_type, String stream_id) { + } + }; + + + public TCFConnectorService(IHost host, int port) { + super(Messages.TCFConnectorService_Name, + Messages.TCFConnectorService_Description, host, + port); + getTCFPropertySet(); + } + + public IPropertySet getTCFPropertySet() { + IPropertySet tcfSet = getPropertySet(PROPERTY_SET_NAME); + if (tcfSet == null) { + tcfSet = createPropertySet(PROPERTY_SET_NAME, Messages.PropertySet_Description); + //add default values if not set + tcfSet.addProperty(PROPERTY_LOGIN_REQUIRED, "false", PropertyType.getEnumPropertyType(new String[] {"true", "false"})); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + tcfSet.addProperty(PROPERTY_PWD_REQUIRED, "false", PropertyType.getEnumPropertyType(new String[] {"true", "false"})); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + tcfSet.addProperty(PROPERTY_LOGIN_PROMPT, "ogin: ", PropertyType.getStringPropertyType()); //$NON-NLS-1$ + tcfSet.addProperty(PROPERTY_PASSWORD_PROMPT, "assword: ", PropertyType.getStringPropertyType()); //$NON-NLS-1$ + tcfSet.addProperty(PROPERTY_COMMAND_PROMPT, "#", PropertyType.getStringPropertyType()); //$NON-NLS-1$ + } + return tcfSet; + } + + /** + * @return true if the associated connector service requires a password. + */ + + public final boolean requiresPassword() { + return false; + } + + @Override + protected void internalConnect(final IProgressMonitor monitor) throws Exception { + assert !Protocol.isDispatchThread(); + final Exception[] res = new Exception[1]; + // Fire comm event to signal state about to change + fireCommunicationsEvent(CommunicationsEvent.BEFORE_CONNECT); + monitor.beginTask("Connecting " + getHostName(), 1); //$NON-NLS-1$ + synchronized (res) { + Protocol.invokeLater(new Runnable() { + public void run() { + if (!connectTCFChannel(res, monitor)) + add_to_wait_list(this); + } + }); + res.wait(); + } + if (res[0] != null) throw res[0]; + monitor.done(); + } + + @Override + protected void internalDisconnect(final IProgressMonitor monitor) + throws Exception { + assert !Protocol.isDispatchThread(); + final Exception[] res = new Exception[1]; + // Fire comm event to signal state about to change + fireCommunicationsEvent(CommunicationsEvent.BEFORE_DISCONNECT); + monitor.beginTask("Disconnecting " + getHostName(), 1); //$NON-NLS-1$ + try { + /* First UnSubscribe TCP channel */ + unsubscribe(); + /* Disconnecting TCP channel */ + synchronized (res) { + Protocol.invokeLater(new Runnable() { + public void run() { + if (!disconnectTCFChannel(res, monitor)) + add_to_wait_list(this); + } + }); + res.wait(); + } + if (res[0] != null) throw res[0]; + + } + catch (Exception e) { + e.printStackTrace(); + throw new RemoteFileException("Error creating Terminal", e); //$NON-NLS-1$ + } + finally { + monitor.done(); + } + } + + public boolean isConnected() { + final boolean res[] = new boolean[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { + res[0] = channel != null && channel.getState() == IChannel.STATE_OPEN; + } + }); + return res[0]; + } + + private void add_to_wait_list(Runnable cb) { + wait_list.add(cb); + if (poll_timer_started) return; + Protocol.invokeLater(1000, new Runnable() { + public void run() { + poll_timer_started = false; + run_wait_list(); + } + }); + poll_timer_started = true; + } + + private void run_wait_list() { + if (wait_list.isEmpty()) return; + Runnable[] r = wait_list.toArray(new Runnable[wait_list.size()]); + wait_list.clear(); + for (int i = 0; i < r.length; i++) r[i].run(); + } + + private boolean connectTCFChannel(Exception[] res, IProgressMonitor monitor) { + if (channel != null) { + switch (channel.getState()) { + case IChannel.STATE_OPEN: + case IChannel.STATE_CLOSED: + synchronized (res) { + if (channel_error instanceof Exception) res[0] = (Exception)channel_error; + else if (channel_error != null) res[0] = new Exception(channel_error); + else res[0] = null; + res.notify(); + return true; + } + } + } + if (monitor.isCanceled()) { + synchronized (res) { + res[0] = new Exception("Canceled"); //$NON-NLS-1$ + if (channel != null) channel.terminate(res[0]); + res.notify(); + return true; + } + } + if (channel == null) { + String host = getHostName().toLowerCase(); + int port = getConnectPort(); + if (port <= 0) { + //Default fallback + port = TCFConnectorServiceManager.TCF_PORT; + } + IPeer peer = null; + String port_str = Integer.toString(port); + ILocator locator = Protocol.getLocator(); + for (IPeer p : locator.getPeers().values()) { + Map<String, String> attrs = p.getAttributes(); + if (("TCP".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)) || //$NON-NLS-1$ + "SSL".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)))&& //$NON-NLS-1$ + host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) && + port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) { + peer = p; + break; + } + } + if (peer == null) { + Map<String, String> attrs = new HashMap<String, String>(); + attrs.put(IPeer.ATTR_ID, "RSE:" + host + ":" + port_str); //$NON-NLS-1$ //$NON-NLS-2$ + attrs.put(IPeer.ATTR_NAME, getName()); + attrs.put(IPeer.ATTR_TRANSPORT_NAME, "TCP"); //$NON-NLS-1$ + attrs.put(IPeer.ATTR_IP_HOST, host); + attrs.put(IPeer.ATTR_IP_PORT, port_str); + peer = new AbstractPeer(attrs); + } + channel = peer.openChannel(); + channel.addChannelListener(new IChannel.IChannelListener() { + + public void onChannelOpened() { + assert channel != null; + run_wait_list(); + } + + public void congestionLevel(int level) { + } + + public void onChannelClosed(Throwable error) { + assert channel != null; + channel.removeChannelListener(this); + channel_error = error; + if (wait_list.isEmpty()) { + fireCommunicationsEvent(CommunicationsEvent.CONNECTION_ERROR); + } + else { + run_wait_list(); + } + bSubscribed = false; + channel = null; + channel_error = null; + } + + }); + assert channel.getState() == IChannel.STATE_OPENING; + } + return false; + } + + private boolean disconnectTCFChannel(Exception[] res, IProgressMonitor monitor) { + if (channel == null || channel.getState() == IChannel.STATE_CLOSED) { + synchronized (res) { + res[0] = null; + res.notify(); + return true; + } + } + if (monitor.isCanceled()) { + synchronized (res) { + res[0] = new Exception("Canceled"); //$NON-NLS-1$ + res.notify(); + return true; + } + } + if (channel.getState() == IChannel.STATE_OPEN) channel.close(); + return false; + } + + public <V extends IService> V getService(Class<V> service_interface) { + if (channel == null || channel.getState() != IChannel.STATE_OPEN) throw new Error("Not connected"); //$NON-NLS-1$ + V m = channel.getRemoteService(service_interface); + if (m == null) throw new Error("Remote peer does not support " + service_interface.getName() + " service"); //$NON-NLS-1$ //$NON-NLS-2$ + return m; + } + + public ISysMonitor getSysMonitorService() { + return getService(ISysMonitor.class); + } + + public IFileSystem getFileSystemService() { + return getService(IFileSystem.class); + } + + public IChannel getChannel() { + return channel; + } + + public String getSessionHostName() { + String hostName = ""; + IHost host = getHost(); + if (host != null) hostName = host.getHostName(); + return hostName; + } + + public String getSessionUserId() { + return getUserId(); + } + + public String getSessionPassword() { + String password = ""; + SystemSignonInformation ssi = getSignonInformation(); + if (ssi != null) { + password = ssi.getPassword(); + } + return password; + } + + public boolean isSubscribed() { + return bSubscribed; + } + + public void unsubscribe() throws IOException { + if (bSubscribed) { + new TCFTask<Object>() { + public void run() { + IStreams streams = getService(IStreams.class); + streams.unsubscribe(ITerminals.NAME, streamListener, + new IStreams.DoneUnsubscribe() { + public void doneUnsubscribe(IToken token, + Exception error) { + done(this); + } + }); + } + }.getIO(); + bSubscribed = false; + } + + } + + public void subscribe() throws RemoteFileException { + try { + new TCFTask<Object>() { + public void run() { + if (bSubscribed) { + done(this); + } + else { + bSubscribed = true; + IStreams streams = getService(IStreams.class); + streams.subscribe(ITerminals.NAME, streamListener, + new IStreams.DoneSubscribe() { + public void doneSubscribe(IToken token, + Exception error) { + if (error != null) { + bSubscribed = false; + error(error); + } + else + done(this); + } + + }); + }} + }.getIO(); + + } + catch (Exception e) { + e.printStackTrace();//$NON-NLS-1$ + throw new RemoteFileException( + "Error When Subscribe Terminal streams!", e); //$NON-NLS-1$ + } + + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorServiceManager.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorServiceManager.java new file mode 100644 index 000000000..25b423710 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFConnectorServiceManager.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.AbstractConnectorServiceManager; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; + +public class TCFConnectorServiceManager extends AbstractConnectorServiceManager { + + public static int TCF_PORT = 1534; + + private static final TCFConnectorServiceManager manager = + new TCFConnectorServiceManager(); + + @Override + public IConnectorService createConnectorService(IHost host) { + return new TCFConnectorService(host, TCF_PORT); + } + + @Override + @SuppressWarnings("rawtypes") + public Class getSubSystemCommonInterface(ISubSystem subsystem) { + return ITCFSubSystem.class; + } + + @Override + public boolean sharesSystem(ISubSystem otherSubSystem) { + return otherSubSystem instanceof ITCFSubSystem; + } + + public static TCFConnectorServiceManager getInstance() { + return manager; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFRSETask.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFRSETask.java new file mode 100644 index 000000000..4d5e5e154 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/TCFRSETask.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Martin Oberhuber (Wind River) - [238564] Adopt TM 3.0 APIs + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Uwe Stieber (Wind River) - [273572] SystemMessage contains exception class name instead of error message + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.tm.tcf.util.TCFTask; + +public abstract class TCFRSETask<V> extends TCFTask<V> { + + public V get(IProgressMonitor monitor, String task_name) + throws InterruptedException, ExecutionException { + monitor.beginTask(task_name, 1); + try { + return get(); + } + finally { + monitor.done(); + } + } + + public V getS(IProgressMonitor monitor, String task_name) throws SystemMessageException { + if (monitor != null) monitor.beginTask(task_name, 1); + try { + return get(); + } + catch (Throwable e) { + if (e instanceof SystemMessageException) throw (SystemMessageException)e; + SystemMessage m = new SystemMessage("TCF", "C", "0001", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + SystemMessage.ERROR, + "TCF task aborted".equals(e.getMessage()) && e.getCause() != null ? e.getCause().getMessage() : e.getMessage(), //$NON-NLS-1$ + ""); //$NON-NLS-1$ + throw new SystemMessageException(m); + } + finally { + if (monitor != null) monitor.done(); + } + } + + public V getI(IProgressMonitor monitor, String task_name) throws InvocationTargetException, InterruptedException { + if (monitor != null) monitor.beginTask(task_name, 1); + try { + return get(); + } + catch (Throwable e) { + if (e instanceof InvocationTargetException) throw (InvocationTargetException)e; + if (e instanceof InterruptedException) throw (InterruptedException)e; + throw new InvocationTargetException(e); + } + finally { + if (monitor != null) monitor.done(); + } + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileAdapter.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileAdapter.java new file mode 100644 index 000000000..7e35849b1 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileAdapter.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Martin Oberhuber (Wind River) - [238564] Adopt TM 3.0 APIs + ******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.files; + +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.AbstractRemoteFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext; + +public class TCFFileAdapter implements IHostFileToRemoteFileAdapter { + + public AbstractRemoteFile convertToRemoteFile(FileServiceSubSystem ss, + IRemoteFileContext ctx, IRemoteFile parent, IHostFile node) { + return new TCFRemoteFile(ss, ctx, parent, node); + } + + public AbstractRemoteFile[] convertToRemoteFiles(FileServiceSubSystem ss, + IRemoteFileContext ctx, IRemoteFile parent, IHostFile[] nodes) { + if (nodes == null) return null; + TCFRemoteFile[] res = new TCFRemoteFile[nodes.length]; + for (int i = 0; i < res.length; i++) { + res[i] = new TCFRemoteFile(ss, ctx, parent, nodes[i]); + } + return res; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileResource.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileResource.java new file mode 100644 index 000000000..81a536172 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileResource.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Anna Dushistova (MontaVista) - [247164][tcf] a lot of file/directory properties are not supported + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.files; + +import org.eclipse.rse.core.subsystems.AbstractResource; +import org.eclipse.rse.services.files.HostFilePermissions; +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.rse.services.files.IHostFilePermissions; +import org.eclipse.rse.services.files.IHostFilePermissionsContainer; +import org.eclipse.tm.tcf.services.IFileSystem; + + +public class TCFFileResource extends AbstractResource implements IHostFile, IHostFilePermissionsContainer{ + + private final TCFFileService service; + private String parent; + private String name; + private final IFileSystem.FileAttrs attrs; + private final boolean root; + private IHostFilePermissions permissions; + + public TCFFileResource(TCFFileService service, String parent, String name, + IFileSystem.FileAttrs attrs, boolean root) { + if (name == null) { + int i = parent.lastIndexOf('/'); + if (i > 0) { + name = parent.substring(i + 1); + parent = parent.substring(0, i); + } + else if (i == 0) { + name = parent.substring(i + 1); + parent = "/"; //$NON-NLS-1$ + } + else { + name = parent; + parent = null; + } + } + this.service = service; + this.parent = parent; + this.name = name; + this.attrs = attrs; + this.root = root; + if (attrs != null) this.permissions = new HostFilePermissions( + attrs.permissions, "" + attrs.uid, "" + attrs.gid); //$NON-NLS-1$ //$NON-NLS-2$ + } + + private String toLocalPath(String path) { + if (path.length() > 1 && path.charAt(1) == ':') { + return path.replace('/', '\\'); + } + else { + return path.replace('\\', '/'); + } + } + + public boolean canRead() { + return attrs != null && service.canRead(attrs); + } + + public boolean canWrite() { + return attrs != null && service.canWrite(attrs); + } + + public boolean exists() { + return attrs != null; + } + + public synchronized String getAbsolutePath() { + if (root) return toLocalPath(name); + if (parent.endsWith("/")) return toLocalPath(parent + name); //$NON-NLS-1$ + return toLocalPath(parent + '/' + name); + } + + public long getModifiedDate() { + if (attrs == null) return 0; + if ((attrs.flags & IFileSystem.ATTR_ACMODTIME) == 0) return 0; + return attrs.mtime; + } + + public synchronized String getName() { + return toLocalPath(name); + } + + public synchronized String getParentPath() { + if (root) return null; + return toLocalPath(parent); + } + + public long getSize() { + if (attrs == null) return 0; + if ((attrs.flags & IFileSystem.ATTR_SIZE) == 0) return 0; + return attrs.size; + } + + public boolean isArchive() { + return false; + } + + public boolean isDirectory() { + if (attrs == null) return false; + return attrs.isDirectory(); + } + + public boolean isFile() { + if (attrs == null) return false; + return attrs.isFile(); + } + + public synchronized boolean isHidden() { + return name.startsWith("."); //$NON-NLS-1$ + } + + public synchronized boolean isRoot() { + return root; + } + + public synchronized void renameTo(String path) { + path = path.replace('\\', '/'); + if (path.equals("/")) { //$NON-NLS-1$ + parent = name = "/"; //$NON-NLS-1$ + return; + } + assert !path.endsWith("/"); //$NON-NLS-1$ + int i = path.lastIndexOf('/'); + parent = path.substring(0, i); + name = path.substring(i + 1); + } + + public IHostFilePermissions getPermissions() { + return permissions; + } + + public void setPermissions(IHostFilePermissions permissions) { + this.permissions = permissions; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileService.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileService.java new file mode 100644 index 000000000..afaab224b --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileService.java @@ -0,0 +1,805 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Martin Oberhuber (Wind River) - [238564] Adopt TM 3.0 APIs + * Uwe Stieber (Wind River) - [271224] NPE in TCFFileService#download + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Uwe Stieber (Wind River) - [274277] The TCF file service subsystem implementation is not updating the progress monitor + * Intel Corporation - [326489] Make recursive copy/delete available (delete/copy a folder contains files) + * Intel Corporation - [329654] Make all sub services operate against TCF connector service + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.files; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.services.clientserver.FileTypeMatcher; +import org.eclipse.rse.services.clientserver.IMatcher; +import org.eclipse.rse.services.clientserver.NamePatternMatcher; +import org.eclipse.rse.services.clientserver.messages.SimpleSystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.clientserver.messages.SystemOperationFailedException; +import org.eclipse.rse.services.files.AbstractFileService; +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.tm.internal.tcf.rse.Activator; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.Messages; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; +import org.eclipse.tm.internal.tcf.rse.TCFRSETask; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.IFileSystem; +import org.eclipse.tm.tcf.services.IFileSystem.DirEntry; +import org.eclipse.tm.tcf.services.IFileSystem.FileAttrs; +import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException; +import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle; +import org.eclipse.tm.tcf.util.TCFFileInputStream; +import org.eclipse.tm.tcf.util.TCFFileOutputStream; + + +public class TCFFileService extends AbstractFileService { + + private final TCFConnectorService connector; + + private UserInfo user_info; + + private static final class UserInfo { + final int r_uid; + final int e_uid; + final int r_gid; + final int e_gid; + final String home; + + final Throwable error; + + UserInfo(int r_uid, int e_uid, int r_gid, int e_gid, String home) { + this.r_uid = r_uid; + this.e_uid = e_uid; + this.r_gid = r_gid; + this.e_gid = e_gid; + this.home = home; + error = null; + } + + UserInfo(Throwable error) { + this.error = error; + r_uid = -1; + e_uid = -1; + r_gid = -1; + e_gid = -1; + home = null; + } + } + + public TCFFileService(IHost host) { + connector = (TCFConnectorService)TCFConnectorServiceManager + .getInstance().getConnectorService(host, ITCFService.class); + } + + @Override + public String getDescription() { + return "The TCF File Service uses the Target Communication Framework to provide service" + //$NON-NLS-1$ + "for the Files subsystem. It requires a TCF agent to be running on the remote machine."; //$NON-NLS-1$ + } + + public SystemMessage getMessage(Throwable x) { + return new SimpleSystemMessage(Activator.PLUGIN_ID, + SystemMessage.ERROR, x.getMessage(), x); + } + + @Override + public String getName() { + return "TCF File Service"; //$NON-NLS-1$ + } + + private String toRemotePath(String parent, String name) throws SystemMessageException { + assert !Protocol.isDispatchThread(); + String s = null; + if (parent != null) parent = parent.replace('\\', '/'); + if (name != null) name = name.replace('\\', '/'); + if (parent == null || parent.length() == 0) s = name; + else if (name == null || name.equals(".")) s = parent; //$NON-NLS-1$ + else if (name.equals("/")) s = parent; //$NON-NLS-1$ + else if (parent.endsWith("/")) s = parent + name; //$NON-NLS-1$ + else s = parent + '/' + name; + if (s.startsWith("./") || s.equals(".")) { //$NON-NLS-1$ //$NON-NLS-2$ + UserInfo ui = getUserInfo(); + if (ui.error != null) throw new SystemMessageException(getMessage(ui.error)); + s = ui.home.replace('\\', '/') + s.substring(1); + } + while (s.endsWith("/.")) s = s.substring(0, s.length() - 2); //$NON-NLS-1$ + return s; + } + + /* Delete from UI action will call deleteBatch interface, yet + * for copy from UI action, it will call copy! It's totally + * inconsistency! For solving the problem, we have to modify + * the copy itself and made it recursive. We can't modify it + * in the same way as delete does! + * + */ + + public void internalCopy(String srcParent, + String srcName, String tgtParent, String tgtName, IProgressMonitor monitor) + throws SystemMessageException, InterruptedException { + //Note the dest directory or file exist surely since UI operations have + //done something, rename it to copy of XXX + if (monitor != null) + { + if (monitor.isCanceled()) + { + throw new InterruptedException(Messages.TCFFileService_UserCancellation); + } + } + + try + { + //firstly create the target directory! + this.createFolder(tgtParent, tgtName, monitor); + //then copy the next level directory! + final String new_srcpath = toRemotePath(srcParent, srcName); + final String new_tgtpath = toRemotePath(tgtParent, tgtName); + IHostFile[] arrFiles = internalFetch(new_srcpath, null, + FILE_TYPE_FILES_AND_FOLDERS, monitor); + if (arrFiles == null || arrFiles.length <=0 ) + return; + else + { + for (int i = 0; i < arrFiles.length; i++) + { + String srcFile = toRemotePath(new_srcpath, arrFiles[i].getName()); + String tgtFile = toRemotePath(new_tgtpath, arrFiles[i].getName()); + if (arrFiles[i].isFile()) + { + copy(srcFile, tgtFile, monitor); + } + else + { + //do recursive directory copy! + internalCopy(new_srcpath, arrFiles[i].getName(), new_tgtpath, + arrFiles[i].getName(), monitor); + } + } + } + } + catch (SystemMessageException e) + { + e.printStackTrace(); + throw new SystemMessageException(e.getSystemMessage()); + } + catch (InterruptedException e) + { + throw new InterruptedException(Messages.TCFFileService_UserCancellation1); + } + } + + public void copy(String srcParent, + String srcName, String tgtParent, String tgtName, IProgressMonitor monitor) + throws SystemMessageException { + + if (monitor != null) + monitor.beginTask(Messages.TCFFileService_CopyingFiles, 1); + + try { + + IHostFile curFile = getFile(srcParent, srcName, monitor); + final String srcFile = toRemotePath(srcParent, srcName); + final String tgtFile = toRemotePath(tgtParent, tgtName); + + if (curFile.isFile()) + copy(srcFile, tgtFile, monitor); + else if (curFile.isDirectory()) + { + internalCopy(srcParent, srcName, tgtParent, tgtName, monitor); + } + else + { + FileNotFoundException e = + new FileNotFoundException(Messages.TCFFileService_FileNotFoundMessage); + throw new SystemMessageException(getMessage(e)); + } + } + catch (Exception e) { + // TODO Auto-generated catch block + if (e instanceof SystemMessageException) + throw (SystemMessageException)e; + throw new SystemOperationFailedException(Activator.PLUGIN_ID, e); + + } + finally { + if (monitor != null) + monitor.done(); + } + } + + public void copy(final String srcFile, final String tgtFile, IProgressMonitor monitor) + throws SystemMessageException { + new TCFRSETask<Boolean>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.copy(srcFile, tgtFile, false, false, new IFileSystem.DoneCopy() { + public void doneCopy(IToken token, FileSystemException error) { + if (error != null) error(error); + else done(Boolean.TRUE); + } + }); + } + }.getS(monitor, "Copy: " + srcFile); //$NON-NLS-1$ + } + + public void copyBatch(String[] srcParents, + String[] srcNames, String tgtParent, IProgressMonitor monitor) throws SystemMessageException { + for (int i = 0; i < srcParents.length; i++) { + copy(srcParents[i], srcNames[i], tgtParent, srcNames[i], monitor); + } + } + + public IHostFile createFile(String parent, + String name, IProgressMonitor monitor) throws SystemMessageException { + try { + getOutputStream(parent, name, true, monitor).close(); + return getFile(parent, name, monitor); + } + catch (IOException e) { + throw new SystemMessageException(getMessage(e)); + } + } + + public IHostFile createFolder(final String parent, final String name, IProgressMonitor monitor) throws SystemMessageException { + final String path = toRemotePath(parent, name); + return new TCFRSETask<IHostFile>() { + public void run() { + final IFileSystem fs = connector.getFileSystemService(); + fs.mkdir(path, null, new IFileSystem.DoneMkDir() { + public void doneMkDir(IToken token, FileSystemException error) { + if (error != null) { + error(error); + return; + } + fs.stat(path, new IFileSystem.DoneStat() { + public void doneStat(IToken token, + FileSystemException error, FileAttrs attrs) { + if (error != null) error(error); + else done(new TCFFileResource(TCFFileService.this, + path, null, attrs, false)); + } + }); + } + }); + } + }.getS(monitor, "Create folder"); //$NON-NLS-1$ + } + + public void delete(String parent, + String name, IProgressMonitor monitor) throws SystemMessageException { + final String path = toRemotePath(parent, name); + new TCFRSETask<Boolean>() { + public void run() { + final IFileSystem fs = connector.getFileSystemService(); + fs.stat(path, new IFileSystem.DoneStat() { + public void doneStat(IToken token, + FileSystemException error, FileAttrs attrs) { + if (error != null) { + error(error); + return; + } + IFileSystem.DoneRemove done = new IFileSystem.DoneRemove() { + public void doneRemove(IToken token, FileSystemException error) { + if (error != null) { + error(error); + return; + } + done(Boolean.TRUE); + } + }; + if (attrs.isDirectory()) { + fs.rmdir(path, done); + } + else { + fs.remove(path, done); + } + } + }); + } + }.getS(monitor, "Delete"); //$NON-NLS-1$ + } + + private void internalDelete(String parent, String name, + IProgressMonitor monitor) + throws SystemMessageException, InterruptedException + { + if (monitor != null) + { + if (monitor.isCanceled()) + { + throw new InterruptedException(Messages.TCFFileService_UserDeleteCancellation); + } + } + + try + { + final String new_path = toRemotePath(parent, name); + IHostFile[] arrFiles = internalFetch(new_path, null, + FILE_TYPE_FILES_AND_FOLDERS, monitor); + if (arrFiles == null || arrFiles.length <= 0) + { + //This is an empty directory, directly delete! + delete(parent, name, monitor); + } + else + { + for (int i = 0; i < arrFiles.length; i++) + { + + if (arrFiles[i].isFile()) + { + delete(new_path, arrFiles[i].getName(), monitor); + } + else + internalDelete(new_path, arrFiles[i].getName(), monitor); + } + //now the folder becomes empty, let us delete it! + delete(parent, name, monitor); + } + } + catch (SystemMessageException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + throw new SystemMessageException(e.getSystemMessage()); + } + catch (InterruptedException e) { + throw new InterruptedException(Messages.TCFFileService_UserDeleteCancellation1); + } + } + + @Override + public void deleteBatch(String[] remoteParents, String[] fileNames, + IProgressMonitor monitor) + throws SystemMessageException { + if (monitor != null) + monitor.beginTask(Messages.TCFFileService_DeletingFiles, remoteParents.length); + try + { + for (int i = 0; i < remoteParents.length; i++) { + IHostFile curFile = getFile(remoteParents[i], fileNames[i], monitor); + if (curFile.isFile()) + delete(remoteParents[i], fileNames[i], monitor); + else if (curFile.isDirectory()) + internalDelete(remoteParents[i], fileNames[i], monitor); + } + } + catch (Exception x) { + if (x instanceof SystemMessageException) throw (SystemMessageException)x; + throw new SystemOperationFailedException(Activator.PLUGIN_ID, x); + } + finally { + if (monitor != null) + monitor.done(); + } + } + + public void download(final String parent, + final String name, final File file, final boolean is_binary, + final String host_encoding, IProgressMonitor monitor) throws SystemMessageException { + IHostFile hostFile = getFile(parent, name, new NullProgressMonitor()); + monitor.beginTask("Downloading " + toRemotePath(parent, name) + " ...", Long.valueOf(hostFile.getSize() / 1024).intValue()); //$NON-NLS-1$ //$NON-NLS-2$ + try { + file.getParentFile().mkdirs(); + InputStream inp = getInputStream(parent, name, is_binary, new NullProgressMonitor()); + OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); + copyStream(inp, out, is_binary, "UTF8", host_encoding, monitor); //$NON-NLS-1$ + } + catch (Exception x) { + if (x instanceof SystemMessageException) throw (SystemMessageException)x; + throw new SystemOperationFailedException(Activator.PLUGIN_ID, x); + } + finally { + monitor.done(); + } + } + + @Override + public String getEncoding(IProgressMonitor monitor) throws SystemMessageException { + return "UTF8"; //$NON-NLS-1$ + } + + public IHostFile getFile(final String parent, + final String name, IProgressMonitor monitor) throws SystemMessageException { + final String path = toRemotePath(parent, name); + return new TCFRSETask<IHostFile>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.stat(path, new IFileSystem.DoneStat() { + public void doneStat(IToken token, + FileSystemException error, FileAttrs attrs) { + if (error != null) { + if (error.getStatus() == IFileSystem.STATUS_NO_SUCH_FILE) { + done(new TCFFileResource(TCFFileService.this, path, null, null, false)); + return; + } + error(error); + return; + } + done(new TCFFileResource(TCFFileService.this, path, null, attrs, false)); + } + }); + } + }.getS(monitor, "Stat"); //$NON-NLS-1$ + } + + @Override + protected IHostFile[] internalFetch(final String parent, final String filter, final int fileType, final IProgressMonitor monitor) + throws SystemMessageException { + final String path = toRemotePath(parent, null); + final boolean wantFiles = (fileType==FILE_TYPE_FILES_AND_FOLDERS || (fileType&FILE_TYPE_FILES)!=0); + final boolean wantFolders = (fileType==FILE_TYPE_FILES_AND_FOLDERS || (fileType%FILE_TYPE_FOLDERS)!=0); + return new TCFRSETask<IHostFile[]>() { + private IMatcher matcher = null; + public void run() { + if (filter == null) { + matcher = null; + } + else if (filter.endsWith(",")) { //$NON-NLS-1$ + String[] types = filter.split(","); //$NON-NLS-1$ + matcher = new FileTypeMatcher(types, true); + } + else { + matcher = new NamePatternMatcher(filter, true, true); + } + final List<TCFFileResource> results = new ArrayList<TCFFileResource>(); + final IFileSystem fs = connector.getFileSystemService(); + fs.opendir(path, new IFileSystem.DoneOpen() { + public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) { + if (error != null) { + error(error); + return; + } + fs.readdir(handle, new IFileSystem.DoneReadDir() { + public void doneReadDir(IToken token, + FileSystemException error, DirEntry[] entries, boolean eof) { + if (error != null) { + error(error); + return; + } + for (DirEntry e : entries) { + if (e.attrs == null) { + // Attrs are not available if, for example, + // the entry is a broken symbolic link + } + else if (e.attrs.isDirectory()) { + // dont filter folder names if getting both folders and files + if (wantFolders && (matcher==null || fileType==FILE_TYPE_FILES_AND_FOLDERS || matcher.matches(e.filename))) { + results.add(new TCFFileResource(TCFFileService.this, + path, e.filename, e.attrs, false)); + } + } + else if (e.attrs.isFile()) { + if (wantFiles && (matcher == null || matcher.matches(e.filename))) { + results.add(new TCFFileResource(TCFFileService.this, + path, e.filename, e.attrs, false)); + } + } + } + if (eof) { + fs.close(handle, new IFileSystem.DoneClose() { + public void doneClose(IToken token, FileSystemException error) { + if (error != null) { + error(error); + return; + } + done(results.toArray(new TCFFileResource[results.size()])); + } + }); + } + else { + fs.readdir(handle, this); + } + } + }); + } + }); + } + }.getS(monitor, "Get files and folders"); //$NON-NLS-1$ + } + + @Override + public InputStream getInputStream(final String parent, final String name, boolean isBinary, IProgressMonitor monitor) + throws SystemMessageException { + final String path = toRemotePath(parent, name); + final IFileHandle handle = new TCFRSETask<IFileHandle>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.open(path, IFileSystem.TCF_O_READ, null, new IFileSystem.DoneOpen() { + public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) { + if (error != null) error(error); + else done(handle); + } + }); + } + }.getS(monitor, "Get input stream"); //$NON-NLS-1$ + return new TCFFileInputStream(handle); + } + + @Override + public OutputStream getOutputStream(final String parent, final String name, boolean isBinary, IProgressMonitor monitor) + throws SystemMessageException { + final String path = toRemotePath(parent, name); + final IFileHandle handle = new TCFRSETask<IFileHandle>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + int flags = IFileSystem.TCF_O_WRITE | IFileSystem.TCF_O_CREAT | IFileSystem.TCF_O_TRUNC; + fs.open(path, flags, null, new IFileSystem.DoneOpen() { + public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) { + if (error != null) error(error); + else done(handle); + } + }); + } + }.getS(monitor, "Get output stream"); //$NON-NLS-1$ + return new TCFFileOutputStream(handle); + } + + public IHostFile[] getRoots(IProgressMonitor monitor) throws SystemMessageException { + return new TCFRSETask<IHostFile[]>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.roots(new IFileSystem.DoneRoots() { + public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) { + if (error != null) { + error(error); + return; + } + List<TCFFileResource> l = new ArrayList<TCFFileResource>(); + for (DirEntry e : entries) { + if (e.attrs == null) continue; + l.add(new TCFFileResource(TCFFileService.this, null, e.filename, e.attrs, true)); + } + done(l.toArray(new IHostFile[l.size()])); + } + }); + } + }.getS(monitor, "Get roots"); //$NON-NLS-1$ + } + + public IHostFile getUserHome() { + UserInfo ui = getUserInfo(); + try { + return getFile(ui.home, ".", new NullProgressMonitor()); //$NON-NLS-1$ + } + catch (SystemMessageException e) { + throw new Error(e); + } + } + + public boolean isCaseSensitive() { + return true; + } + + public void move(final String srcParent, + final String srcName, final String tgtParent, final String tgtName, IProgressMonitor monitor) + throws SystemMessageException { + final String src_path = toRemotePath(srcParent, srcName); + final String tgt_path = toRemotePath(tgtParent, tgtName); + new TCFRSETask<Boolean>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.rename(src_path, tgt_path, new IFileSystem.DoneRename() { + public void doneRename(IToken token, FileSystemException error) { + if (error != null) error(error); + else done(Boolean.TRUE); + } + }); + } + }.getS(monitor, "Move"); //$NON-NLS-1$ + } + + public void rename(String remoteParent, + String oldName, String newName, IProgressMonitor monitor) throws SystemMessageException { + move(remoteParent, oldName, remoteParent, newName, monitor); + } + + public void rename(String remoteParent, + String oldName, String newName, IHostFile oldFile, IProgressMonitor monitor) + throws SystemMessageException { + move(remoteParent, oldName, remoteParent, newName, monitor); + oldFile.renameTo(toRemotePath(remoteParent, newName)); + } + + public void setLastModified(final String parent, + final String name, final long timestamp, IProgressMonitor monitor) throws SystemMessageException { + final String path = toRemotePath(parent, name); + new TCFRSETask<Boolean>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + FileAttrs attrs = new FileAttrs(IFileSystem.ATTR_ACMODTIME, + 0, 0, 0, 0, timestamp, timestamp, null); + fs.setstat(path, attrs, new IFileSystem.DoneSetStat() { + public void doneSetStat(IToken token, FileSystemException error) { + if (error != null) error(error); + else done(Boolean.TRUE); + } + }); + } + }.getS(monitor, "Set modification time"); //$NON-NLS-1$ + } + + public void setReadOnly(final String parent, + final String name, final boolean readOnly, IProgressMonitor monitor) throws SystemMessageException { + final String path = toRemotePath(parent, name); + new TCFRSETask<Boolean>() { + public void run() { + final IFileSystem fs = connector.getFileSystemService(); + fs.stat(path, new IFileSystem.DoneStat() { + public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) { + if (error != null) { + error(error); + return; + } + int p = attrs.permissions; + if (readOnly) { + p &= ~IFileSystem.S_IWUSR; + p &= ~IFileSystem.S_IWGRP; + p &= ~IFileSystem.S_IWOTH; + } + else { + p |= IFileSystem.S_IWUSR; + p |= IFileSystem.S_IWGRP; + p |= IFileSystem.S_IWOTH; + } + FileAttrs new_attrs = new FileAttrs(IFileSystem.ATTR_PERMISSIONS, + 0, 0, 0, p, 0, 0, null); + fs.setstat(path, new_attrs, new IFileSystem.DoneSetStat() { + public void doneSetStat(IToken token, FileSystemException error) { + if (error != null) error(error); + else done(Boolean.TRUE); + } + }); + } + }); + } + }.getS(monitor, "Set permissions"); //$NON-NLS-1$ + } + + public void upload(InputStream inp, + String parent, String name, boolean isBinary, + String hostEncoding, IProgressMonitor monitor) throws SystemMessageException { + monitor.beginTask("Upload", 1); //$NON-NLS-1$ + try { + OutputStream out = getOutputStream(parent, name, isBinary, new NullProgressMonitor()); + // As we cannot determine the local file size, redirect the worked ticks to a NullProgressMonitor. + copyStream(inp, out, isBinary, hostEncoding, "UTF8", new NullProgressMonitor()); //$NON-NLS-1$ + } + catch (Throwable x) { + if (x instanceof SystemMessageException) throw (SystemMessageException)x; + throw new SystemMessageException(getMessage(x)); + } + finally { + monitor.done(); + } + } + + public void upload(File localFile, + String parent, String name, boolean isBinary, + String srcEncoding, String hostEncoding, IProgressMonitor monitor) + throws SystemMessageException { + monitor.beginTask("Uploading " + localFile.toString() + " ...", Long.valueOf(localFile.length() / 1024).intValue()); //$NON-NLS-1$ //$NON-NLS-2$ + try { + OutputStream out = getOutputStream(parent, name, isBinary, new NullProgressMonitor()); + InputStream inp = new BufferedInputStream(new FileInputStream(localFile)); + copyStream(inp, out, isBinary, hostEncoding, "UTF8", monitor); //$NON-NLS-1$ + } + catch (Throwable x) { + if (x instanceof SystemMessageException) throw (SystemMessageException)x; + throw new SystemMessageException(getMessage(x)); + } + finally { + monitor.done(); + } + } + + private void copyStream(InputStream inp, OutputStream out, + boolean is_binary, String inp_encoding, String out_encoding, IProgressMonitor monitor) throws IOException { + try { + if (!is_binary) { + if (inp_encoding == null || inp_encoding.equals("UTF-8")) inp_encoding = "UTF8"; //$NON-NLS-1$ //$NON-NLS-2$ + if (out_encoding == null || out_encoding.equals("UTF-8")) out_encoding = "UTF8"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if (is_binary || inp_encoding.equals(out_encoding)) { + byte[] buf = new byte[0x1000]; + for (;;) { + int buf_len = inp.read(buf); + if (buf_len < 0) break; + out.write(buf, 0, buf_len); + if (monitor != null) monitor.worked(buf_len / 1024); + } + } + else { + Reader reader = new InputStreamReader(inp, inp_encoding); + Writer writer = new OutputStreamWriter(out, out_encoding); + char[] buf = new char[0x1000]; + for (;;) { + int buf_len = reader.read(buf); + if (buf_len < 0) break; + writer.write(buf, 0, buf_len); + if (monitor != null) monitor.worked(buf_len / 1024); + } + writer.flush(); + } + } + finally { + out.close(); + inp.close(); + } + } + + private synchronized UserInfo getUserInfo() { + if (user_info == null || user_info.error != null) { + user_info = new TCFRSETask<UserInfo>() { + public void run() { + IFileSystem fs = connector.getFileSystemService(); + fs.user(new IFileSystem.DoneUser() { + public void doneUser(IToken token, FileSystemException error, int real_uid, + int effective_uid, int real_gid, int effective_gid, String home) { + if (error != null) done(new UserInfo(error)); + else done(new UserInfo(real_uid, effective_uid, real_gid, effective_gid, home)); + } + }); + } + }.getE(); + } + return user_info; + } + + public boolean canRead(FileAttrs attrs) { + if ((attrs.flags & IFileSystem.ATTR_PERMISSIONS) == 0) return false; + if ((attrs.flags & IFileSystem.ATTR_UIDGID) == 0) return false; + UserInfo ui = getUserInfo(); + if (ui.error != null) return false; + if (ui.e_uid == attrs.uid) { + return (attrs.permissions & IFileSystem.S_IRUSR) != 0; + } + if (ui.e_gid == attrs.gid) { + return (attrs.permissions & IFileSystem.S_IRGRP) != 0; + } + return (attrs.permissions & IFileSystem.S_IROTH) != 0; + } + + public boolean canWrite(FileAttrs attrs) { + if ((attrs.flags & IFileSystem.ATTR_PERMISSIONS) == 0) return false; + if ((attrs.flags & IFileSystem.ATTR_UIDGID) == 0) return false; + UserInfo ui = getUserInfo(); + if (ui.error != null) return false; + if (ui.e_uid == attrs.uid) { + return (attrs.permissions & IFileSystem.S_IWUSR) != 0; + } + if (ui.e_gid == attrs.gid) { + return (attrs.permissions & IFileSystem.S_IWGRP) != 0; + } + return (attrs.permissions & IFileSystem.S_IWOTH) != 0; + } + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileSubSystemConfiguration.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileSubSystemConfiguration.java new file mode 100644 index 000000000..79e1dd48d --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFFileSubSystemConfiguration.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Intel Corp. - Add Unix File System style detection, set TRUE by default + * Intel Corporation - [329654] Make all sub services operate against TCF connector service + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.files; + +import java.util.Vector; + +import org.eclipse.rse.core.filters.ISystemFilter; +import org.eclipse.rse.core.filters.ISystemFilterPool; +import org.eclipse.rse.core.filters.ISystemFilterPoolManager; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.services.clientserver.SystemSearchString; +import org.eclipse.rse.services.files.IFileService; +import org.eclipse.rse.services.search.IHostSearchResultConfiguration; +import org.eclipse.rse.services.search.IHostSearchResultSet; +import org.eclipse.rse.services.search.ISearchService; +import org.eclipse.rse.subsystems.files.core.ILanguageUtilityFactory; +import org.eclipse.rse.subsystems.files.core.model.RemoteFileFilterString; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystemConfiguration; +import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; +import org.eclipse.rse.ui.SystemBasePlugin; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.Messages; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; + +public class TCFFileSubSystemConfiguration extends FileServiceSubSystemConfiguration { + + private final TCFFileAdapter file_adapter = new TCFFileAdapter(); + + public TCFFileSubSystemConfiguration() + { + super(); + if (Messages.IS_UNIX_STYLE.equalsIgnoreCase("true")) + setIsUnixStyle(true); + else + setIsUnixStyle(false); + } + + @Override + public ISubSystem createSubSystemInternal(IHost host) { + TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host); + return new FileServiceSubSystem(host, connectorService, + getFileService(host), getHostFileAdapter(), createSearchService(host)); + } + + public IFileService createFileService(IHost host) { + return new TCFFileService(host); + } + + public IHostSearchResultConfiguration createSearchConfiguration(IHost host, + IHostSearchResultSet resultSet, Object searchTarget, + SystemSearchString searchString) { + // TODO Auto-generated method stub + return null; + } + + public ISearchService createSearchService(IHost host) { + // TODO Auto-generated method stub + return null; + } + + public IHostFileToRemoteFileAdapter getHostFileAdapter() { + return file_adapter; + } + + public ILanguageUtilityFactory getLanguageUtilityFactory(IRemoteFileSubSystem ss) { + // TODO Auto-generated method stub + return null; + } + + public boolean supportsArchiveManagement() { + return false; + } + + @Override + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance() + .getConnectorService(host, getServiceImplType()); + } + + @Override + public Class<ITCFService> getServiceImplType() { + return ITCFService.class; + } + + @Override + public void setConnectorService(IHost host, IConnectorService connectorService) { + TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService); + } + + @Override + protected ISystemFilterPool createDefaultFilterPool(ISystemFilterPoolManager mgr) { + ISystemFilterPool pool = null; + try { + pool = mgr.createSystemFilterPool(getDefaultFilterPoolName(mgr.getName(), getId()), true); + + Vector<String> filterStrings = new Vector<String>(); + RemoteFileFilterString myHomeFilterString = new RemoteFileFilterString(this); + myHomeFilterString.setPath("."); //$NON-NLS-1$ + myHomeFilterString.setFile("*"); //$NON-NLS-1$ + filterStrings.add(myHomeFilterString.toString()); + ISystemFilter filter = mgr.createSystemFilter(pool, "Home", filterStrings); //$NON-NLS-1$ + filter.setNonChangable(true); + filter.setSingleFilterStringOnly(true); + + filterStrings = new Vector<String>(); + RemoteFileFilterString rootFilesFilterString = new RemoteFileFilterString(this); + rootFilesFilterString.setPath(""); //$NON-NLS-1$ + rootFilesFilterString.setFile("*"); //$NON-NLS-1$ + filterStrings.add(rootFilesFilterString.toString()); + filter = mgr.createSystemFilter(pool, "Root", filterStrings); //$NON-NLS-1$ + filter.setNonChangable(true); + filter.setSingleFilterStringOnly(true); + } + catch (Exception exc) { + SystemBasePlugin.logError("Error creating default filter pool", exc); //$NON-NLS-1$ + } + return pool; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFRemoteFile.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFRemoteFile.java new file mode 100644 index 000000000..1be7f12f1 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/files/TCFRemoteFile.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Anna Dushistova (MontaVista) - [247164][tcf] a lot of file/directory properties are not supported + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.files; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.files.IHostFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.AbstractRemoteFile; +import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; +import org.eclipse.rse.ui.SystemBasePlugin; + +public class TCFRemoteFile extends AbstractRemoteFile { + + public TCFRemoteFile(FileServiceSubSystem ss, IRemoteFileContext ctx, IRemoteFile parent, IHostFile file) { + super(ss, ctx, parent, file); + } + + @Override + public IRemoteFile getParentRemoteFile() { + if (this._parentFile == null) { + if (isRoot()) return null; + IRemoteFile parentFile = null; + IRemoteFileSubSystem ss = _context.getParentRemoteFileSubSystem(); + if (ss != null) { + IProgressMonitor monitor = new NullProgressMonitor(); + try { + parentFile = ss.getRemoteFileObject(getParentPath(), monitor); + } + catch (SystemMessageException e) { + SystemBasePlugin.logError("TCFRemoteFile.getParentRemoteFile()", e); //$NON-NLS-1$ + } + } + this._parentFile = parentFile; + } + return this._parentFile; + } + + public String getCanonicalPath() { + return getAbsolutePath(); + } + + public String getClassification() { + String result; + if (isFile()) { + result = "file"; //$NON-NLS-1$ + } else if (isDirectory()) { + result = "directory"; //$NON-NLS-1$ + } else { + result = "unknown"; //default-fallback //$NON-NLS-1$ + } + return result; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessAdapter.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessAdapter.java new file mode 100644 index 000000000..7f43ddfc6 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessAdapter.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.IHostProcessToRemoteProcessAdapter; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessContext; + +public class TCFProcessAdapter implements IHostProcessToRemoteProcessAdapter { + + public IRemoteProcess convertToRemoteProcess(IRemoteProcessContext context, + IRemoteProcess parent, IHostProcess node) { + IHostProcess[] nodes = new IHostProcess[]{ node }; + IRemoteProcess[] processes = convertToRemoteProcesses(context, parent, nodes); + if (processes != null && processes.length > 0) return processes[0]; + return null; + } + + public IRemoteProcess[] convertToRemoteProcesses( + IRemoteProcessContext context, IRemoteProcess parent, + IHostProcess[] nodes) { + + if (nodes == null)return null; + List<IRemoteProcess> list = new ArrayList<IRemoteProcess>(nodes.length); + for (int idx = 0; idx < nodes.length; idx++) { + TCFProcessResource node = (TCFProcessResource)nodes[idx]; + if (node != null) list.add(new TCFRemoteProcess(context, node)); + } + return list.toArray(new IRemoteProcess[list.size()]); + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessResource.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessResource.java new file mode 100644 index 000000000..4fad1b6cd --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessResource.java @@ -0,0 +1,378 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Anna Dushistova (MontaVista) - [246996] [tcf] NullPointerException when trying to copy the process + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.rse.core.subsystems.AbstractResource; +import org.eclipse.rse.services.clientserver.IServiceConstants; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.ISysMonitor; +import org.eclipse.tm.tcf.services.ISysMonitor.SysMonitorContext; + +public class TCFProcessResource extends AbstractResource implements IHostProcess { + + public static final String PROP_PC_UTIME = "PCUTime"; //$NON-NLS-1$ + public static final String PROP_PC_STIME = "PCSTime"; //$NON-NLS-1$ + + private final TCFProcessService rse_service; + private final ISysMonitor tcf_service; + private final TCFProcessResource prev; + private final String id; + + private Throwable error; + private ISysMonitor.SysMonitorContext context; + + private final List<Runnable> children_wait_list = new ArrayList<Runnable>(); + private final HashMap<String,TCFProcessResource> children = new HashMap<String,TCFProcessResource>(); + private boolean children_loading; + private boolean children_loaded; + private Throwable children_error; + private boolean running_wait_list; + + private long timestamp; + + private final String[] propertyKeys = new String[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT]; + { + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_EXENAME] = ISysMonitor.PROP_FILE; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_GID] = ISysMonitor.PROP_GROUPNAME; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_PID] = ISysMonitor.PROP_PID; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_PPID] = ISysMonitor.PROP_PPID; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_STATUS] = ISysMonitor.PROP_STATE; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_TGID] = ISysMonitor.PROP_TGID; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_TRACERPID] = ISysMonitor.PROP_TRACERPID; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_UID] = ISysMonitor.PROP_UID; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_USERNAME] = ISysMonitor.PROP_USERNAME; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_VMSIZE] = ISysMonitor.PROP_VSIZE; + propertyKeys[ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_INDEX_VMRSS] = ISysMonitor.PROP_RSS; + } + + private Map<String, Object> properties = new HashMap<String, Object>(); + + TCFProcessResource(TCFProcessService rse_service, ISysMonitor service, + TCFProcessResource prev, String id) { + this.rse_service = rse_service; + this.tcf_service = service; + this.prev = prev; + this.id = id; + } + + public String getID() { + return id; + } + + public String getParentID() { + return (String)properties.get(ISysMonitor.PROP_PARENTID); + } + + public TCFProcessService getService() { + return rse_service; + } + + public void invalidate() { + assert Protocol.isDispatchThread(); + error = null; + context = null; + } + + public boolean validate(final Runnable done) { + assert Protocol.isDispatchThread(); + if (error != null) return true; + if (context != null) return true; + tcf_service.getContext(id, new ISysMonitor.DoneGetContext() { + + public void doneGetContext(IToken token, Exception error, SysMonitorContext context) { + TCFProcessResource.this.error = error; + TCFProcessResource.this.context = context; + timestamp = System.currentTimeMillis(); + if (error != null) { + properties = new HashMap<String,Object>(); + } + else { + properties = new HashMap<String,Object>(context.getProperties()); + if (prev != null && timestamp > prev.timestamp) { + setPCProperty(PROP_PC_UTIME, ISysMonitor.PROP_UTIME); + setPCProperty(PROP_PC_STIME, ISysMonitor.PROP_STIME); + } + // Conversions are necessary for sorting to work + toLong(ISysMonitor.PROP_PID); + toLong(ISysMonitor.PROP_PPID); + toLong(ISysMonitor.PROP_UTIME); + toLong(ISysMonitor.PROP_STIME); + toLong(ISysMonitor.PROP_CUTIME); + toLong(ISysMonitor.PROP_CSTIME); + toLong(ISysMonitor.PROP_STARTTIME); + toLong(ISysMonitor.PROP_ITREALVALUE); + toBigInteger(ISysMonitor.PROP_CODESTART); + toBigInteger(ISysMonitor.PROP_CODEEND); + toBigInteger(ISysMonitor.PROP_STACKSTART); + toBigInteger(ISysMonitor.PROP_WCHAN); + } + Protocol.invokeLater(done); + } + + }); + return false; + } + + private void toLong(String name) { + Number n = (Number)properties.get(name); + if (n == null || n instanceof Long) return; + properties.put(name, Long.valueOf(n.longValue())); + } + + private void toBigInteger(String name) { + Number n = (Number)properties.get(name); + if (n == null || n instanceof BigInteger) return; + properties.put(name, new BigInteger(n.toString())); + } + + private void setPCProperty(String property, String name) { + Object x = prev.properties.get(name); + Object y = properties.get(name); + if (x instanceof Number && y instanceof Number) { + BigInteger nx = x instanceof BigInteger ? (BigInteger) x + : new BigInteger(x.toString()); + BigInteger ny = y instanceof BigInteger ? (BigInteger) y + : new BigInteger(y.toString()); + double d = ny.subtract(nx).doubleValue() + / (timestamp - prev.timestamp); + properties.put(property, d); + } + } + + public long getTimestamp() { + return timestamp; + } + + public Throwable getError() { + assert Protocol.isDispatchThread(); + return error; + } + + public ISysMonitor.SysMonitorContext getContext() { + assert Protocol.isDispatchThread(); + return context; + } + + // IHostProcess methods + + public String getAllProperties() { + String result = ""; //$NON-NLS-1$ + for (int i = 0; i < ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT; i++) { + result = result + properties.get(propertyKeys[i]); + if (i != ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT - 1) + result = result + IServiceConstants.TOKEN_SEPARATOR; + } + return result; + } + + public long getGid() { + Number n = (Number)properties.get(ISysMonitor.PROP_UGID); + if (n == null) return -1; + return n.longValue(); + } + + public String getLabel() { + return Long.toString(getPid()) + " " + notNull(getName()); //$NON-NLS-1$ + } + + public String getName() { + return (String)properties.get(ISysMonitor.PROP_FILE); + } + + public long getPPid() { + Number n = (Number)properties.get(ISysMonitor.PROP_PPID); + if (n == null) return -1; + return n.longValue(); + } + + public long getPid() { + Number n = (Number)properties.get(ISysMonitor.PROP_PID); + if (n == null) return -1; + return n.longValue(); + } + + public String getState() { + return (String)properties.get(ISysMonitor.PROP_STATE); + } + + public long getTgid() { + Number n = (Number)properties.get(ISysMonitor.PROP_TGID); + if (n == null) return -1; + return n.longValue(); + } + + public long getTracerPid() { + Number n = (Number)properties.get(ISysMonitor.PROP_TRACERPID); + if (n == null) return -1; + return n.longValue(); + } + + public long getUid() { + Number n = (Number)properties.get(ISysMonitor.PROP_UID); + if (n == null) return -1; + return n.longValue(); + } + + public String getUsername() { + return (String)properties.get(ISysMonitor.PROP_USERNAME); + } + + public long getVmRSSInKB() { + Number rss = (Number)properties.get(ISysMonitor.PROP_RSS); + Number psz = (Number)properties.get(ISysMonitor.PROP_PSIZE); + if (rss == null || psz == null) return 0; + return (rss.longValue() * psz.longValue() + 1023) / 1024; + } + + public long getVmSizeInKB() { + Number vsz = (Number)properties.get(ISysMonitor.PROP_VSIZE); + if (vsz == null) return 0; + return (vsz.longValue() + 1023) / 1024; + } + + public boolean isRoot() { + return true; + } + + private String notNull(String s) { + return s == null ? "" : s; + } + + String getStatusLine() { + final String STATUS_DELIMITER = "|"; //$NON-NLS-1$ + StringBuffer s = new StringBuffer(); + s.append(getPid()).append(STATUS_DELIMITER); + s.append(notNull(getName())).append(STATUS_DELIMITER); + s.append(notNull(getState())).append(STATUS_DELIMITER); + s.append(getTgid()).append(STATUS_DELIMITER); + s.append(getPPid()).append(STATUS_DELIMITER); + s.append('0').append(STATUS_DELIMITER); + s.append(getUid()).append(STATUS_DELIMITER); + s.append(notNull(getUsername())).append(STATUS_DELIMITER); + s.append(getGid()).append(STATUS_DELIMITER); + s.append(getVmSizeInKB()).append(STATUS_DELIMITER); + s.append(getVmRSSInKB()).append(STATUS_DELIMITER); + return s.toString(); + } + + public Map<String,Object> getProperties() { + return properties; + } + + private void runChildrenWaitList() { + assert !children_loading; + assert children_loaded; + try { + running_wait_list = true; + for (Runnable r : children_wait_list) r.run(); + children_wait_list.clear(); + } + finally { + running_wait_list = false; + } + } + + public Throwable getChildrenError() { + return children_error; + } + + public void flushChildrenCache() { + Map<Long,TCFProcessResource> pid2res = rse_service.getProcessCache(); + for (TCFProcessResource r : children.values()) { + long pid = r.getPid(); + if (pid > 0 && getPid() != pid) pid2res.remove(r.getPid()); + } + children_loaded = false; + children_error = null; + } + + public boolean loadChildren(Runnable run) { + if (children_loaded) return true; + assert !running_wait_list; + children_wait_list.add(run); + if (children_loading) return false; + children_loading = true; + try { + final ISysMonitor m = rse_service.getTCFConnectorService().getSysMonitorService(); + m.getChildren(getID(), new ISysMonitor.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] ids) { + try { + if (error != null) { + loadProcessesDone(error, null); + } + else if (ids == null) { + loadProcessesDone(null, new TCFProcessResource[0]); + } + else { + final TCFProcessResource[] arr = new TCFProcessResource[ids.length]; + final Set<IHostProcess> pending = new HashSet<IHostProcess>(); + for (int i = 0; i < ids.length; i++) { + final TCFProcessResource r = new TCFProcessResource( + rse_service, m, children.get(ids[i]), ids[i]); + if (!r.validate(new Runnable() { + public void run() { + pending.remove(r); + if (pending.isEmpty()) loadProcessesDone(null, arr); + } + })) pending.add(r); + arr[i] = r; + } + if (pending.isEmpty()) loadProcessesDone(null, arr); + } + } + catch (Throwable x) { + loadProcessesDone(x, null); + } + } + }); + return false; + } + catch (Throwable x) { + loadProcessesDone(x, null); + return true; + } + } + + private void loadProcessesDone(Throwable error, TCFProcessResource[] arr) { + assert children_loading; + children_loading = false; + children_loaded = true; + children.clear(); + if (arr != null && error == null) { + Map<Long,TCFProcessResource> pid2res = rse_service.getProcessCache(); + for (TCFProcessResource r : arr) { + long pid = r.getPid(); + if (pid > 0 && getPid() != pid) pid2res.put(pid, r); + if (r.getError() == null) children.put(r.getID(), r); + } + } + children_error = error; + runChildrenWaitList(); + } + + @Override + public String toString() { + return "[" + getStatusLine() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessService.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessService.java new file mode 100644 index 000000000..82f1bc622 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessService.java @@ -0,0 +1,258 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Martin Oberhuber (Wind River) - [238564] Adopt TM 3.0 APIs + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Intel Corporation - [329654] Make all sub services operate against TCF connector service + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; +import org.eclipse.rse.services.processes.AbstractProcessService; +import org.eclipse.rse.services.processes.IProcessService; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; +import org.eclipse.tm.internal.tcf.rse.TCFRSETask; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IProcesses; + + +public class TCFProcessService extends AbstractProcessService implements IProcessService { + + private final TCFConnectorService connector; + private final TCFProcessResource root; + private final Map<Long,TCFProcessResource> pid2res = new HashMap<Long,TCFProcessResource>(); + private final Map<String,Long> signals = new HashMap<String,Long>(); + private final List<Runnable> get_signals_wait_list = new ArrayList<Runnable>(); + + public TCFProcessService(IHost host) { + connector = (TCFConnectorService)TCFConnectorServiceManager + .getInstance().getConnectorService(host, ITCFService.class); + root = new TCFProcessResource(this, null, null, null); + } + + public TCFConnectorService getTCFConnectorService() { + return connector; + } + + @Override + public String getDescription() { + return "The TCF Process Service uses the Target Communication Framework to provide service for the Processes subsystem." + //$NON-NLS-1$ + " It requires a TCF agent to be running on the remote machine."; //$NON-NLS-1$ + } + + @Override + public String getName() { + return "TCF Process Service"; //$NON-NLS-1$ + } + + @Override + public IHostProcess getParentProcess(long PID, IProgressMonitor monitor) throws SystemMessageException { + return getProcess(getProcess(PID, monitor).getPPid(), monitor); + } + + @Override + public IHostProcess getProcess(final long PID, IProgressMonitor monitor) throws SystemMessageException { + return new TCFRSETask<IHostProcess>() { + public void run() { + if (!root.loadChildren(this)) return; + if (root.getChildrenError() != null) { + error(root.getChildrenError()); + return; + } + done(pid2res.get(PID)); + } + }.getS(monitor, "Get process properties"); //$NON-NLS-1$ + } + + public String[] getSignalTypes() { + return new TCFRSETask<String[]>() { + public void run() { + if (signals.isEmpty()) { + if (get_signals_wait_list.contains(this)) { + done(signals.keySet().toArray(new String[signals.size()])); + } + else { + if (get_signals_wait_list.isEmpty()) { + connector.getService(IProcesses.class).getSignalList(null, new IProcesses.DoneGetSignalList() { + public void doneGetSignalList(IToken token, Exception error, Collection<Map<String,Object>> list) { + if (list != null) { + for (Map<String,Object> m : list) { + String name = (String)m.get(IProcesses.SIG_NAME); + Number code = (Number)m.get(IProcesses.SIG_CODE); + if (name != null && code != null) signals.put(name, code.longValue()); + } + } + for (Runnable r : get_signals_wait_list) r.run(); + get_signals_wait_list.clear(); + } + }); + } + get_signals_wait_list.add(this); + } + } + else { + done(signals.keySet().toArray(new String[signals.size()])); + } + } + }.getE(); + } + + public boolean kill(final long PID, final String signal, IProgressMonitor monitor) throws SystemMessageException { + return new TCFRSETask<Boolean>() { + public void run() { + if (!root.loadChildren(this)) return; + if (root.getChildrenError() != null) { + error(root.getChildrenError()); + return; + } + TCFProcessResource prs = pid2res.get(PID); + if (prs == null) { + done(false); + return; + } + Long signo = signals.get(signal); + if (signal.equals(ISystemProcessRemoteConstants.PROCESS_SIGNAL_TYPE_DEFAULT)) { + if (signo == null) signo = signals.get("SIGTERM"); + if (signo == null) signo = signals.get("SIGKILL"); + } + if (signo == null) { + error(new Exception("Unknown signal: " + signal)); + return; + } + connector.getService(IProcesses.class).signal(prs.getID(), signo.longValue(), new IProcesses.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) { + error(error); + } + else { + done(true); + } + } + }); + } + }.getS(monitor, "Sending signal to a process"); //$NON-NLS-1$ + } + + private void sort(IHostProcess[] arr) { + Comparator<IHostProcess> c = new Comparator<IHostProcess>() { + public int compare(IHostProcess o1, IHostProcess o2) { + long p1 = o1.getPid(); + long p2 = o2.getPid(); + if (p1 < p2) return -1; + if (p1 > p2) return 1; + return 0; + } + }; + Arrays.sort(arr, c); + } + + @Override + public IHostProcess[] listAllProcesses(IProgressMonitor monitor) throws SystemMessageException { + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + return listAllProcesses(rpfs, monitor); + } + + public IHostProcess[] listAllProcesses(final IHostProcessFilter filter, IProgressMonitor monitor) throws SystemMessageException { + return listAllProcesses(filter, root, monitor); + } + + private boolean eqaulIDs(String x, String y) { + if (x == null) return y == null; + return x.equals(y); + } + + public IHostProcess[] listAllProcesses(final IHostProcessFilter filter, final IHostProcess up, IProgressMonitor monitor) throws SystemMessageException { + new TCFRSETask<Boolean>() { + public void run() { + TCFProcessResource parent = (TCFProcessResource)up; + if (parent != null) { + if (filter.getPpid() == null || filter.getPpid().equals("*") || parent.getChildrenError() != null) { //$NON-NLS-1$ + parent.flushChildrenCache(); + } + } + done(true); + } + }.getE(); + return new TCFRSETask<IHostProcess[]>() { + public void run() { + TCFProcessResource parent = (TCFProcessResource)up; + if (parent == null) { + error(new IOException("Invalid parent")); //$NON-NLS-1$ + return; + } + if (!parent.loadChildren(this)) return; + if (parent.getChildrenError() != null) { + error(parent.getChildrenError()); + return; + } + List<IHostProcess> l = new ArrayList<IHostProcess>(); + for (TCFProcessResource p : pid2res.values()) { + if (eqaulIDs(parent.getID(), p.getParentID())) { + if (p.getError() == null && filter.allows(p.getStatusLine())) l.add(p); + } + } + IHostProcess[] arr = new IHostProcess[l.size()]; + l.toArray(arr); + sort(arr); + done(arr); + } + }.getS(monitor, "List processes"); //$NON-NLS-1$ + } + + @Override + public IHostProcess[] listAllProcesses(String exeNameFilter, String userNameFilter, String stateFilter, IProgressMonitor monitor) + throws SystemMessageException { + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setName(exeNameFilter); + rpfs.setUsername(userNameFilter); + rpfs.setSpecificState(stateFilter); + return listAllProcesses(rpfs, monitor); + } + + @Override + public IHostProcess[] listChildProcesses(long parentPID, IProgressMonitor monitor) throws SystemMessageException { + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + return listChildProcesses(parentPID, rpfs, monitor); + } + + @Override + public IHostProcess[] listChildProcesses(long parentPID, IHostProcessFilter filter, IProgressMonitor monitor) + throws SystemMessageException { + filter.setPpid(Long.toString(parentPID)); + return listAllProcesses(filter, monitor); + } + + @Override + public IHostProcess[] listRootProcesses(IProgressMonitor monitor) throws SystemMessageException { + IHostProcess[] roots = new IHostProcess[1]; + roots[0] = getProcess(1, monitor); + return roots; + } + + Map<Long,TCFProcessResource> getProcessCache() { + return pid2res; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessSubSystemConfiguration.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessSubSystemConfiguration.java new file mode 100644 index 000000000..cd8698c0f --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFProcessSubSystemConfiguration.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + * Intel Corporation - [329654] Make all sub services operate against TCF connector service + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.services.processes.IProcessService; +import org.eclipse.rse.subsystems.processes.core.subsystem.IHostProcessToRemoteProcessAdapter; +import org.eclipse.rse.subsystems.processes.servicesubsystem.ProcessServiceSubSystem; +import org.eclipse.rse.subsystems.processes.servicesubsystem.ProcessServiceSubSystemConfiguration; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; + +public class TCFProcessSubSystemConfiguration extends ProcessServiceSubSystemConfiguration { + + private final TCFProcessAdapter process_adapter = new TCFProcessAdapter(); + + @Override + public Class<ITCFService> getServiceImplType() { + return ITCFService.class; + } + + @Override + public ISubSystem createSubSystemInternal(IHost host) { + TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host); + return new ProcessServiceSubSystem(host, connectorService, + getProcessService(host), getHostProcessAdapter()); + } + + public IProcessService createProcessService(IHost host) { + return new TCFProcessService(host); + } + + public IHostProcessToRemoteProcessAdapter getHostProcessAdapter() { + return process_adapter; + } + + @Override + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance() + .getConnectorService(host, getServiceImplType()); + } + + @Override + public void setConnectorService(IHost host, IConnectorService connectorService) { + TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService); + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFRemoteProcess.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFRemoteProcess.java new file mode 100644 index 000000000..26b10dac0 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFRemoteProcess.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import java.util.Map; + +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessContext; +import org.eclipse.rse.subsystems.processes.core.subsystem.impl.RemoteProcessImpl; + +public class TCFRemoteProcess extends RemoteProcessImpl { + + public TCFRemoteProcess(IRemoteProcessContext context, IHostProcess process) { + super(context, process); + assert process != null; + } + + @Override + public Object getObject() { + return _underlyingProcess; + } + + public Map<String,Object> getProperties() { + return ((TCFProcessResource)_underlyingProcess).getProperties(); + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewProcessAdapterFactory.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewProcessAdapterFactory.java new file mode 100644 index 000000000..7a9b1771a --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewProcessAdapterFactory.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.rse.core.subsystems.IRemoteObjectIdentifier; +import org.eclipse.rse.core.subsystems.ISystemDragDropAdapter; +import org.eclipse.rse.ui.view.ISystemRemoteElementAdapter; +import org.eclipse.rse.ui.view.ISystemViewElementAdapter; +import org.eclipse.ui.IActionFilter; +import org.eclipse.ui.model.IWorkbenchAdapter; +import org.eclipse.ui.progress.IDeferredWorkbenchAdapter; +import org.eclipse.ui.views.properties.IPropertySource; + +public class TCFSystemViewProcessAdapterFactory implements IAdapterFactory { + + private final TCFSystemViewRemoteProcessAdapter adapter = + new TCFSystemViewRemoteProcessAdapter(); + + @SuppressWarnings("rawtypes") + public Object getAdapter(Object adaptableObject, Class adapterType) { + assert adaptableObject instanceof TCFRemoteProcess; + if (adapterType == IPropertySource.class) { + ((ISystemViewElementAdapter)adapter).setPropertySourceInput(adaptableObject); + } + return adapter; + } + + @SuppressWarnings("rawtypes") + public Class[] getAdapterList() { + return new Class[] { + ISystemViewElementAdapter.class, + ISystemDragDropAdapter.class, + ISystemRemoteElementAdapter.class, + IPropertySource.class, + IWorkbenchAdapter.class, + IActionFilter.class, + IDeferredWorkbenchAdapter.class, + IRemoteObjectIdentifier.class, + }; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewRemoteProcessAdapter.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewRemoteProcessAdapter.java new file mode 100644 index 000000000..cf14e0018 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/processes/TCFSystemViewRemoteProcessAdapter.java @@ -0,0 +1,502 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Wind River Systems, Inc. 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 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Uwe Stieber (Wind River) - [271227] Fix compiler warnings in org.eclipse.tm.tcf.rse + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.processes; + +import java.math.BigInteger; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.rse.core.model.ISystemMessageObject; +import org.eclipse.rse.core.model.ISystemResourceSet; +import org.eclipse.rse.core.model.SystemMessageObject; +import org.eclipse.rse.core.model.SystemRemoteResourceSet; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.processes.ui.actions.SystemKillProcessAction; +import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteTypes; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessSubSystem; +import org.eclipse.rse.ui.ISystemContextMenuConstants; +import org.eclipse.rse.ui.ISystemMessages; +import org.eclipse.rse.ui.RSEUIPlugin; +import org.eclipse.rse.ui.SystemBasePlugin; +import org.eclipse.rse.ui.SystemMenuManager; +import org.eclipse.rse.ui.actions.SystemCopyToClipboardAction; +import org.eclipse.rse.ui.view.AbstractSystemViewAdapter; +import org.eclipse.rse.ui.view.ISystemRemoteElementAdapter; +import org.eclipse.rse.ui.view.ISystemViewElementAdapter; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.internal.tcf.rse.Activator; +import org.eclipse.tm.internal.tcf.rse.Messages; +import org.eclipse.tm.tcf.services.ISysMonitor; +import org.eclipse.ui.views.properties.IPropertyDescriptor; + + +@SuppressWarnings("restriction") +public class TCFSystemViewRemoteProcessAdapter extends AbstractSystemViewAdapter + implements ISystemViewElementAdapter, ISystemRemoteElementAdapter{ + + private SystemCopyToClipboardAction copyClipboardAction; + private static final Object[] EMPTY_LIST = new Object[0]; + private static IPropertyDescriptor[] properties = null; + private SystemKillProcessAction killProcessAction; + + private static final NumberFormat percent_format; + + static { + percent_format = NumberFormat.getPercentInstance(); + percent_format.setMaximumFractionDigits(3); + } + + @Override + public boolean canDrag(Object element) { + return true; + } + + @Override + public boolean canDrag(SystemRemoteResourceSet elements) { + return true; + } + + @Override + public Object doDrag(Object element, boolean sameSystemType, IProgressMonitor monitor) { + return getText(element); + } + + @Override + public ISystemResourceSet doDrag(SystemRemoteResourceSet set, IProgressMonitor monitor) { + return set; + } + + @Override + public void addActions(SystemMenuManager menu, + IStructuredSelection selection, Shell parent, String menuGroup) { + if (killProcessAction == null) { + killProcessAction = new SystemKillProcessAction(getShell()); + } + menu.add(ISystemContextMenuConstants.GROUP_CHANGE, killProcessAction); + if (copyClipboardAction == null) { + Clipboard clipboard = RSEUIPlugin.getTheSystemRegistryUI().getSystemClipboard(); + copyClipboardAction = new SystemCopyToClipboardAction(getShell(), clipboard); + } + menu.add(menuGroup, copyClipboardAction); + } + + @Override + public ISubSystem getSubSystem(Object element) { + if (element instanceof IRemoteProcess) { + IRemoteProcess process = (IRemoteProcess)element; + return process.getParentRemoteProcessSubSystem(); + } + return super.getSubSystem(element); + } + + @Override + public ImageDescriptor getImageDescriptor(Object element) { + IRemoteProcess process = (IRemoteProcess)element; + TCFProcessResource r = (TCFProcessResource)process.getObject(); + String state = r.getState(); + if (r.getParentID() != null) { + if (state == null || state.indexOf('R') >= 0) { + return Activator.getDefault().getImageDescriptorFromPath("icons/thread-r.gif"); //$NON-NLS-1$ + } + return Activator.getDefault().getImageDescriptorFromPath("icons/thread-s.gif"); //$NON-NLS-1$ + } + else { + if (state == null || state.indexOf('R') >= 0) { + return Activator.getDefault().getImageDescriptorFromPath("icons/process-r.gif"); //$NON-NLS-1$ + } + return Activator.getDefault().getImageDescriptorFromPath("icons/process-s.gif"); //$NON-NLS-1$ + } + } + + public String getText(Object element) { + String text = ((IRemoteProcess)element).getLabel(); + return (text == null) ? "" : text; //$NON-NLS-1$ + } + + @Override + public String getAlternateText(Object element) { + IRemoteProcess process = (IRemoteProcess)element; + String allProperties = process.getAllProperties(); + return allProperties.replace('|', '\t'); + } + + public String getAbsoluteName(Object object) { + IRemoteProcess process = (IRemoteProcess) object; + return "" + process.getPid(); //$NON-NLS-1$ + } + + @Override + public String getType(Object element) { + return "Process"; //$NON-NLS-1$ + } + + @Override + public Object getParent(Object element) { + IRemoteProcess process = (IRemoteProcess) element; + IRemoteProcess parent = process.getParentRemoteProcess(); + if ((parent != null) && parent.getAbsolutePath().equals(process.getAbsolutePath())) + // should never happen but sometimes it does, leading to infinite loop. + parent = null; + return parent; + } + + @Override + public boolean hasChildren(IAdaptable element) { + return getChildren(element, new NullProgressMonitor()).length > 0; + } + + @Override + public Object[] getChildren(IAdaptable element, IProgressMonitor monitor) { + IRemoteProcess process = (IRemoteProcess)element; + IRemoteProcessSubSystem ss = process.getParentRemoteProcessSubSystem(); + IHostProcessFilter orgRpfs = process.getFilterString(); + IHostProcessFilter newRpfs = new HostProcessFilterImpl(orgRpfs.toString()); + + Object[] children1 = null; + Object[] children2 = null; + newRpfs.setPpid(Long.toString(process.getPid())); + + try { + TCFProcessResource r = (TCFProcessResource)process.getObject(); + IHostProcess[] nodes = r.getService().listAllProcesses(orgRpfs, r, monitor); + TCFProcessAdapter adapter = new TCFProcessAdapter(); + children1 = adapter.convertToRemoteProcesses(process.getContext(), process, nodes); + if (children1 == null) children1 = EMPTY_LIST; + + children2 = ss.listAllProcesses(newRpfs, process.getContext(), monitor); + if (children2 == null) children2 = EMPTY_LIST; + } + catch (Exception exc) { + children1 = new SystemMessageObject[1]; + children1[0] = new SystemMessageObject(RSEUIPlugin.getPluginMessage(ISystemMessages.MSG_EXPAND_FAILED), ISystemMessageObject.MSGTYPE_ERROR, element); + children2 = null; + SystemBasePlugin.logError("Exception resolving file filter strings", exc); //$NON-NLS-1$ + } + if (children1 == null || children1.length == 0) return children2; + if (children2 == null || children2.length == 0) return children1; + Object[] children = new Object[children1.length + children2.length]; + System.arraycopy(children1, 0, children, 0, children1.length); + System.arraycopy(children2, 0, children, children1.length, children2.length); + return children; + } + + @Override + protected IPropertyDescriptor[] internalGetPropertyDescriptors() { + if (properties != null) return properties; + List<IPropertyDescriptor> l = new ArrayList<IPropertyDescriptor>(); + + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ID, Messages.PROCESS_ID_LABEL, Messages.PROCESS_ID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PID, Messages.PROCESS_PID_LABEL, Messages.PROCESS_PID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_FILE, Messages.PROCESS_NAME_LABEL, Messages.PROCESS_NAME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CWD, Messages.PROCESS_CWD_LABEL, Messages.PROCESS_CWD_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ROOT, Messages.PROCESS_ROOT_LABEL, Messages.PROCESS_ROOT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STATE, Messages.PROCESS_STATE_LABEL, Messages.PROCESS_STATE_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UID, Messages.PROCESS_UID_LABEL, Messages.PROCESS_UID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_USERNAME, Messages.PROCESS_USERNAME_LABEL, Messages.PROCESS_USERNAME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UGID, Messages.PROCESS_GID_LABEL, Messages.PROCESS_GID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_GROUPNAME, Messages.PROCESS_GROUPNAME_LABEL, Messages.PROCESS_GROUPNAME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PPID, Messages.PROCESS_PPID_LABEL, Messages.PROCESS_PPID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PGRP, Messages.PROCESS_PGRP_LABEL, Messages.PROCESS_PGRP_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TGID, Messages.PROCESS_TGID_LABEL, Messages.PROCESS_TGID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TRACERPID, Messages.PROCESS_TRACERPID_LABEL, Messages.PROCESS_TRACERPID_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_VSIZE, Messages.PROCESS_VMSIZE_LABEL, Messages.PROCESS_VMSIZE_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RSS, Messages.PROCESS_VMRSS_LABEL, Messages.PROCESS_VMRSS_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SESSION, Messages.PROCESS_SESSION_LABEL, Messages.PROCESS_SESSION_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TTY, Messages.PROCESS_TTY_LABEL, Messages.PROCESS_TTY_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_FLAGS, Messages.PROCESS_FLAGS_LABEL, Messages.PROCESS_FLAGS_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_MINFLT, Messages.PROCESS_MINFLT_LABEL, Messages.PROCESS_MINFLT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CMINFLT, Messages.PROCESS_CMINFLT_LABEL, Messages.PROCESS_CMINFLT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_MAJFLT, Messages.PROCESS_MAJFLT_LABEL, Messages.PROCESS_MAJFLT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CMAJFLT, Messages.PROCESS_CMAJFLT_LABEL, Messages.PROCESS_CMAJFLT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UTIME, Messages.PROCESS_UTIME_LABEL, Messages.PROCESS_UTIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STIME, Messages.PROCESS_STIME_LABEL, Messages.PROCESS_STIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CUTIME, Messages.PROCESS_CUTIME_LABEL, Messages.PROCESS_CUTIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CSTIME, Messages.PROCESS_CSTIME_LABEL, Messages.PROCESS_CSTIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(TCFProcessResource.PROP_PC_UTIME, Messages.PROCESS_PC_UTIME_LABEL, Messages.PROCESS_PC_UTIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(TCFProcessResource.PROP_PC_STIME, Messages.PROCESS_PC_STIME_LABEL, Messages.PROCESS_PC_STIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PRIORITY, Messages.PROCESS_PRIORITY_LABEL, Messages.PROCESS_PRIORITY_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_NICE, Messages.PROCESS_NICE_LABEL, Messages.PROCESS_NICE_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ITREALVALUE, Messages.PROCESS_ITREALVALUE_LABEL, Messages.PROCESS_ITREALVALUE_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STARTTIME, Messages.PROCESS_STARTTIME_LABEL, Messages.PROCESS_STARTTIME_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RLIMIT, Messages.PROCESS_RLIMIT_LABEL, Messages.PROCESS_RLIMIT_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CODESTART, Messages.PROCESS_CODESTART_LABEL, Messages.PROCESS_CODESTART_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CODEEND, Messages.PROCESS_CODEEND_LABEL, Messages.PROCESS_CODEEND_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STACKSTART, Messages.PROCESS_STACKSTART_LABEL, Messages.PROCESS_STACKSTART_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGNALS, Messages.PROCESS_SIGNALS_LABEL, Messages.PROCESS_SIGNALS_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGBLOCK, Messages.PROCESS_SIGBLOCK_LABEL, Messages.PROCESS_SIGBLOCK_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGIGNORE, Messages.PROCESS_SIGIGNORE_LABEL, Messages.PROCESS_SIGIGNORE_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGCATCH, Messages.PROCESS_SIGCATCH_LABEL, Messages.PROCESS_SIGCATCH_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_WCHAN, Messages.PROCESS_WCHAN_LABEL, Messages.PROCESS_WCHAN_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_NSWAP, Messages.PROCESS_NSWAP_LABEL, Messages.PROCESS_NSWAP_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CNSWAP, Messages.PROCESS_CNSWAP_LABEL, Messages.PROCESS_CNSWAP_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_EXITSIGNAL, Messages.PROCESS_EXITSIGNAL_LABEL, Messages.PROCESS_EXITSIGNAL_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PROCESSOR, Messages.PROCESS_PROCESSOR_LABEL, Messages.PROCESS_PROCESSOR_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RTPRIORITY, Messages.PROCESS_RTPRIORITY_LABEL, Messages.PROCESS_RTPRIORITY_TOOLTIP)); + l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_POLICY, Messages.PROCESS_POLICY_LABEL, Messages.PROCESS_POLICY_TOOLTIP)); + + properties = l.toArray(new IPropertyDescriptor[l.size()]); + return properties; + } + + /** + * Returns the current value for the named property. + * @return the current value of the given property + */ + @Override + protected Object internalGetPropertyValue(Object property) { + Object v = internalGetPropertyValueOrNull(property); + if (v == null) v = ""; + return v; + } + + private Object internalGetPropertyValueOrNull(Object property) { + TCFRemoteProcess process = (TCFRemoteProcess)propertySourceInput; + Object p = process.getProperties().get(property); + if (property.equals(ISysMonitor.PROP_VSIZE)) { + return NLS.bind(Messages.PROCESS_VMSIZE_VALUE, Long.toString(process.getVmSizeInKB())); + } + if (property.equals(ISysMonitor.PROP_RSS)) { + return NLS.bind(Messages.PROCESS_VMRSS_VALUE, Long.toString(process.getVmRSSInKB())); + } + if (property.equals(ISysMonitor.PROP_SIGNALS)) return formatBitSet(p); + if (property.equals(ISysMonitor.PROP_SIGBLOCK)) return formatBitSet(p); + if (property.equals(ISysMonitor.PROP_SIGCATCH)) return formatBitSet(p); + if (property.equals(ISysMonitor.PROP_SIGIGNORE)) return formatBitSet(p); + if (property.equals(ISysMonitor.PROP_CODESTART)) return formatHex(p); + if (property.equals(ISysMonitor.PROP_CODEEND)) return formatHex(p); + if (property.equals(ISysMonitor.PROP_STACKSTART)) return formatHex(p); + if (property.equals(ISysMonitor.PROP_WCHAN)) return formatHex(p); + if (property.equals(ISysMonitor.PROP_FLAGS)) return formatBitSet(p); + if (property.equals(ISysMonitor.PROP_UTIME)) return formatTime(p); + if (property.equals(ISysMonitor.PROP_STIME)) return formatTime(p); + if (property.equals(ISysMonitor.PROP_CUTIME)) return formatTime(p); + if (property.equals(ISysMonitor.PROP_CSTIME)) return formatTime(p); + if (property.equals(ISysMonitor.PROP_STARTTIME)) return formatTime(p); + if (property.equals(ISysMonitor.PROP_ITREALVALUE)) return formatTime(p); + if (property.equals(TCFProcessResource.PROP_PC_UTIME)) return formatPercent(p); + if (property.equals(TCFProcessResource.PROP_PC_STIME)) return formatPercent(p); + if (p != null) return p.toString(); + return null; + } + + /** + * Returns the current value for the named property. + * + * @param property the name or key of the property as named by its property descriptor + * @param formatted indication of whether to return the value in formatted or raw form + * @return the current value of the given property + */ + @Override + public Object getPropertyValue(Object property, boolean formatted) { + if (formatted) return getPropertyValue(property); + + TCFRemoteProcess process = (TCFRemoteProcess)propertySourceInput; + Object p = process.getProperties().get(property); + if (p == null) { + if (property.equals(ISysMonitor.PROP_PID)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_PPID)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_CODESTART)) return BigInteger.ZERO; + if (property.equals(ISysMonitor.PROP_CODEEND)) return BigInteger.ZERO; + if (property.equals(ISysMonitor.PROP_STACKSTART)) return BigInteger.ZERO; + if (property.equals(ISysMonitor.PROP_WCHAN)) return BigInteger.ZERO; + if (property.equals(ISysMonitor.PROP_UTIME)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_STIME)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_CUTIME)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_CSTIME)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_STARTTIME)) return Long.valueOf(0); + if (property.equals(ISysMonitor.PROP_ITREALVALUE)) return Long.valueOf(0); + if (property.equals(TCFProcessResource.PROP_PC_UTIME)) return Double.valueOf(0); + if (property.equals(TCFProcessResource.PROP_PC_STIME)) return Double.valueOf(0); + if (property.equals(ISysMonitor.PROP_CWD)) return ""; + if (property.equals(ISysMonitor.PROP_FILE)) return ""; + } + return p; + } + + private String formatPercent(Object o) { + if (o instanceof Number) { + Number n = (Number)o; + return percent_format.format(n.doubleValue()); + } + return null; + } + + private String formatTime(Object o) { + if (o instanceof Number) { + BigInteger n = new BigInteger(o.toString()); + BigInteger s[] = n.divideAndRemainder(BigInteger.valueOf(1000)); + BigInteger m[] = s[0].divideAndRemainder(BigInteger.valueOf(60)); + BigInteger h[] = m[0].divideAndRemainder(BigInteger.valueOf(60)); + StringBuffer buf = new StringBuffer(); + if (!h[0].equals(BigInteger.ZERO)) { + buf.append(h[0]); + buf.append("h "); //$NON-NLS-1$ + } + if (buf.length() > 0 || !h[1].equals(BigInteger.ZERO)) { + buf.append(h[1]); + buf.append("m "); //$NON-NLS-1$ + } + buf.append(m[1]); + buf.append('.'); + String ms = s[1].toString(); + buf.append("000".substring(ms.length())); //$NON-NLS-1$ + buf.append(ms); + buf.append('s'); + return buf.toString(); + } + if (o == null) return null; + return o.toString(); + } + + private void formatHex(StringBuffer buf, BigInteger n, int cnt) { + BigInteger m[] = n.divideAndRemainder(BigInteger.valueOf(16)); + if (cnt < 7 || !m[0].equals(BigInteger.ZERO)) { + formatHex(buf, m[0], cnt + 1); + } + int d = m[1].intValue(); + buf.append((char)(d <= 9 ? '0' + d : 'a' + d - 10)); + } + + protected String formatHex(Object o) { + if (o instanceof Number) { + BigInteger n = o instanceof BigInteger ? + (BigInteger)o : new BigInteger(o.toString()); + StringBuffer buf = new StringBuffer(); + buf.append("0x"); //$NON-NLS-1$ + formatHex(buf, n, 0); + return buf.toString(); + } + if (o == null) return null; + return o.toString(); + } + + protected String formatBitSet(Object o) { + if (o instanceof Number) { + StringBuffer buf = new StringBuffer(); + long n = ((Number)o).longValue(); + for (int i = 0; i < 64; i++) { + if ((n & (1l << i)) != 0) { + if (buf.length() > 0) buf.append(','); + int i0 = i; + while (i < 63 && (n & (1l << (i + 1))) != 0) i++; + buf.append(i0); + if (i0 != i) { + buf.append(".."); //$NON-NLS-1$ + buf.append(i); + } + } + } + return buf.toString(); + } + if (o == null) return null; + return o.toString(); + } + + protected String formatState(String state) { + return state; + } + + /** + * Return fully qualified name that uniquely identifies this remote object's remote parent within its subsystem + */ + public String getAbsoluteParentName(Object element) { + IRemoteProcess process = (IRemoteProcess) element; + IRemoteProcess parent = process.getParentRemoteProcess(); + if (parent != null) return parent.getAbsolutePath(); + else return "/proc/0"; //$NON-NLS-1$ + } + + /** + * Given a remote object, returns it remote parent object. Eg, given a process, return the process that + * spawned it. + * <p> + * The shell is required in order to set the cursor to a busy state if a remote trip is required. + * + * @return an IRemoteProcess object for the parent + */ + public Object getRemoteParent(Object element, IProgressMonitor monitor) throws Exception { + return ((IRemoteProcess) element).getParentRemoteProcess(); + } + + /** + * Given a remote object, return the unqualified names of the objects contained in that parent. This is + * used for testing for uniqueness on a rename operation, for example. Sometimes, it is not + * enough to just enumerate all the objects in the parent for this purpose, because duplicate + * names are allowed if the types are different, such as on iSeries. In this case return only + * the names which should be used to do name-uniqueness validation on a rename operation. + * + * @return an array of all file and folder names in the parent of the given IRemoteFile object + */ + public String[] getRemoteParentNamesInUse(Object element, IProgressMonitor monitor) throws Exception { + String[] pids = EMPTY_STRING_LIST; + + IRemoteProcess process = (IRemoteProcess) element; + String parentName = "" + process.getPPid(); //$NON-NLS-1$ + if (parentName.equals("-1")) // given a root? //$NON-NLS-1$ + return pids; // not much we can do. Should never happen: you can't rename a root! + + Object[] children = getChildren(process.getParentRemoteProcess(), monitor); + if ((children == null) || (children.length == 0)) + return pids; + + pids = new String[children.length]; + for (int idx = 0; idx < pids.length; idx++) + pids[idx] = "" + ((IRemoteProcess) children[idx]).getPid(); //$NON-NLS-1$ + + return pids; + } + + public String getRemoteSubType(Object element) { + return null; + } + + public String getRemoteType(Object element) { + IRemoteProcess process = (IRemoteProcess) element; + if (process.isRoot()) + return ISystemProcessRemoteTypes.TYPE_ROOT; + else + return ISystemProcessRemoteTypes.TYPE_PROCESS; + } + + public String getRemoteTypeCategory(Object element) { + return ISystemProcessRemoteTypes.TYPECATEGORY; + } + + /** + * Return the subsystem factory id that owns this remote object + * The value must not be translated, so that property pages registered via xml can subset by it. + */ + public String getSubSystemConfigurationId(Object element) { + IRemoteProcess process = (IRemoteProcess) element; + return process.getParentRemoteProcessSubSystem().getSubSystemConfiguration().getId(); + } + + public boolean refreshRemoteObject(Object oldElement, Object newElement) { + return false; + } + + public boolean supportsUserDefinedActions(Object object) { + return false; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFServiceCommandShell.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFServiceCommandShell.java new file mode 100644 index 000000000..f7c55c77d --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFServiceCommandShell.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 IBM Corporation 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalServiceCommandShell + * Martin Oberhuber (Wind River) - [225510][api] Fix OutputRefreshJob API leakage + * Anna Dushistova (MontaVista) - [259414][api] refactor the "SSH Shell" to use the generic Terminal->IHostShell converter + * Anna Dushistova (MontaVista) - [261478] Remove SshShellService, SshHostShell (or deprecate and schedule for removal in 3.2) + * David McKnight (IBM) - [272032][ssh][telnet][local] shell output not setting line numbers when available + * Liping Ke (Intel Corp.)- Adapted from org.eclipse.rse.internal.subsystems.shells.ssh.SshServiceCommandShell + * Liping Ke (Intel Corp.)- [246987] Implement TCF Shell/terminal services + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.shells; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.shells.TerminalServiceHostShell; +import org.eclipse.rse.services.shells.IHostOutput; +import org.eclipse.rse.services.shells.IHostShell; +import org.eclipse.rse.services.shells.IHostShellChangeEvent; +import org.eclipse.rse.services.shells.ParsedOutput; +import org.eclipse.rse.services.shells.Patterns; +import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem; +import org.eclipse.rse.subsystems.shells.core.model.ISystemOutputRemoteTypes; +import org.eclipse.rse.subsystems.shells.core.model.RemoteError; +import org.eclipse.rse.subsystems.shells.core.model.RemoteOutput; +import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem; +import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteOutput; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ServiceCommandShell; + +@SuppressWarnings("restriction") +public class TCFServiceCommandShell extends ServiceCommandShell { + private Patterns _patterns; + private String _workingDir; + private String _curCommand; + private IRemoteFileSubSystem _fs; + + public TCFServiceCommandShell(IRemoteCmdSubSystem cmdSS, + IHostShell hostShell) { + super(cmdSS, hostShell); + _patterns = new Patterns(); + _patterns.update("cmd"); //$NON-NLS-1$ + ISubSystem[] sses = cmdSS.getHost().getSubSystems(); + for (int i = 0; i < sses.length; i++) + { + if (sses[i] instanceof IRemoteFileSubSystem) + { + _fs = (IRemoteFileSubSystem)sses[i]; + break; + } + } + } + + public Object getContext() + { + String workingDir = _workingDir; + if (workingDir != null && workingDir.length() > 0) + { + try { + return _fs.getRemoteFileObject(workingDir, new NullProgressMonitor()); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + return null; + + } + + public String getContextString() + { + return _workingDir; + } + + public void shellOutputChanged(IHostShellChangeEvent event) + { + IHostOutput[] lines = event.getLines(); + boolean gotCommand = false; + ArrayList<RemoteOutput> outputs = new ArrayList<RemoteOutput>(lines.length); + for (int i = 0; i < lines.length; i++) + { + String line = lines[i].getString(); + if (line.endsWith(getPromptCommand())) { + continue; //ignore our synthetic prompt command + } + ParsedOutput parsedMsg = null; + if (!gotCommand && line.equals(_curCommand)) { + gotCommand = true; + continue; //ignore remote command echo + } else + { + try + { + // Bug 160202: Remote shell dies. + if ((_curCommand == null) || (!_curCommand.trim().equals("ls"))) { //$NON-NLS-1$ + parsedMsg = _patterns.matchLine(line); + + // Bug 160202: Remote shell dies. + if (_curCommand != null) { + String temp = _curCommand.trim(); + StringTokenizer tokenizer = new StringTokenizer(temp); + + if (tokenizer.countTokens() == 2) { + String token1 = tokenizer.nextToken(); + String token2 = tokenizer.nextToken(); + + if ((token1.equals("ls")) && (token2.indexOf('-') == 0) && (token2.indexOf('l') > 0)) { //$NON-NLS-1$ + if (line.startsWith("total")) { //$NON-NLS-1$ + parsedMsg = null; + } + } + } + } + } + } + catch (Throwable e) { + e.printStackTrace(); + } + } + + RemoteOutput output = null; + + String type = "stdout"; //$NON-NLS-1$ + + if (parsedMsg != null) { + type = parsedMsg.type; + } + + if (event.isError()) { + output = new RemoteError(this, type); + } + else { + output = new RemoteOutput(this, type); + } + + output.setText(line); + if (parsedMsg != null) + { + String file = parsedMsg.file; + if (type.equals(ISystemOutputRemoteTypes.TYPE_PROMPT)) + { + _workingDir = file; + output.setAbsolutePath(_workingDir); + } + else if(_workingDir!=null) + { + IPath p = new Path(_workingDir).append(file); + output.setAbsolutePath(p.toString()); + } + else + { + output.setAbsolutePath(file); + } + if (parsedMsg.line > 0){ + output.setLine(parsedMsg.line); + } + } + + addOutput(output); + outputs.add(output); + } + + IRemoteOutput[] remoteOutputs = outputs.toArray(new IRemoteOutput[outputs.size()]); + notifyOutputChanged(remoteOutputs, false); + } + + /** + * Return the prompt command, such that lines ending with the + * prompt command can be removed from output. + * Should be overridden in case the IHostShell used for this + * service is not an SshHostShell. + * @return String promptCommand + */ + protected String getPromptCommand() { + IHostShell shell = getHostShell(); + if (shell instanceof TerminalServiceHostShell) { + return ((TerminalServiceHostShell)shell).getPromptCommand(); + } + //return something impossible such that nothing is ever matched + return "\uffff"; //$NON-NLS-1$ + } + + public void writeToShell(String cmd) + { + _curCommand = cmd; + _patterns.update(cmd); + super.writeToShell(cmd); + + } + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFShellSubSystemConfiguration.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFShellSubSystemConfiguration.java new file mode 100644 index 000000000..46b5902d1 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFShellSubSystemConfiguration.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 IBM Corporation 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted template for ssh service. + * Anna Dushistova (MontaVista) - [259414][api] refactor the "SSH Shell" to use the generic Terminal->IHostShell converter + * Liping Ke (Intel Corp.)- Adapted from org.eclipse.rse.subsystems.shells.ssh.SshShellSubSystemConfiguration + * Liping Ke (Intel Corp.)- [246987] Implement TCF Shell/terminal services + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.shells; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.services.shells.IHostShell; +import org.eclipse.rse.services.shells.IShellService; +import org.eclipse.rse.subsystems.shells.core.subsystems.IRemoteCmdSubSystem; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.IServiceCommandShell; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystem; +import org.eclipse.rse.subsystems.shells.core.subsystems.servicesubsystem.ShellServiceSubSystemConfiguration; +import org.eclipse.tm.internal.tcf.rse.*; +import org.eclipse.tm.internal.tcf.rse.terminals.TCFTerminalService; + + +public class TCFShellSubSystemConfiguration extends + ShellServiceSubSystemConfiguration { + + public TCFShellSubSystemConfiguration() { + super(); + } + + /** + * Instantiate and return an instance of OUR subsystem. + * Do not populate it yet though! + * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost) + */ + public ISubSystem createSubSystemInternal(IHost host) + { + TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host); + ISubSystem subsys = new ShellServiceSubSystem(host, connectorService, createShellService(host)); + return subsys; + } + + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance().getConnectorService(host, getServiceImplType()); +} + + public void setConnectorService(IHost host, + IConnectorService connectorService) { + TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService); + } + + public Class<ITCFService> getServiceImplType() + { + return ITCFService.class; + } + + public IServiceCommandShell createRemoteCommandShell(IRemoteCmdSubSystem cmdSS, IHostShell hostShell) { + return new TCFServiceCommandShell(cmdSS, hostShell); + } + + public IShellService createShellService(IHost host) { + TCFConnectorService cserv = (TCFConnectorService)getConnectorService(host); + + return (IShellService) (new TCFTerminalService(cserv)).getAdapter(IShellService.class); + } + + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalInputStream.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalInputStream.java new file mode 100644 index 000000000..2c7d44e18 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalInputStream.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2010 Intel Corporation. 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 + * + * Contributors: + * Liping Ke (Intel Corp.) - initial API and implementation + ******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.shells; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.util.TCFTask; + +public class TCFTerminalInputStream extends InputStream { + private IStreams streams; + private boolean connected = true;;/* The stream is connected or not */ + String is_id; + private int value; + private boolean bEof = false;; + + public TCFTerminalInputStream(final IStreams streams, final String is_id) throws IOException{ + if (streams == null) + throw new IOException("TCP streams is null");//$NON-NLS-1$ + this.streams = streams; + this.is_id = is_id; + } + + /* read must be synchronized */ + @Override + public synchronized int read() throws IOException { + if (!connected) + throw new IOException("istream is not connected");//$NON-NLS-1$ + if (bEof) + return -1; + try { + new TCFTask<Object>() { + public void run() { + streams.read(is_id, 1, new IStreams.DoneRead() { + public void doneRead(IToken token, Exception error, int lostSize, + byte[] data, boolean eos) { + if (error != null) { + error(error); + return; + } + bEof = eos; + if (data != null) { + value = (int)data[0]; + } + else + value = -1; + done(this); + } + }); + } + }.getIO(); + } + catch (Exception e) { + e.printStackTrace();//$NON-NLS-1$ + throw new IOException(e.getMessage());//$NON-NLS-1$ + } + return value; + } + + private static class Buffer { + byte[] buf; + Buffer() { + } + } + private Buffer buffer; + + public synchronized int read(byte b[], final int off, final int len) throws IOException { + + + if (!connected) + throw new IOException("istream is not connected");//$NON-NLS-1$ + if (bEof) return -1; + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + try { + new TCFTask<Buffer>() { + public void run() { + streams.read(is_id, len, new IStreams.DoneRead() { + public void doneRead(IToken token, Exception error, int lostSize, + byte[] data, boolean eos) { + if (error != null) { + error(error); + return; + } + bEof = eos; + if (data != null) { + buffer = new Buffer(); + buffer.buf = data; + + } + done(buffer); + } + }); + } + }.getIO(); + + if (buffer.buf != null) { + int length = buffer.buf.length; + System.arraycopy(buffer.buf, 0, b, off, length); + return length; + } + else if (bEof) + return -1; + else return 0; + } catch (Exception ee) { + throw new IOException(ee.getMessage());//$NON-NLS-1$ + } + } + + public void close() throws IOException { + if (!connected) return; + new TCFTask<Object>() { + public void run() { + streams.disconnect(is_id, new IStreams.DoneDisconnect() { + public void doneDisconnect(IToken token, Exception error) { + connected = false; + done(this); + } + }); + } + }.getIO(); + connected = false; + } + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalOutputStream.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalOutputStream.java new file mode 100644 index 000000000..ffb0bae22 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalOutputStream.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2010 Intel Corporation. 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 + * + * Contributors: + * Liping Ke (Intel Corp.) - initial API and implementation + ******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.shells; + +import java.io.IOException; + +import java.io.OutputStream; + +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.util.TCFTask; + +public class TCFTerminalOutputStream extends OutputStream { + + private final IStreams streams; + private boolean connected = true; + private boolean write_eof; + String os_id; + + public TCFTerminalOutputStream(final IStreams streams, final String os_id) throws IOException{ + if (streams == null) throw new IOException("istream is null");//$NON-NLS-1$ + this.streams = streams; + this.os_id = os_id; + write_eof = false; + } + + @Override + public synchronized void write(final byte b[], final int off, final int len) throws IOException { + /* If eof is written, we can't write anything into the stream */ + if (!connected || write_eof) + throw new IOException("stream is not connected or write_eof already!");//$NON-NLS-1$ + try { + new TCFTask<Object>() { + public void run() { + streams.write(os_id, b, off, len, new IStreams.DoneWrite() { + public void doneWrite(IToken token, Exception error) { + if (error != null) error(error); + done(this); + } + }); + + } + }.getIO(); + } + catch (Exception e) + { + throw new IOException(e.getMessage());//$NON-NLS-1$ + } + } + + @Override + public synchronized void write(int b) throws IOException { + + try { + final byte[] buf = new byte[1]; + buf[0] = (byte)b; + this.write(buf, 0, 1); + } + catch(IOException ioe) { + throw new IOException(ioe.getMessage());//$NON-NLS-1$ + } + + } + + /* close must be called --Need to reconsider it in the future*/ + public void close() throws IOException { + if (!connected) + return; + try { + new TCFTask<Object>() { + public void run() { + streams.eos(os_id, new IStreams.DoneEOS() { + public void doneEOS(IToken token, Exception error) { + write_eof = true; + done(this); + } + }); + } + }.getIO(); + new TCFTask<Object>() { + public void run() { + streams.disconnect(os_id, new IStreams.DoneDisconnect() { + public void doneDisconnect(IToken token, Exception error) { + connected = false; + done(this); + } + }); + + } + }.getIO(); + } + catch(Exception e) { + throw new IOException(e.getMessage()); //$NON-NLS-1$ + } + } + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalShell.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalShell.java new file mode 100644 index 000000000..f180dd7a5 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/shells/TCFTerminalShell.java @@ -0,0 +1,444 @@ + /******************************************************************************* + * Copyright (c) 2006, 2010 Wind River Systems, Inc., Intel Corporation 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 + + + * Contributors: + * Liping Ke (Intel Corp.) - initial API and implementation + * Sheldon D'souza (Celunite) - LoginThread and readUntil implementation + * Liping Ke (Intel Corp.) - For non-login mode, we don't need detect command prompt + ******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.shells; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.rse.core.model.IPropertySet; +import org.eclipse.rse.services.clientserver.PathUtility; +import org.eclipse.rse.services.clientserver.messages.CommonMessages; +import org.eclipse.rse.services.clientserver.messages.ICommonMessageIds; +import org.eclipse.rse.services.clientserver.messages.SimpleSystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.terminals.AbstractTerminalShell; +import org.eclipse.rse.services.terminals.ITerminalService; +import org.eclipse.rse.ui.SystemBasePlugin; +import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider; +import org.eclipse.tm.internal.tcf.rse.Messages; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFRSETask; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.services.ITerminals; + + +public class TCFTerminalShell extends AbstractTerminalShell { + private ITCFSessionProvider fSessionProvider; + private IChannel fChannel; + private String fPtyType; + private ITerminals.TerminalContext terminalContext; + private String fEncoding; + private InputStream fInputStream; + private OutputStream fOutputStream; + private Writer fOutputStreamWriter; + private int fWidth = 0; + private int fHeight = 0; + private String fContextID; + private String in_id; + private String out_id; + private boolean connected = false; + private ITerminals terminal; + private int status; + + private IPropertySet tcfPropertySet = null; + + private static String defaultEncoding = new java.io.InputStreamReader(new java.io.ByteArrayInputStream(new byte[0])).getEncoding(); + private ITerminals.TerminalsListener listeners = new ITerminals.TerminalsListener(){ + + public void exited(String terminalId, int exitCode) { + + if(!terminalContext.getID().equals(terminalId)) + return; + terminal.removeListener(listeners); + TCFTerminalShell.this.connected = false; + } + + + public void winSizeChanged(String terminalId, int newWidth, + int newHeight) { + + } + }; + + /* LoginThread and readUntil functionality are cloned from TelnetConnectorService + * and then modified for our own needs + * */ + private class LoginThread extends Thread { + + private String username; + private String password; + private int status = ITCFSessionProvider.SUCCESS_CODE; + public LoginThread(String username, String password) { + this.username = username; + this.password = password; + } + + public void run() { + tcfPropertySet = ((TCFConnectorService)fSessionProvider).getTCFPropertySet(); + /* By default, we only support non-login mode. If user open the + * switch on the agent side, he can also set the properties in + * TCF connection property*/ + String login_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_REQUIRED); + + if (Boolean.valueOf(login_required).booleanValue()) { + String login_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_LOGIN_PROMPT); + String password_prompt =tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PASSWORD_PROMPT); + String command_prompt = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_COMMAND_PROMPT); + String pwd_required = tcfPropertySet.getPropertyValue(TCFConnectorService.PROPERTY_PWD_REQUIRED); + status = ITCFSessionProvider.SUCCESS_CODE; + if (login_prompt != null && login_prompt.length() > 0) { + status = readUntil(login_prompt,fInputStream); + write(username + "\n"); //$NON-NLS-1$ + } + if (Boolean.valueOf(pwd_required).booleanValue()) { + if (status == ITCFSessionProvider.SUCCESS_CODE && password_prompt != null && password_prompt.length() > 0) { + status = readUntil(password_prompt,fInputStream); + write(password + "\n"); //$NON-NLS-1$ + } + } + if (status == ITCFSessionProvider.SUCCESS_CODE && command_prompt != null && command_prompt.length() > 0) { + status = readUntil(command_prompt,fInputStream); + write("\n"); //$NON-NLS-1$ + } + } else { + status = ITCFSessionProvider.SUCCESS_CODE; + } + } + + public int readUntil(String pattern,InputStream in) { + try { + char lastChar = pattern.charAt(pattern.length() - 1); + StringBuffer sb = new StringBuffer(); + int ch = in.read(); + while (ch >= 0) { + char tch = (char) ch; + sb.append(tch); + if (tch=='t' && sb.indexOf("incorrect") >= 0) { //$NON-NLS-1$ + return ITCFSessionProvider.ERROR_CODE; + } + if (tch=='d' && sb.indexOf("closed") >= 0) { //$NON-NLS-1$ + return ITCFSessionProvider.CONNECT_CLOSED; + } + if (tch == lastChar) { + if (sb.toString().endsWith(pattern)) { + return ITCFSessionProvider.SUCCESS_CODE; + } + } + ch = in.read(); + } + } + catch (Exception e) { + e.printStackTrace(); + SystemBasePlugin.logError(e.getMessage() == null ? e.getClass().getName() : e.getMessage(), e); + } + return ITCFSessionProvider.CONNECT_CLOSED; + } + + public int getLoginStatus() { + return this.status; + } + + } + + public void write(String value) { + try { + fOutputStream.write(value.getBytes()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private int login(String username, String password) throws InterruptedException + { + long millisToEnd = System.currentTimeMillis() + ITCFSessionProvider.TCP_CONNECT_TIMEOUT*1000; + LoginThread checkLogin = new LoginThread(username, password); + status = ITCFSessionProvider.ERROR_CODE; + checkLogin.start(); + while (checkLogin.isAlive() && System.currentTimeMillis()<millisToEnd) + checkLogin.join(500); + status = checkLogin.getLoginStatus(); + checkLogin.join(); + return status; + } + /** + * Construct a new TCF connection. + * + * The TCF channel is immediately connected in the Constructor. + * + * @param sessionProvider TCF session provider + * @param ptyType Terminal type to set, or <code>null</code> if not + * relevant + * @param encoding The default encoding to use for initial command. + * @param environment Environment array to set, or <code>null</code> if + * not relevant. + * @param initialWorkingDirectory initial directory to open the Terminal in. + * Use <code>null</code> or empty String ("") to start in a + * default directory. Empty String will typically start in the + * home directory. + * @param commandToRun initial command to send. + * @throws SystemMessageException in case anything goes wrong. Channels and + * Streams are all cleaned up again in this case. + * @see ITerminalService + */ + public TCFTerminalShell(final ITCFSessionProvider sessionProvider, final String ptyType, + final String encoding, final String[] environment, + String initialWorkingDirectory, String commandToRun) + throws SystemMessageException { + Map<String, Object> map_ids; + Exception nestedException = null; + try { + fSessionProvider = sessionProvider; + fEncoding = encoding; + fPtyType = ptyType; + fChannel = fSessionProvider.getChannel(); + + if (fChannel == null || fChannel.getState() != IChannel.STATE_OPEN) + throw new Exception("TCP channel is not connected!");//$NON-NLS-1$ + if (((TCFConnectorService)sessionProvider).isSubscribed() == false) + ((TCFConnectorService)sessionProvider).subscribe(); + assert (((TCFConnectorService)sessionProvider).isSubscribed()); + + new TCFRSETask<ITerminals.TerminalContext>() { + public void run() { + terminal = ((TCFConnectorService)sessionProvider).getService(ITerminals.class); + terminal.launch(ptyType, encoding, environment, new ITerminals.DoneLaunch() { + public void doneLaunch(IToken token, Exception error, + ITerminals.TerminalContext ctx) { + + if (ctx != null) { + terminalContext = ctx; + terminal.addListener(listeners); + } + + if (error != null) error(error); + else done(ctx); + } + }); + } + + }.getS(null, Messages.TCFTerminalService_Name); + + fPtyType = terminalContext.getPtyType(); + fEncoding = terminalContext.getEncoding(); + fContextID = terminalContext.getID(); + fWidth = terminalContext.getWidth(); + fHeight = terminalContext.getHeight(); + map_ids = terminalContext.getProperties(); + in_id = (String)map_ids.get(ITerminals.PROP_STDOUT_ID); + out_id = (String)map_ids.get(ITerminals.PROP_STDIN_ID); + + String user = fSessionProvider.getSessionUserId(); + String password = fSessionProvider.getSessionPassword(); + status = ITCFSessionProvider.ERROR_CODE; + + IStreams streams = new TCFRSETask<IStreams>() { + public void run() { + done(((TCFConnectorService)sessionProvider).getService(IStreams.class)); + } + }.getS(null, Messages.TCFTerminalService_Name); + fOutputStream = new TCFTerminalOutputStream(streams, out_id); + fInputStream = new TCFTerminalInputStream(streams, in_id); + if (fEncoding != null) { + fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream, encoding)); + } else { + // default encoding == System.getProperty("file.encoding") + // TODO should try to determine remote encoding if possible + fOutputStreamWriter = new BufferedWriter(new OutputStreamWriter(fOutputStream)); + } + + try { + status = login(user, password); + } + finally + { + if ((status == ITCFSessionProvider.CONNECT_CLOSED)) + { + //Give one time chance of retrying.... + } + + } + + //give another chance of retrying + if ((status == ITCFSessionProvider.CONNECT_CLOSED)) + { + ((TCFConnectorService)sessionProvider).unsubscribe(); + ((TCFConnectorService)sessionProvider).subscribe(); + assert (((TCFConnectorService)sessionProvider).isSubscribed()); + status = login(user, password); + } + + connected = true; + if (initialWorkingDirectory!=null && initialWorkingDirectory.length()>0 + && !initialWorkingDirectory.equals(".") //$NON-NLS-1$ + && !initialWorkingDirectory.equals("Command Shell") //$NON-NLS-1$ //FIXME workaround for bug 153047 + ) { + writeToShell("cd " + PathUtility.enQuoteUnix(initialWorkingDirectory)); //$NON-NLS-1$ + } + + if (commandToRun != null && commandToRun.length() > 0) { + writeToShell(commandToRun); + } + + } + catch (Exception e) + { + e.printStackTrace(); + nestedException = e; + } + finally { + if (status == ITCFSessionProvider.SUCCESS_CODE) { + } + else { + SystemMessage msg; + + if (nestedException!=null) { + msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID, + ICommonMessageIds.MSG_EXCEPTION_OCCURRED, + IStatus.ERROR, + CommonMessages.MSG_EXCEPTION_OCCURRED, nestedException); + } else { + String strErr; + if (status == ITCFSessionProvider.CONNECT_CLOSED) + strErr = "Connection closed!";//$NON-NLS-1$ + else if (status == ITCFSessionProvider.ERROR_CODE) + strErr = "Login Incorrect or meet other unknown error!";//$NON-NLS-1$ + else + strErr = "Not identified Errors";//$NON-NLS-1$ + + msg = new SimpleSystemMessage(org.eclipse.tm.internal.tcf.rse.Activator.PLUGIN_ID, + ICommonMessageIds.MSG_COMM_AUTH_FAILED, + IStatus.ERROR, + strErr, + "Meet error when trying to login in!");//$NON-NLS-1$ + msg.makeSubstitution(((TCFConnectorService)fSessionProvider).getHost().getAliasName()); + } + throw new SystemMessageException(msg);//$NON-NLS-1$ + } + } + + } + + public void writeToShell(String command) throws IOException { + if (isActive()) { + if ("#break".equals(command)) { //$NON-NLS-1$ + command = "\u0003"; // Unicode 3 == Ctrl+C //$NON-NLS-1$ + } else { + command += "\r\n"; //$NON-NLS-1$ + } + fOutputStreamWriter.write(command); + } + } + + public void exit() { + + if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) { + return; + } + try { + getOutputStream().close(); + getInputStream().close(); + + } + catch (IOException ioe) { + ioe.printStackTrace(); + } //$NON-NLS-1$ + + try { + new TCFRSETask<Object>() { + public void run() { + terminalContext.exit(new ITerminals.DoneCommand(){ + public void doneCommand(IToken token, + Exception error) { + if (error != null) + error(error); + else { + done(this); + } + } + }); + }}.getS(null, Messages.TCFShellService_Name); //seems no need block here. need further modification. + } + catch (SystemMessageException e) { + e.printStackTrace(); + } //$NON-NLS-1$; + } + + public InputStream getInputStream() { + return fInputStream; + } + + public OutputStream getOutputStream() { + return fOutputStream; + } + + public boolean isActive() { + if (fChannel != null && !(fChannel.getState() == IChannel.STATE_CLOSED) && connected) { + return true; + } + exit(); + // shell is not active: check for session lost + return false; + } + + public String getPtyType() { + return fPtyType; + } + + public void setTerminalSize(int newWidth, int newHeight) { + if (fChannel == null || (fChannel.getState() == IChannel.STATE_CLOSED) || !connected) { + // do nothing + return; + } + fWidth = newWidth; + fHeight = newHeight; + try { + new TCFRSETask<Object>() { + public void run() { + if (fChannel != null && connected) { + terminal.setWinSize(fContextID, fWidth, fHeight, new ITerminals.DoneCommand(){ + + public void doneCommand(IToken token, Exception error) { + if (error != null) + error(error); + else + done(this); + + }}); + + } + else { + done(this); + } + }}.getS(null, Messages.TCFShellService_Name); + } + catch (SystemMessageException e) { + e.printStackTrace(); + } //$NON-NLS-1$; + } + + public String getDefaultEncoding() { + if (fEncoding != null) return fEncoding; + return defaultEncoding; + } + +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalService.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalService.java new file mode 100644 index 000000000..e3ee65dc4 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalService.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2010 Intel Corporation. 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 + * + * Contributors: + * Liping Ke(Intel Corp.) - initial API and implementation + ******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.terminals; + +import org.eclipse.core.runtime.IProgressMonitor; + +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.terminals.AbstractTerminalService; +import org.eclipse.rse.services.terminals.ITerminalShell; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.ITCFSessionProvider; +import org.eclipse.tm.internal.tcf.rse.Messages; +import org.eclipse.tm.internal.tcf.rse.shells.TCFTerminalShell; + +public class TCFTerminalService extends AbstractTerminalService implements ITCFService{ + private final ITCFSessionProvider fSessionProvider; + + /** + * Return the TCF property set, and fill it with default values if it has + * not been created yet. Extender may override in order to set different + * default values. + * + * @return a property set holding properties understood by the TCF + * connector service. + */ + public ITerminalShell launchTerminal(String ptyType, String encoding, + String[] environment, String initialWorkingDirectory, + String commandToRun, IProgressMonitor monitor) + throws SystemMessageException { + TCFTerminalShell hostShell = new TCFTerminalShell(fSessionProvider, ptyType, encoding, environment, initialWorkingDirectory, commandToRun); + return hostShell; + } + + + public TCFTerminalService(ITCFSessionProvider sessionProvider) { + fSessionProvider = sessionProvider; + } + + public ITCFSessionProvider getSessionProvider() { + return fSessionProvider; + } + @Override + public String getName() { + return Messages.TCFTerminalService_Name; + } + @Override + public String getDescription() { + return Messages.TCFTerminalService_Description; + } +} diff --git a/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java new file mode 100644 index 000000000..817f1c7b2 --- /dev/null +++ b/plugins/org.eclipse.tcf.rse/src/org/eclipse/tcf/internal/rse/terminals/TCFTerminalServiceSubSystemConfiguration.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2008, 2010 MontaVista Software, Inc. 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 + * + * Contributors: + * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Anna Dushistova (MontaVista) - [240530][rseterminal][apidoc] Add terminals.rse Javadoc into org.eclipse.rse.doc.isv + * Liping Ke (Intel Corp.) - Adapted from TerminalServiceSubSystemConfiguration + * Liping Ke (Intel Corp.) - TCF terminal services subsystem implementation + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.rse.terminals; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.services.terminals.ITerminalService; +import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystem; +import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystemConfiguration; +import org.eclipse.tm.internal.tcf.rse.ITCFService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorService; +import org.eclipse.tm.internal.tcf.rse.TCFConnectorServiceManager; + +public class TCFTerminalServiceSubSystemConfiguration extends + TerminalServiceSubSystemConfiguration { + + + /** + * Instantiate and return an instance of OUR subsystem. Do not populate it + * yet though! + * + * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost) + */ + public ISubSystem createSubSystemInternal(IHost host) { + TCFConnectorService connectorService = (TCFConnectorService) getConnectorService(host); + ISubSystem subsys = new TerminalServiceSubSystem(host, + connectorService, createTerminalService(host)); + return subsys; + } + + /** + * @inheritDoc + * @since 1.0 + */ + public ITerminalService createTerminalService(IHost host) { + TCFConnectorService cserv = (TCFConnectorService) getConnectorService(host); + return new TCFTerminalService(cserv); + } + + public IConnectorService getConnectorService(IHost host) { + return TCFConnectorServiceManager.getInstance().getConnectorService( + host, getServiceImplType()); + } + + public void setConnectorService(IHost host, + IConnectorService connectorService) { + TCFConnectorServiceManager.getInstance().setConnectorService(host, + getServiceImplType(), connectorService); + } + + public Class<ITCFService> getServiceImplType() { + return ITCFService.class; + } + +} |