diff --git a/rse/plugins/org.eclipse.rse.processes.ui/.classpath b/rse/plugins/org.eclipse.rse.processes.ui/.classpath new file mode 100644 index 00000000000..751c8f2e504 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.processes.ui/.cvsignore b/rse/plugins/org.eclipse.rse.processes.ui/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/rse/plugins/org.eclipse.rse.processes.ui/.project b/rse/plugins/org.eclipse.rse.processes.ui/.project new file mode 100644 index 00000000000..82980f8922e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.processes.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.processes.ui/HelpContexts.xml b/rse/plugins/org.eclipse.rse.processes.ui/HelpContexts.xml new file mode 100644 index 00000000000..284e1f84bd9 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/HelpContexts.xml @@ -0,0 +1,57 @@ + + + + + + +Specify a simple executable name or a generic name pattern, containing up to 2 wildcard characters *. For example, abc*def*. Specify * to list all executables. + + + +Specify a simple username or a generic name pattern, containing up to 2 wildcard characters *. For example, abc*def*. Specify * to list all users. + + + +Specify an integer group id to list all processes whose owners belong to that group. + + + +Choose one or more status types to restrict. Only processes with the selected states will be shown for this filter string. + + + +Set this to any positive long integer to show only processes with virtual memory usage greater than this value. + + + +Set this to any positive long integer to show only processes with virtual memory usage less than this value. + + + +Check this box to show only processes with virtual memory usage greater than the value specified in the Minimum VM entry field, but with no maximum VM size. + + + +Kill the selected process or processes. You will be prompted for the type of kill signal to be sent to the process or processes. + + + + +Select the process or processes to which you wish to send a kill signal. Select the type of signal to be sent from the combo box. Then press OK to send the signal to the process or processes. + + + \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.processes.ui/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..42c0ff36e74 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/META-INF/MANIFEST.MF @@ -0,0 +1,35 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %plugin.name +Bundle-SymbolicName: org.eclipse.rse.processes.ui;singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.rse.processes.ui.ProcessesPlugin +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.rse.services, + org.eclipse.core.resources, + org.eclipse.ui.ide, + org.eclipse.ui.views, + org.eclipse.debug.core, + org.eclipse.ui.workbench.texteditor, + org.eclipse.jface.text, + org.eclipse.search, + org.eclipse.compare, + org.eclipse.rse.subsystems.shells.core, + org.eclipse.rse.subsystems.files.core, + org.eclipse.rse.subsystems.processes.core, + org.eclipse.jface, + org.eclipse.rse.services, + org.eclipse.ui, + org.eclipse.ui.views, + org.eclipse.core.runtime, + org.eclipse.rse.ui +Export-Package: org.eclipse.rse.processes.ui, + org.eclipse.rse.processes.ui.actions, + org.eclipse.rse.processes.ui.dialogs, + org.eclipse.rse.processes.ui.propertypages, + org.eclipse.rse.processes.ui.view +Eclipse-LazyStart: true +Bundle-Vendor: Eclipse.org +Bundle-ClassPath: processes_ui.jar diff --git a/rse/plugins/org.eclipse.rse.processes.ui/about.html b/rse/plugins/org.eclipse.rse.processes.ui/about.html new file mode 100644 index 00000000000..6f6b96c4c87 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

February 24, 2005

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content.

+ + + \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/build.properties b/rse/plugins/org.eclipse.rse.processes.ui/build.properties new file mode 100644 index 00000000000..6794cecf340 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/build.properties @@ -0,0 +1,20 @@ +bin.includes = META-INF/,\ + plugin.xml,\ + HelpContexts.xml,\ + about.html,\ + icons/,\ + messageFile.dtd,\ + plugin.properties,\ + systemmessages.xml,\ + processes_ui.jar +src.includes = HelpContexts.xml,\ + about.html,\ + META-INF/,\ + icons/,\ + messageFile.dtd,\ + plugin.properties,\ + plugin.xml,\ + systemmessages.xml +source.processes_ui.jar = src/ +jars.compile.order = processes_ui.jar +output.processes_ui.jar = bin/ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/dlcl16/killprocessj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/dlcl16/killprocessj.gif new file mode 100644 index 00000000000..5cc47ff7e98 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/dlcl16/killprocessj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/elcl16/killprocessj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/elcl16/killprocessj.gif new file mode 100644 index 00000000000..ef6a25d94e0 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/elcl16/killprocessj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess.gif new file mode 100644 index 00000000000..7902f8115c3 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess_obj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess_obj.gif new file mode 100644 index 00000000000..87aa144a81c Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/activeprocess_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/inactiveprocess_obj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/inactiveprocess_obj.gif new file mode 100644 index 00000000000..c1644b2ecc4 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/inactiveprocess_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystem_obj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystem_obj.gif new file mode 100644 index 00000000000..e07b81aa6c9 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystem_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystemlive_obj.gif b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystemlive_obj.gif new file mode 100644 index 00000000000..96a447a7175 Binary files /dev/null and b/rse/plugins/org.eclipse.rse.processes.ui/icons/full/obj16/processsubsystemlive_obj.gif differ diff --git a/rse/plugins/org.eclipse.rse.processes.ui/messageFile.dtd b/rse/plugins/org.eclipse.rse.processes.ui/messageFile.dtd new file mode 100644 index 00000000000..2f6a27b1fda --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/messageFile.dtd @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.processes.ui/plugin.properties b/rse/plugins/org.eclipse.rse.processes.ui/plugin.properties new file mode 100644 index 00000000000..ffdc89c29bc --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/plugin.properties @@ -0,0 +1,24 @@ +################################################################################ +# Copyright (c) 2005, 2006 IBM Corporation. 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: +# {Name} (company) - description of contribution. +################################################################################ + +# NLS_MESSAGEFORMAT_VAR + +plugin.name = RSE Processes UI + +Factory.LocalProcesses = Local Processes +PropertyPage.ServerLauncherSettings = Server Launcher Settings +PropertyPage.ServerConnectionSecurity= Server Connection Security +PropertyPage.Service = Service \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/plugin.xml b/rse/plugins/org.eclipse.rse.processes.ui/plugin.xml new file mode 100644 index 00000000000..53df753565b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/plugin.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/ProcessesPlugin.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/ProcessesPlugin.java new file mode 100644 index 00000000000..98170e7bf30 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/ProcessesPlugin.java @@ -0,0 +1,167 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.rse.core.SystemBasePlugin; +import org.eclipse.rse.processes.ui.view.RemoteProcessSubsystemFactoryAdapterFactory; +import org.eclipse.rse.processes.ui.view.SystemViewProcessAdapterFactory; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageFile; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + + +/** + * The main plugin class to be used in the desktop. + */ +public class ProcessesPlugin extends SystemBasePlugin { + //The shared instance. + private static ProcessesPlugin plugin; + //Resource bundle. + private ResourceBundle resourceBundle; + private SystemViewProcessAdapterFactory svpaf; + private static SystemMessageFile messageFile = null; + private static SystemMessageFile defaultMessageFile = null; + + public static final String HELPPREFIX = "org.eclipse.rse.processes.ui."; + + + /** + * The constructor. + */ + public ProcessesPlugin() { + super(); + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + messageFile = getMessageFile("systemmessages.xml"); + defaultMessageFile = getDefaultMessageFile("systemmessages.xml"); + + IAdapterManager manager = Platform.getAdapterManager(); + svpaf = new SystemViewProcessAdapterFactory(); + svpaf.registerWithManager(manager); + + RemoteProcessSubsystemFactoryAdapterFactory rpssfaf = new RemoteProcessSubsystemFactoryAdapterFactory(); + rpssfaf.registerWithManager(manager); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + resourceBundle = null; + } + + /** + * Returns the shared instance. + */ + public static ProcessesPlugin getDefault() { + return plugin; + } + + /** + * Returns the string from the plugin's resource bundle, + * or 'key' if not found. + */ + public static String getResourceString(String key) { + ResourceBundle bundle = ProcessesPlugin.getDefault().getResourceBundle(); + try { + return (bundle != null) ? bundle.getString(key) : key; + } catch (MissingResourceException e) { + return key; + } + } + + /** + * Returns the plugin's resource bundle, + */ + public ResourceBundle getResourceBundle() { + try { + if (resourceBundle == null) + resourceBundle = ResourceBundle.getBundle("org.eclipse.rse.processes.ui.SystemProcessesResources"); + } catch (MissingResourceException x) { + resourceBundle = null; + } + return resourceBundle; + } + + /** + * Retrieve a message from this plugin's message file + * @param msgId - the ID of the message to retrieve. This is the concatenation of the + * message's component abbreviation, subcomponent abbreviation, and message ID as declared + * in the message xml file. + */ + public static SystemMessage getPluginMessage(String msgId) + { + SystemMessage msg = getMessage(messageFile, msgId); + if (msg == null) + { + msg = getMessage(defaultMessageFile, msgId); + } + return msg; + } + + /** + * Load a message file for this plugin. + * @param messageFileName - the name of the message xml file. Will look for it in this plugin's install folder. + * @return a message file object containing the parsed contents of the message file, or null if not found. + */ + public SystemMessageFile getMessageFile(String messageFileName) + { + return loadMessageFile(getBundle(), messageFileName); + } + + /** + * Load a default message file for this plugin for cases where messages haven't been translated. + * @param messageFileName - the name of the message xml file. Will look for it in this plugin's install folder. + * @return a message file object containing the parsed contents of the message file, or null if not found. + */ + public SystemMessageFile getDefaultMessageFile(String messageFileName) + { + return loadDefaultMessageFile(getBundle(), messageFileName); + } + + public ImageDescriptor getImageDescriptorFromPath(String path) + { + return AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.rse.processes.ui", path); + } + + /** + * Initialize the image registry by declaring all of the required + * graphics. + */ + protected void initializeImageRegistry() + { + //String path = getIconPath(); + //putImageInRegistry(ISystemIconConstants.ICON_SYSTEM_NEWPROFILEWIZARD_ID, + // path+ISystemIconConstants.ICON_SYSTEM_NEWPROFILEWIZARD); + + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessFilterStringEditPane.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessFilterStringEditPane.java new file mode 100644 index 00000000000..ffbca8928e5 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessFilterStringEditPane.java @@ -0,0 +1,734 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui; + +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.rse.core.SystemBasePlugin; +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.processes.ui.view.SystemProcessStatesContentProvider; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessSubSystemConfiguration; +import org.eclipse.rse.ui.ISystemMessages; +import org.eclipse.rse.ui.SystemResources; +import org.eclipse.rse.ui.SystemWidgetHelpers; +import org.eclipse.rse.ui.actions.SystemTestFilterStringAction; +import org.eclipse.rse.ui.filters.SystemFilterStringEditPane; +import org.eclipse.rse.ui.messages.SystemMessageDialog; +import org.eclipse.rse.ui.validators.ValidatorIntegerInput; +import org.eclipse.rse.ui.validators.ValidatorIntegerRangeInput; +import org.eclipse.rse.ui.validators.ValidatorLongRangeInput; +import org.eclipse.rse.ui.validators.ValidatorSpecialChar; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + + +public class SystemProcessFilterStringEditPane extends + SystemFilterStringEditPane implements ISystemMessages, ISystemProcessRemoteConstants +{ + + // GUI widgets + + protected Label lblStatus; + protected CheckboxTableViewer chkStatus; + protected Label lblExeName, lblUserName, lblGid; + protected Text txtExeName, txtUserName, txtGid; + + protected Label lblMinVM, lblMaxVM; + protected Text txtMinVM, txtMaxVM; + protected Button chkBoxUnlimitedVM; + + // limits + protected int gidLimit = Integer.MAX_VALUE; + protected long vmMaxValue = Long.MAX_VALUE; + protected int exeNameLength = 256; + protected int userNameLength = 256; + + // validators + protected ValidatorLongRangeInput vmRangeValidator = new ValidatorLongRangeInput(0, vmMaxValue); + protected ValidatorIntegerRangeInput gidValidator = new ValidatorIntegerRangeInput(0, gidLimit); + protected ValidatorSpecialChar nameValidator = new ValidatorSpecialChar(" \t|", true); + + // inputs + protected String[] inputFilterStrings; + + // state + protected boolean noValidation = false; + protected boolean callerInstanceOfWizardPage, callerInstanceOfSystemPromptDialog; + protected boolean skipUniquenessChecking; + protected boolean calledFromVerify; + protected boolean dontStealFocus; + protected IRemoteProcessSubSystemConfiguration inputSubsystemFactory = null; + + // actions + protected SystemTestFilterStringAction testAction = null; + + // constants + protected final static int SIZING_SELECTION_WIDGET_HEIGHT = 90; + protected final static int SIZING_SELECTION_WIDGET_WIDTH = 145; + + /** + * Constructor for SystemProcessFilterStringEditPane. + * @param shell + */ + public SystemProcessFilterStringEditPane(Shell shell) + { + super(shell); + ((ValidatorIntegerInput)gidValidator).setBlankAllowed(true); + } + + // ------------------------------ + // INPUT/CONFIGURATION METHODS... + // ------------------------------ + + /** + * Call this to override the text limit for the filter name, from the default of 256. + */ + public void setExeNameLength(int max) + { + exeNameLength = max; + if (txtExeName != null) + txtExeName.setTextLimit(max); + } + /** + * Call this to override the text limit for the filter name, from the default of 256. + */ + public void setUserNameLength(int max) + { + userNameLength = max; + if (txtUserName != null) + txtUserName.setTextLimit(max); + } + /** + * Existing strings are used to aid in uniqueness validation. + */ + public void setExistingStrings(String[] existingStrings) + { + this.inputFilterStrings = existingStrings; + } + + // ------------------------------ + // LIFECYCLE METHODS... + // ------------------------------ + + /** + * Populate the pane with the GUI widgets + * @param parent + * @return Control + */ + public Control createContents(Composite parent) + { + Composite composite_prompts = SystemWidgetHelpers.createComposite(parent, 1); + int gridColumns = 2; + Composite sub_prompts1 = SystemWidgetHelpers.createComposite(composite_prompts, gridColumns); + + // Exe name prompt + lblExeName = SystemWidgetHelpers.createLabel(sub_prompts1, SystemProcessesResources.RESID_PROCESSFILTERSTRING_EXENAME_LABEL); + lblExeName.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_EXENAME_TOOLTIP); + txtExeName = SystemWidgetHelpers.createTextField(sub_prompts1, null); + txtExeName.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_EXENAME_TOOLTIP); + + SystemWidgetHelpers.setHelp(txtExeName, ProcessesPlugin.HELPPREFIX+"pfsd0001"); + updateGridData(txtExeName, gridColumns-1); + txtExeName.setText("*"); + + // User name prompt + lblUserName = SystemWidgetHelpers.createLabel(sub_prompts1, SystemProcessesResources.RESID_PROCESSFILTERSTRING_USERNAME_LABEL); + lblUserName.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_USERNAME_TOOLTIP); + txtUserName = SystemWidgetHelpers.createTextField(sub_prompts1, null); + txtUserName.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_USERNAME_TOOLTIP); + + SystemWidgetHelpers.setHelp(txtUserName, ProcessesPlugin.HELPPREFIX+"pfsd0002"); + updateGridData(txtUserName, gridColumns-1); + txtUserName.setText("*"); + + // Group ID prompt + lblGid = SystemWidgetHelpers.createLabel(sub_prompts1, SystemProcessesResources.RESID_PROCESSFILTERSTRING_GID_LABEL); + lblGid.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_GID_TOOLTIP); + txtGid = SystemWidgetHelpers.createTextField(sub_prompts1, null); + txtGid.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_GID_TOOLTIP); + + SystemWidgetHelpers.setHelp(txtGid, ProcessesPlugin.HELPPREFIX+"pfsd0003"); + updateGridData(txtGid, gridColumns-1); + txtGid.setText("*"); + + // status checkbox table + lblStatus = SystemWidgetHelpers.createLabel(sub_prompts1, SystemProcessesResources.RESID_PROCESSFILTERSTRING_STATUS_LABEL); + lblStatus.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_STATUS_TOOLTIP); + chkStatus = CheckboxTableViewer.newCheckList(sub_prompts1, SWT.BORDER); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING); + data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT; + data.widthHint = SIZING_SELECTION_WIDGET_WIDTH; + chkStatus.getTable().setLayoutData(data); + chkStatus.setLabelProvider(new LabelProvider()); + + SystemWidgetHelpers.setHelp(chkStatus.getControl(), ProcessesPlugin.HELPPREFIX+"pfsd0004"); + SystemWidgetHelpers.createLabel(sub_prompts1, " "); + addSelectionButtons(sub_prompts1); + + // Range prompt + Composite subsub = SystemWidgetHelpers.createComposite(sub_prompts1, gridColumns, 3, false, null, -1, -1); + lblMinVM = SystemWidgetHelpers.createLabel(subsub, SystemProcessesResources.RESID_PROCESSFILTERSTRING_MINVM_LABEL); + lblMinVM.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_MINVM_TOOLTIP); + txtMinVM = SystemWidgetHelpers.createTextField(subsub, null); + txtMinVM.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_MINVM_TOOLTIP); + + SystemWidgetHelpers.setHelp(txtMinVM, ProcessesPlugin.HELPPREFIX+"pfsd0005"); + txtMinVM.setText("0"); + SystemWidgetHelpers.createLabel(subsub, " "); + + lblMaxVM = SystemWidgetHelpers.createLabel(subsub, SystemProcessesResources.RESID_PROCESSFILTERSTRING_MAXVM_LABEL); + lblMaxVM.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_MAXVM_TOOLTIP); + txtMaxVM = SystemWidgetHelpers.createTextField(subsub, null); + txtMaxVM.setToolTipText(SystemProcessesResources.RESID_PROCESSFILTERSTRING_MAXVM_TOOLTIP); + + SystemWidgetHelpers.setHelp(txtMaxVM, ProcessesPlugin.HELPPREFIX+"pfsd0006"); + txtMaxVM.setEnabled(false); + + // Unlimited check box + chkBoxUnlimitedVM = SystemWidgetHelpers.createCheckBox(subsub, 1, null, + SystemProcessesResources.RESID_PROCESSFILTERSTRING_UNLIMITED_LABEL, SystemProcessesResources.RESID_PROCESSFILTERSTRING_UNLIMITED_TOOLTIP); + SystemWidgetHelpers.setHelp(chkBoxUnlimitedVM, ProcessesPlugin.HELPPREFIX+"pfsd0007"); + + txtExeName.setFocus(); + + if (refProvider != null) + inputSubsystemFactory = (IRemoteProcessSubSystemConfiguration)((ISubSystem)refProvider).getSubSystemConfiguration(); + else if (provider != null) + inputSubsystemFactory = (IRemoteProcessSubSystemConfiguration)provider; + IStructuredContentProvider p = new SystemProcessStatesContentProvider(); + + chkStatus.setContentProvider(p); + chkStatus.setInput(p.getElements(null)); + + txtExeName.setTextLimit(exeNameLength); + txtUserName.setTextLimit(userNameLength); + + resetFields(); + doInitializeFields(); + + txtExeName.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + validateNameInput(txtExeName); + } + } + ); + txtUserName.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + validateNameInput(txtUserName); + } + } + ); + txtGid.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + validateGidInput(); + } + } + ); + txtMinVM.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + if (validateMinVMInput() == null) + { + if (!chkBoxUnlimitedVM.getSelection() && !txtMaxVM.getText().trim().equals("")) + { + SystemMessage message = validateMinLessThanMax(); + fireChangeEvent(message); + } + } + } + } + ); + txtMaxVM.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + if (validateMaxVMInput() == null) + { + if (!txtMinVM.getText().trim().equals("")) + { + SystemMessage message = validateMinLessThanMax(); + fireChangeEvent(message); + } + } + } + } + ); + + chkBoxUnlimitedVM.addSelectionListener(this); + + return composite_prompts; + } + + /** + * Add the selection and deselection buttons to the dialog. + * @param composite org.eclipse.swt.widgets.Composite + */ + private void addSelectionButtons(Composite composite) + { + Composite buttonComposite = new Composite(composite, SWT.RIGHT); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + buttonComposite.setLayout(layout); + GridData data = + new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL); + data.grabExcessHorizontalSpace = true; + composite.setData(data); + + //Button selectButton = createButton(buttonComposite, IDialogConstants.SELECT_ALL_ID, WorkbenchMessages.getString("WizardTransferPage.selectAll"), false); //$NON-NLS-1$ + Button selectButton = SystemWidgetHelpers.createPushButton(buttonComposite, null, + SystemResources.RESID_SELECTFILES_SELECTALL_BUTTON_ROOT_LABEL, SystemResources.RESID_SELECTFILES_SELECTALL_BUTTON_ROOT_TOOLTIP); + + SelectionListener listener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + chkStatus.setAllChecked(true); + } + }; + selectButton.addSelectionListener(listener); + + + //Button deselectButton = createButton(buttonComposite, IDialogConstants.DESELECT_ALL_ID, WorkbenchMessages.getString("WizardTransferPage.deselectAll"), false); //$NON-NLS-1$ + Button deselectButton = SystemWidgetHelpers.createPushButton(buttonComposite, null, + SystemResources.RESID_SELECTFILES_DESELECTALL_BUTTON_ROOT_LABEL, SystemResources.RESID_SELECTFILES_DESELECTALL_BUTTON_ROOT_TOOLTIP); + + listener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + chkStatus.setAllChecked(false); + } + }; + deselectButton.addSelectionListener(listener); + } + + private void updateGridData(Control widget, int gridColumns) + { + GridData data = (GridData)widget.getLayoutData(); + data.horizontalSpan = gridColumns; + data.grabExcessHorizontalSpace = false; + data.horizontalAlignment = GridData.HORIZONTAL_ALIGN_BEGINNING; + } + + /** + * Return the control to recieve initial focus. Should be overridden if you override createContents + */ + public Control getInitialFocusControl() + { + return txtExeName; + } + + /** + * Override of parent. + * Called after reset fields, at first create time or when input is reset to a non-null value. + */ + protected void doInitializeFields() + { + if (txtExeName == null) return; + + if (inputFilterString != null) + { + HostProcessFilterImpl rffs = new HostProcessFilterImpl(inputFilterString); + String defaultExeName = rffs.getName(); + txtExeName.setText((defaultExeName==null) ? "" : defaultExeName); + String defaultUserName = rffs.getUsername(); + txtUserName.setText((defaultUserName==null) ? "" : defaultUserName); + + String defaultGid = rffs.getGid(); + txtGid.setText((defaultGid==null) ? "" : defaultGid); + String defaultMinVM = rffs.getMinVM(); + txtMinVM.setText((defaultMinVM==null) ? "" : defaultMinVM); + String defaultMaxVM = rffs.getMaxVM(); + if (defaultMaxVM.equals("-1") || defaultMaxVM == null) + { + txtMaxVM.setText(""); + txtMaxVM.setEnabled(false); + chkBoxUnlimitedVM.setEnabled(true); + chkBoxUnlimitedVM.setSelection(true); + } + else + { + txtMaxVM.setEnabled(true); + chkBoxUnlimitedVM.setEnabled(false); + txtMaxVM.setText(defaultMaxVM); + } + + chkStatus.setAllChecked(rffs.getAnyStatus()); + + String[] stateTypes = SystemProcessStatesContentProvider.getStates(); + for (int i = 0; i < ALL_STATES_STR.length; i++) + { + chkStatus.setChecked(stateTypes[i], rffs.getSpecificState(ALL_STATES_STR[i])); + } + } + } + /** + * This is called in the change filter dialog when the user selects "new", or selects another string. + * You must override this if you override createContents. Be sure to test if the contents have even been created yet! + */ + protected void resetFields() + { + if (txtExeName == null) + return; + txtExeName.setText("*"); + txtUserName.setText("*"); + txtGid.setText(""); + txtMinVM.setText("0"); + txtMaxVM.setText(""); + chkBoxUnlimitedVM.setSelection(true); + txtMaxVM.setEnabled(false); + chkBoxUnlimitedVM.setEnabled(true); + chkStatus.setAllChecked(false); + } + + /** + * Must be overridden if createContents is overridden. + *

+ * This is called by the isComplete, to decide if the default information + * is complete enough to enable finish. It doesn't do validation, that will be done when + * finish is pressed. + */ + protected boolean areFieldsComplete() + { + if (txtExeName == null) return false; + else return true; + } + + /** + * Completes processing of the wizard page or dialog. If this + * method returns true, the wizard/dialog will close; + * otherwise, it will stay active. + * + * @return error, if there is one + */ + public SystemMessage verify() + { + errorMessage = null; + Control controlInError = null; + calledFromVerify = true; + skipEventFiring = true; + + errorMessage = validateNameInput(txtExeName); + if (errorMessage != null) + controlInError = txtExeName; + + errorMessage = validateNameInput(txtUserName); + if (errorMessage != null) + controlInError = txtUserName; + + errorMessage = validateGidInput(); + if (errorMessage != null) + controlInError = txtGid; + + errorMessage = validateMinVMInput(); + if (errorMessage != null) + controlInError = txtMinVM; + + if (errorMessage == null) + { + if (!chkBoxUnlimitedVM.getSelection()) + { + errorMessage = validateMaxVMInput(); + if (errorMessage == null) + { + errorMessage = validateMinLessThanMax(); + } + } + if (errorMessage != null) + controlInError = txtMaxVM; + + } + if ((errorMessage == null) && (inputFilterStrings!=null) && !skipUniquenessChecking) + { + boolean notUnique = false; + String currFilterString = getFilterString(); + if (containsFilterString(currFilterString)) + notUnique = true; + if (notUnique) + { + errorMessage = SystemPlugin.getPluginMessage(FILEMSG_VALIDATE_FILEFILTERSTRING_NOTUNIQUE).makeSubstitution(currFilterString); + } + controlInError = txtExeName; + } + + if (errorMessage != null) + { + if (!dontStealFocus) + controlInError.setFocus(); + } + + calledFromVerify = false; + skipEventFiring = false; + fireChangeEvent(errorMessage); + return errorMessage; + } + + /* + * + */ + private boolean containsFilterString(String newString) + { + if (inputFilterStrings == null) + return false; + else + { + for (int idx=0; idxISystemValidator object. + * If the ISystemValidator reports an error the error message is displayed + * in the Dialog's message line. + */ + protected SystemMessage validateNameInput(Text txt) + { + if (noValidation || ignoreChanges) + return null; + + errorMessage = null; + + if (nameValidator != null) + { + errorMessage = nameValidator.validate(txt.getText().trim()); + } + + fireChangeEvent(errorMessage); + return errorMessage; + } + + /** + * This hook method is called whenever the text changes in the input field. + * The default implementation delegates the request to an ISystemValidator object. + * If the ISystemValidator reports an error the error message is displayed + * in the Dialog's message line. + */ + protected SystemMessage validateGidInput() + { + if (noValidation || ignoreChanges) + return null; + + errorMessage = null; + + if (gidValidator != null) + { + errorMessage = gidValidator.validate(txtGid.getText().trim()); + } + + fireChangeEvent(errorMessage); + return errorMessage; + } + + /** + * This hook method is called whenever the text changes in the input field. + * The default implementation delegates the request to an ISystemValidator object. + * If the ISystemValidator reports an error the error message is displayed + * in the Dialog's message line. + */ + protected SystemMessage validateMinVMInput() + { + if (noValidation || ignoreChanges) + return null; + + errorMessage = null; + + if (vmRangeValidator != null) + { + errorMessage = vmRangeValidator.validate(txtMinVM.getText().trim()); + } + + fireChangeEvent(errorMessage); + return errorMessage; + } + + /** + * This hook method is called whenever the text changes in the input field. + * The default implementation delegates the request to an ISystemValidator object. + * If the ISystemValidator reports an error the error message is displayed + * in the Dialog's message line. + */ + protected SystemMessage validateMaxVMInput() + { + if (noValidation || ignoreChanges || chkBoxUnlimitedVM.getSelection()) + return null; + + errorMessage = null; + + if (vmRangeValidator != null) + { + errorMessage = vmRangeValidator.validate(txtMaxVM.getText().trim()); + } + + fireChangeEvent(errorMessage); + return errorMessage; + } + + /** + * This hook method is called whenever the text changes in the input field. + * The default implementation delegates the request to an ISystemValidator object. + * If the ISystemValidator reports an error the error message is displayed + * in the Dialog's message line. + */ + protected SystemMessage validateMinLessThanMax() + { + long minVM = 0; + long maxVM = 0; + try + { + minVM = Long.parseLong(txtMinVM.getText()); + maxVM = Long.parseLong(txtMaxVM.getText()); + } + catch (Exception e) + { + return null; + } + if (maxVM < minVM) + { + return ProcessesPlugin.getPluginMessage("RSEPG1001"); + } + return null; + } + // ------------------------------ + // DATA EXTRACTION METHODS + // ------------------------------ + + /** + * Get the filter string in its current form. + * This should be overridden if createContents is overridden. + */ + public String getFilterString() + { + if (txtExeName == null) + return inputFilterString; + + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + + String exeName = txtExeName.getText().trim(); + if (!exeName.equals("")) rpfs.setName(exeName); + + String userName = txtUserName.getText().trim(); + if (!userName.equals("")) rpfs.setUsername(userName); + + String gid = txtGid.getText().trim(); + if (!gid.equals("")) rpfs.setGid(gid); + + String minVM = txtMinVM.getText().trim(); + if (!minVM.equals("")) rpfs.setMinVM(minVM); + + if (chkBoxUnlimitedVM.getSelection()) + { + rpfs.setMaxVM("-1"); + } + else + { + String maxVM = txtMaxVM.getText().trim(); + if (!maxVM.equals("")) rpfs.setMaxVM(maxVM); + } + + String[] stateStrings = SystemProcessStatesContentProvider.getStates(); + for (int i = 0; i < ALL_STATES_STR.length; i++) + { + if (chkStatus.getChecked(stateStrings[i])) rpfs.setSpecificState(ALL_STATES_STR[i]); + } + return rpfs.toString(); + } + + // ------------------ + // EVENT LISTENERS... + // ------------------ + + /** + * User has selected something + */ + public void widgetSelected(SelectionEvent event) + { + Object src = event.getSource(); + dontStealFocus = true; + if (src == chkBoxUnlimitedVM) + { + txtMaxVM.setEnabled(!chkBoxUnlimitedVM.getSelection()); + if (!chkBoxUnlimitedVM.getSelection()) + { + txtMaxVM.setFocus(); + if (validateMaxVMInput() == null) + { + if (!txtMinVM.getText().trim().equals("")) + { + SystemMessage message = validateMinLessThanMax(); + fireChangeEvent(message); + } + } + } + else verify(); + } + dontStealFocus = false; + } + + /** + * Called by us or by owning dialog when common Test button is pressed + */ + public void processTest(Shell shell) + { + if (refProvider == null) + { + SystemBasePlugin.logWarning("Programming Error: input subsystem is not set"); + return; + } + skipUniquenessChecking = true; + if (verify() == null) + { + SystemTestFilterStringAction testAction = new SystemTestFilterStringAction(getShell()); + testAction.setSubSystem((ISubSystem)refProvider); + testAction.setFilterString(getFilterString()); + try + { + testAction.run(); + } + catch (Exception exc) + { + + SystemMessage msg = SystemMessageDialog.getExceptionMessage(getShell(), exc); + fireChangeEvent(msg); + } + } + skipUniquenessChecking = false; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.java new file mode 100644 index 00000000000..246fb90ad5e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.java @@ -0,0 +1,90 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui; + +import org.eclipse.osgi.util.NLS; + +public class SystemProcessesResources extends NLS +{ + private static String BUNDLE_NAME = "org.eclipse.rse.processes.ui.SystemProcessesResources"; + + // ------------------------- + // ACTIONS... + // ------------------------- + public static String ACTION_NEWPROCESSFILTER_LABEL; + public static String ACTION_NEWPROCESSFILTER_TOOLTIP; + + public static String ACTION_UPDATEFILTER_LABEL; + public static String ACTION_UPDATEFILTER_TOOLTIP; + + public static String ACTION_KILLPROCESS_LABEL; + public static String ACTION_KILLPROCESS_TOOLTIP; + + // ------------------------- + // WIZARDS... + // ------------------------- + + // New System process Filter wizard... + public static String RESID_NEWPROCESSFILTER_PAGE1_TITLE; + public static String RESID_NEWPROCESSFILTER_PAGE1_DESCRIPTION; + + // Change process filter + public static String RESID_CHGPROCESSFILTER_TITLE; + + // Process Filter String Re-Usable form (used in dialog and wizard) + + public static String RESID_PROCESSFILTERSTRING_EXENAME_LABEL; + public static String RESID_PROCESSFILTERSTRING_USERNAME_LABEL; + public static String RESID_PROCESSFILTERSTRING_GID_LABEL; + public static String RESID_PROCESSFILTERSTRING_MINVM_LABEL; + public static String RESID_PROCESSFILTERSTRING_MAXVM_LABEL; + public static String RESID_PROCESSFILTERSTRING_UNLIMITED_LABEL; + public static String RESID_PROCESSFILTERSTRING_STATUS_LABEL; + + public static String RESID_PROCESSFILTERSTRING_EXENAME_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_USERNAME_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_GID_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_MINVM_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_MAXVM_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_UNLIMITED_TOOLTIP; + public static String RESID_PROCESSFILTERSTRING_STATUS_TOOLTIP; + + // Warnings + public static String RESID_KILL_WARNING_LABEL; + public static String RESID_KILL_WARNING_TOOLTIP; + + // KILL Process dialog + public static String RESID_KILL_TITLE; + public static String RESID_KILL_PROMPT; + public static String RESID_KILL_PROMPT_SINGLE; + public static String RESID_KILL_BUTTON; + public static String RESID_KILL_TIP; + public static String RESID_KILL_SIGNAL_TYPE_LABEL; + public static String RESID_KILL_SIGNAL_TYPE_TOOLTIP; + public static String RESID_KILL_SIGNAL_TYPE_DEFAULT; + public static String RESID_KILL_COLHDG_EXENAME; + public static String RESID_KILL_COLHDG_PID; + + // Remote Processes dialog + public static String RESID_REMOTE_PROCESSES_EXECUTABLE_LABEL; + public static String RESID_REMOTE_PROCESSES_EXECUTABLE_TOOLTIP; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, SystemProcessesResources.class); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.properties b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.properties new file mode 100644 index 00000000000..5c115892b34 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/SystemProcessesResources.properties @@ -0,0 +1,79 @@ +################################################################################ +# Copyright (c) 2005, 2006 IBM Corporation. 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: +# {Name} (company) - description of contribution. +################################################################################ + + +#============================================================= +# PROCESS SUBSYSTEM ACTIONS... +#============================================================= +ACTION_NEWPROCESSFILTER_LABEL=Filter... +ACTION_NEWPROCESSFILTER_TOOLTIP=Create a new process filter +ACTION_UPDATEFILTER_LABEL=Change... +ACTION_UPDATEFILTER_TOOLTIP=Change this filter's name or contents +ACTION_KILLPROCESS_LABEL=Kill... +ACTION_KILLPROCESS_TOOLTIP=Send this process a kill signal + +#============================================================= +# NEW PROCESS FILTER WIZARD... +#============================================================= +RESID_NEWPROCESSFILTER_PAGE1_TITLE=Process Filter +RESID_NEWPROCESSFILTER_PAGE1_DESCRIPTION=Create a process filter + +RESID_PROCESSFILTERSTRING_EXENAME_LABEL=Executable Name +RESID_PROCESSFILTERSTRING_USERNAME_LABEL=User Name +RESID_PROCESSFILTERSTRING_GID_LABEL=Group ID +RESID_PROCESSFILTERSTRING_MINVM_LABEL=Minimum VM Size (kB) +RESID_PROCESSFILTERSTRING_MAXVM_LABEL=Maximum VM Size (kB) +RESID_PROCESSFILTERSTRING_UNLIMITED_LABEL=Unlimited +RESID_PROCESSFILTERSTRING_STATUS_LABEL=Status + +RESID_PROCESSFILTERSTRING_EXENAME_TOOLTIP=The name of the executable owning the process +RESID_PROCESSFILTERSTRING_USERNAME_TOOLTIP=The name of the user owning the process +RESID_PROCESSFILTERSTRING_GID_TOOLTIP=The group id of the user owning the process +RESID_PROCESSFILTERSTRING_MINVM_TOOLTIP=The minimum virtual memory size used by the process +RESID_PROCESSFILTERSTRING_MAXVM_TOOLTIP=The maximum virtual memory size used by the process +RESID_PROCESSFILTERSTRING_UNLIMITED_TOOLTIP=No limit to virtual memory size +RESID_PROCESSFILTERSTRING_STATUS_TOOLTIP=The current status of the process + +#============================================================= +# CHANGE FILE FILTER DIALOG... +#============================================================= +RESID_CHGPROCESSFILTER_TITLE=Change Process Filter + +#============================================================= +# KILL PROCESS WARNING... +#============================================================= +RESID_KILL_WARNING_LABEL=WARNING! Terminating or interrupting a remote process can cause\nsystem instability and other undesirable effects! +RESID_KILL_WARNING_TOOLTIP=You are confirming that a signal will be sent to the remote process(es). This action cannot be undone + +#============================================================= +# KILL PROCESS DIALOG +#============================================================= +RESID_KILL_TITLE=Send a kill signal +RESID_KILL_PROMPT=Kill selected processes? +RESID_KILL_PROMPT_SINGLE=Kill selected process? +RESID_KILL_BUTTON=Kill +RESID_KILL_TIP=Confirm kill request +RESID_KILL_SIGNAL_TYPE_LABEL=Signal Type +RESID_KILL_SIGNAL_TYPE_TOOLTIP=The type of kill signal to send to the process +RESID_KILL_SIGNAL_TYPE_DEFAULT=default +RESID_KILL_COLHDG_EXENAME=Executable Name +RESID_KILL_COLHDG_PID=Process ID + +#============================================================= +# REMOTE PROCESSES DIALOG +#============================================================= +RESID_REMOTE_PROCESSES_EXECUTABLE_LABEL=Executable +RESID_REMOTE_PROCESSES_EXECUTABLE_TOOLTIP=Name of executable \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemKillProcessAction.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemKillProcessAction.java new file mode 100644 index 00000000000..af9ba9de7a4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemKillProcessAction.java @@ -0,0 +1,360 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.actions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.filters.ISystemFilterReference; +import org.eclipse.rse.model.ISystemRegistry; +import org.eclipse.rse.model.ISystemResourceChangeEvents; +import org.eclipse.rse.model.SystemResourceChangeEvent; +import org.eclipse.rse.processes.ui.ProcessesPlugin; +import org.eclipse.rse.processes.ui.SystemProcessesResources; +import org.eclipse.rse.processes.ui.dialogs.SystemKillDialog; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.RemoteProcessSubSystem; +import org.eclipse.rse.ui.ISystemContextMenuConstants; +import org.eclipse.rse.ui.ISystemMessages; +import org.eclipse.rse.ui.actions.SystemBaseAction; +import org.eclipse.rse.ui.actions.SystemBaseDialogAction; +import org.eclipse.rse.ui.messages.SystemMessageDialog; +import org.eclipse.swt.widgets.Shell; + + +public class SystemKillProcessAction extends SystemBaseDialogAction implements IRunnableWithProgress +{ + + protected Exception runException = null; + protected Object[] processesDeathRow; + protected boolean killedOk = true; + protected String signalType = null; + + /** + * Constructor for subclass + */ + public SystemKillProcessAction(Shell shell) + { + super(SystemProcessesResources.ACTION_KILLPROCESS_LABEL, + SystemProcessesResources.ACTION_KILLPROCESS_TOOLTIP, + ProcessesPlugin.getDefault().getImageDescriptorFromPath("/icons/full/elcl16/killprocessj.gif"), + shell); + allowOnMultipleSelection(true); + setProcessAllSelections(true); + setContextMenuGroup(ISystemContextMenuConstants.GROUP_REORGANIZE); + setHelp(ProcessesPlugin.HELPPREFIX+"actn0001"); + setDialogHelp(ProcessesPlugin.HELPPREFIX+"dkrp0000"); + } + + /** + * We override from parent to do unique checking... + *

+ * We simply ensure every selected object is an IRemoteProcess + *

+ * @see SystemBaseAction#updateSelection(IStructuredSelection) + */ + public boolean updateSelection(IStructuredSelection selection) + { + boolean enable = true; + Iterator e= ((IStructuredSelection) selection).iterator(); + while (enable && e.hasNext()) + { + Object selectedObject = e.next(); + if (!(selectedObject instanceof IRemoteProcess)) + enable = false; + } + return enable; + } + + /** + * Required by parent. + * It is up to the caller to call wasCancelled() and if not true, do their own killing. + */ + protected Object getDialogValue(Dialog dlg) + { + SystemKillDialog killDlg = (SystemKillDialog)dlg; + if (!killDlg.wasCancelled()) + signalType = killDlg.getSignal(); + if (signalType.equals(SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_DEFAULT)) + signalType = ISystemProcessRemoteConstants.PROCESS_SIGNAL_TYPE_DEFAULT; + if (signalType != null) + { + IRunnableContext runnableContext = getRunnableContext(); + try + { + runnableContext.run(false,false,this); // inthread, cancellable, IRunnableWithProgress + } + catch (java.lang.reflect.InvocationTargetException exc) // unexpected error + { + showOperationMessage((Exception)exc.getTargetException(), getShell()); + } + catch (Exception exc) + { + showOperationMessage(exc, getShell()); + } + } + return null; + } + + + /** + * If you decide to use the supplied run method as is, + * then you must override this method to create and return + * the dialog that is displayed by the default run method + * implementation. + *

+ * If you override run with your own, then + * simply implement this to return null as it won't be used. + * @see #run() + */ + protected Dialog createDialog(Shell shell) + { + SystemKillDialog dlg = new SystemKillDialog(shell); + return dlg; + } + + /** + * Get an IRunnable context to show progress in. If there is currently a dialog or wizard up with + * a progress monitor in it, we will use this, else we will create a progress monitor dialog. + */ + protected IRunnableContext getRunnableContext() + { + ISystemRegistry sr = SystemPlugin.getTheSystemRegistry(); + IRunnableContext irc = sr.getRunnableContext(); + if (irc == null) + irc = new ProgressMonitorDialog(getShell()); + return irc; + } + + // ---------------------------------- + // INTERNAL METHODS... + // ---------------------------------- + /** + * Method required by IRunnableWithProgress interface. + * Allows execution of a long-running operation modally by via a thread. + * In our case, it runs the kill operation with a visible progress monitor + */ + public void run(IProgressMonitor monitor) + throws java.lang.reflect.InvocationTargetException, + java.lang.InterruptedException + { + SystemMessage msg = getKillingMessage(); + runException = null; + populateSelectedObjects(); + + try + { + int steps = processesDeathRow.length; + monitor.beginTask(msg.getLevelOneText(), steps); + killedOk = true; + IRemoteProcess currentProcess = null; + for (int idx=0; killedOk && (idx + * Overridable extension. For those cases when you don't want to create your + * own wizard subclass, but prefer to simply configure the default wizard. + *

+ * Note, at the point this is called, all the base configuration, based on the + * setters for this action, have been called. + *

+ * We do it here versus via setters as it defers some work until the user actually + * selects this action. + */ + protected void configureNewFilterWizard(SystemNewFilterWizard wizard) + { + // configuration that used to only be possible via subclasses... + wizard.setWizardPageTitle(SystemProcessesResources.RESID_NEWPROCESSFILTER_PAGE1_TITLE); + wizard.setWizardImage(SystemPlugin.getDefault().getImageDescriptor(ICON_SYSTEM_NEWFILTERWIZARD_ID)); + wizard.setPage1Description(SystemProcessesResources.RESID_NEWPROCESSFILTER_PAGE1_DESCRIPTION); + wizard.setFilterStringEditPane(new SystemProcessFilterStringEditPane(wizard.getShell())); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemProcessUpdateFilterAction.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemProcessUpdateFilterAction.java new file mode 100644 index 00000000000..2b614723ca6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/actions/SystemProcessUpdateFilterAction.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.actions; + +import org.eclipse.rse.processes.ui.SystemProcessFilterStringEditPane; +import org.eclipse.rse.processes.ui.SystemProcessesResources; +import org.eclipse.rse.ui.filters.actions.SystemChangeFilterAction; +import org.eclipse.rse.ui.filters.dialogs.SystemChangeFilterDialog; +import org.eclipse.swt.widgets.Shell; + + +public class SystemProcessUpdateFilterAction extends SystemChangeFilterAction +{ + + /** + * Constructor + */ + public SystemProcessUpdateFilterAction(Shell parent) + { + super(parent, SystemProcessesResources.ACTION_UPDATEFILTER_LABEL, SystemProcessesResources.ACTION_UPDATEFILTER_TOOLTIP); + setDialogTitle(SystemProcessesResources.RESID_CHGPROCESSFILTER_TITLE); + } + /** + * Overridable extension point to configure the filter dialog. Typically you don't need + * to subclass our default dialog. + */ + protected void configureFilterDialog(SystemChangeFilterDialog dlg) + { + // it is cheaper to do this here, as it defers instantiation of the edit pane until the + // user actually runs the action! + Shell shell = dlg.getShell(); + if (shell == null) + shell = dlg.getParentShell(); + + dlg.setFilterStringEditPane(new SystemProcessFilterStringEditPane(shell)); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/RemoteProcessesDialog.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/RemoteProcessesDialog.java new file mode 100644 index 00000000000..d0f04433abe --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/RemoteProcessesDialog.java @@ -0,0 +1,174 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.dialogs; + +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.filters.ISystemFilterReference; +import org.eclipse.rse.processes.ui.SystemProcessesResources; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.subsystems.processes.core.subsystem.RemoteProcessSubSystem; +import org.eclipse.rse.ui.SystemWidgetHelpers; +import org.eclipse.rse.ui.dialogs.SystemPromptDialog; +import org.eclipse.rse.ui.view.SystemTableView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; + + +/** + * + * @author dmcknigh + * + */ +public class RemoteProcessesDialog extends SystemPromptDialog implements KeyListener +{ + private Text _nameFilterText; + private SystemTableView _viewer; + private RemoteProcessSubSystem _subSystem; + private String _executableFilter; + private Table _table; + private IHostProcess _selected; + + public RemoteProcessesDialog(Shell shell, String title, RemoteProcessSubSystem subSystem, String executableFilter) + { + super(shell, title); + _subSystem = subSystem; + _executableFilter = executableFilter; + } + + protected Control createInner(Composite parent) + { + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + parent.setLayout(gridLayout); + + _nameFilterText = SystemWidgetHelpers.createLabeledTextField(parent, this, SystemProcessesResources.RESID_REMOTE_PROCESSES_EXECUTABLE_LABEL, SystemProcessesResources.RESID_REMOTE_PROCESSES_EXECUTABLE_TOOLTIP); + _nameFilterText.addKeyListener(this); + + // create table portion + _table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.HIDE_SELECTION); + _viewer = new SystemTableView(_table,this); + + + _viewer.addDoubleClickListener(new IDoubleClickListener() + { + public void doubleClick(DoubleClickEvent event) + { + //handleDoubleClick(event); + } + }); + + + SystemWidgetHelpers.setHelp(_viewer.getControl(), SystemPlugin.HELPPREFIX + "ucmd0000"); + + TableLayout layout = new TableLayout(); + _table.setLayout(layout); + _table.setHeaderVisible(false); + _table.setLinesVisible(false); + + GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL); + gridData.heightHint = 200; + gridData.widthHint = 400; + _table.setLayoutData(gridData); + init(); + return _table; + } + + protected Control getInitialFocusControl() + { + // TODO Auto-generated method stub + return _viewer.getControl(); + } + + + public void doubleClick(DoubleClickEvent event) + { + IStructuredSelection s = (IStructuredSelection) event.getSelection(); + Object element = s.getFirstElement(); + if (element == null) + return; + processOK(); + close(); + } + + + protected boolean processOK() + { + StructuredSelection sel = (StructuredSelection)_viewer.getSelection(); + IRemoteProcess proc = (IRemoteProcess)sel.getFirstElement(); + if (proc != null) + { + _selected = proc; + } + return true; + } + + public IHostProcess getSelected() + { + return _selected; + } + + protected void init() + { + _nameFilterText.setText(_executableFilter); + Object[] filters = _subSystem.getChildren(); + + ISystemFilterReference ref = (ISystemFilterReference)filters[0]; + ref.markStale(true); + updateViewFilter(); + _viewer.setInput(ref); + } + + protected void updateViewFilter() + { + if (_executableFilter.indexOf("*") == -1) + _executableFilter += "*"; + String[] viewFilters = {_executableFilter}; + _viewer.setViewFilters(viewFilters); + } + + public void keyPressed(KeyEvent e) + { + } + + public void keyReleased(KeyEvent e) + { + if (e.widget == _nameFilterText) + { + if (!_nameFilterText.getText().equals(_executableFilter)) + { + _executableFilter = _nameFilterText.getText(); + updateViewFilter(); + } + } + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillDialog.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillDialog.java new file mode 100644 index 00000000000..2c3259c7c2c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillDialog.java @@ -0,0 +1,331 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.dialogs; + +import org.eclipse.jface.viewers.ColumnLayoutData; +import org.eclipse.jface.viewers.ColumnPixelData; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.rse.core.SystemAdapterHelpers; +import org.eclipse.rse.core.SystemBasePlugin; +import org.eclipse.rse.processes.ui.ProcessesPlugin; +import org.eclipse.rse.processes.ui.SystemProcessesResources; +import org.eclipse.rse.processes.ui.view.ISystemProcessPropertyConstants; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.ui.SystemWidgetHelpers; +import org.eclipse.rse.ui.dialogs.SystemPromptDialog; +import org.eclipse.rse.ui.messages.ISystemMessageLine; +import org.eclipse.rse.ui.view.ISystemPropertyConstants; +import org.eclipse.rse.ui.view.ISystemViewElementAdapter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + + +/** + * Dialog for confirming killing of a process or group of processes. User + * selects the type of signal to be sent to the process. + */ +public class SystemKillDialog extends SystemPromptDialog +{ + private String warningMessage = SystemProcessesResources.RESID_KILL_WARNING_LABEL; + private String warningTip = SystemProcessesResources.RESID_KILL_WARNING_TOOLTIP; + private String promptLabel; + private SystemKillTableProvider sktp; + private Label prompt; + private Table table; + private TableViewer tableViewer; + private GridData tableData; + private Combo cmbSignal; + private String signalType; + + // column headers + private String columnHeaders[] = { + "", + SystemProcessesResources.RESID_KILL_COLHDG_EXENAME, + SystemProcessesResources.RESID_KILL_COLHDG_PID + }; + + // column layout + private ColumnLayoutData columnLayouts[] = + { + new ColumnPixelData(19, false), + new ColumnWeightData(150,150,true), + new ColumnWeightData(120,120,true) + }; + + // give each column a property value to identify it + private static String[] tableColumnProperties = + { + ISystemPropertyConstants.P_OK, + ISystemProcessPropertyConstants.P_PROCESS_NAME, + ISystemProcessPropertyConstants.P_PROCESS_PID, + }; + + /** + * Constructor for SystemKillDialog + */ + public SystemKillDialog(Shell shell) + { + super(shell, SystemProcessesResources.RESID_KILL_TITLE); + super.setOkButtonLabel(SystemProcessesResources.RESID_KILL_BUTTON); + setHelp(ProcessesPlugin.HELPPREFIX+"dkrp0000"); + } + + /** + * Create message line. Intercept so we can set msg line of form. + */ + protected ISystemMessageLine createMessageLine(Composite c) + { + super.createMessageLine(c); + return fMessageLine; + } + + /** + * @see SystemPromptDialog#getInitialFocusControl() + */ + protected Control getInitialFocusControl() + { + return tableViewer.getControl(); + } + + /** + * @see SystemPromptDialog#createInner(Composite) + */ + protected Control createInner(Composite parent) + { + // Inner composite + int nbrColumns = 2; + Composite composite = SystemWidgetHelpers.createComposite(parent, nbrColumns); + + // PROMPT + if (promptLabel == null) { + Object input = getInputObject(); + + if (input != null && input instanceof IStructuredSelection) { + int size = ((IStructuredSelection)input).size(); + + if (size > 1) { + prompt = SystemWidgetHelpers.createLabel(composite, SystemProcessesResources.RESID_KILL_PROMPT, nbrColumns); + } + else { + prompt = SystemWidgetHelpers.createLabel(composite, SystemProcessesResources.RESID_KILL_PROMPT_SINGLE, nbrColumns); + } + } + // should never get here + else { + prompt = SystemWidgetHelpers.createLabel(composite, SystemProcessesResources.RESID_KILL_PROMPT, nbrColumns); + } + } + else { + prompt = (Label)SystemWidgetHelpers.createVerbage(composite, promptLabel, nbrColumns, false, 200); + } + + // WARNING + if (warningMessage != null) + { + // filler line + SystemWidgetHelpers.createLabel(composite, "", nbrColumns); + // create image + Image image = getShell().getDisplay().getSystemImage(SWT.ICON_WARNING); + Label imageLabel = null; + if (image != null) + { + imageLabel = new Label(composite, 0); + image.setBackground(imageLabel.getBackground()); + imageLabel.setImage(image); + imageLabel.setLayoutData(new GridData( + GridData.HORIZONTAL_ALIGN_CENTER | + GridData.VERTICAL_ALIGN_BEGINNING)); + } + Label warningLabel = SystemWidgetHelpers.createLabel(composite, warningMessage); + if (warningTip != null) + { + warningLabel.setToolTipText(warningTip); + imageLabel.setToolTipText(warningTip); + } + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + data.widthHint = 350; + data.grabExcessVerticalSpace = true; + warningLabel.setLayoutData(data); + + // filler line + SystemWidgetHelpers.createLabel(composite, "", nbrColumns); + } + + // TABLE + tableViewer = createTableViewer(composite, nbrColumns); + createColumns(); + tableViewer.setColumnProperties(tableColumnProperties); + + sktp = new SystemKillTableProvider(); + + int width = tableData.widthHint; + int nbrRows = Math.min(getRows().length,8); + int rowHeight = table.getItemHeight() + table.getGridLineWidth(); + int sbHeight = table.getHorizontalBar().getSize().y; + int height = (nbrRows * rowHeight) + sbHeight; + + tableData.heightHint = height; + table.setLayoutData(tableData); + table.setSize(width, height); + + tableViewer.setLabelProvider(sktp); + tableViewer.setContentProvider(sktp); + + Object input = getInputObject(); + tableViewer.setInput(input); + + // Signal Type combo box + cmbSignal = SystemWidgetHelpers.createLabeledReadonlyCombo(composite, null, SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_LABEL, SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_TOOLTIP); + cmbSignal.addModifyListener( + new ModifyListener() { + public void modifyText(ModifyEvent e) { + selectionChanged(); + } + } + ); + cmbSignal.setItems(getSignalTypes()); + cmbSignal.add(SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_DEFAULT, 0); + cmbSignal.setText(cmbSignal.getItem(0)); + signalType = cmbSignal.getText(); + cmbSignal.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + + return composite; + } + + /** + * @return all the possible signal types that can be sent to the selected processes + * on that system + */ + private String[] getSignalTypes() + { + Object selObj = getInputObject(); + if (selObj instanceof IStructuredSelection) + { + IStructuredSelection selection = (IStructuredSelection) selObj; + IRemoteProcess process = (IRemoteProcess) selection.getFirstElement(); + String[] types = null; + try + { + types = process.getParentRemoteProcessSubSystem().getSignalTypes(); + } + catch (SystemMessageException e) + { + SystemBasePlugin.logMessage(e.getSystemMessage(), e); + return new String[] { SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_DEFAULT }; + } + if (types == null) types = new String[] { SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_DEFAULT }; + return types; + } + else return new String[] { SystemProcessesResources.RESID_KILL_SIGNAL_TYPE_DEFAULT }; + } + + private TableViewer createTableViewer(Composite parent, int nbrColumns) + { + table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.HIDE_SELECTION); + table.setLinesVisible(true); + tableViewer = new TableViewer(table); + tableData = new GridData(); + tableData.horizontalAlignment = GridData.BEGINNING; + tableData.grabExcessHorizontalSpace = false; + tableData.widthHint = 350; + tableData.heightHint = 30; + tableData.verticalAlignment = GridData.CENTER; + tableData.grabExcessVerticalSpace = true; + tableData.horizontalSpan = nbrColumns; + table.setLayoutData(tableData); + return tableViewer; + } + + private void createColumns() + { + TableLayout layout = new TableLayout(); + table.setLayout(layout); + table.setHeaderVisible(true); + for (int i = 0; i < columnHeaders.length; i++) + { + layout.addColumnData(columnLayouts[i]); + TableColumn tc = new TableColumn(table, SWT.NONE,i); + tc.setResizable(columnLayouts[i].resizable); + tc.setText(columnHeaders[i]); + } + } + + public void selectionChanged() + { + signalType = cmbSignal.getText(); + } + + /** + * Override of parent. Must pass selected object onto the form for initializing fields. + * Called by SystemDialogAction's default run() method after dialog instantiated. + */ + public void setInputObject(Object inputObject) + { + super.setInputObject(inputObject); + } + + /** + * Called when user presses OK button. + * Return true to close dialog. + * Return false to not close dialog. + */ + protected boolean processOK() + { + return true; + } + + /** + * Returns the rows of deletable items. + */ + public SystemKillTableRow[] getRows() + { + return (SystemKillTableRow[])sktp.getElements(getInputObject()); + } + + /** + * Returns the implementation of ISystemViewElement for the given + * object. Returns null if the adapter is not defined or the + * object is not adaptable. + */ + protected ISystemViewElementAdapter getAdapter(Object o) + { + return SystemAdapterHelpers.getAdapter(o); + } + + public String getSignal() + { + if (cmbSignal == null) return ""; + if (cmbSignal.isDisposed()) return signalType; + String signal = cmbSignal.getText(); + if (signal == null) return ""; + return signal; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableProvider.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableProvider.java new file mode 100644 index 00000000000..01c71d7ffe3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableProvider.java @@ -0,0 +1,79 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.dialogs; + +import java.util.Iterator; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.rse.ui.dialogs.SystemDeleteTableProvider; + + +public class SystemKillTableProvider extends SystemDeleteTableProvider +{ + + static final int COLUMN_IMAGE = 0; + static final int COLUMN_NAME = 1; + static final int COLUMN_TYPE = 2; + + /** + * Return rows. Input must be an IStructuredSelection. + */ + public Object[] getElements(Object inputElement) + { + if (children == null) + { + IStructuredSelection iss = (IStructuredSelection)inputElement; + children = new SystemKillTableRow[iss.size()]; + Iterator i = iss.iterator(); + int idx = 0; + while (i.hasNext()) + { + children[idx] = new SystemKillTableRow(i.next(), idx); + idx++; + } + } + return children; + } + + /** + * Return the 0-based row number of the given element. + */ + public int getRowNumber(SystemKillTableRow row) + { + return row.getRowNumber(); + } + + /** + * @see ITableLabelProvider#getColumnText(java.lang.Object, int) + */ + public String getColumnText(Object element, int column) + { + String text = ""; + if (column == COLUMN_NAME) + text = getTableRow(element).getName(); + else if (column == COLUMN_TYPE) + text = getTableRow(element).getType(); + //System.out.println("INSIDE GETCOLUMNTEXT: " + column + ", " + text + ", " + getTableRow(element)); + return text; + } + + private SystemKillTableRow getTableRow(Object element) + { + return (SystemKillTableRow)element; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableRow.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableRow.java new file mode 100644 index 00000000000..eb611237058 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/dialogs/SystemKillTableRow.java @@ -0,0 +1,150 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.dialogs; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.rse.core.SystemAdapterHelpers; +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.ui.ISystemIconConstants; +import org.eclipse.rse.ui.dialogs.SystemDeleteTableRow; +import org.eclipse.rse.ui.dialogs.SystemSimpleContentElement; +import org.eclipse.rse.ui.view.ISystemRemoteElementAdapter; +import org.eclipse.rse.ui.view.ISystemViewElementAdapter; + + +public class SystemKillTableRow extends SystemDeleteTableRow +{ + + private Object element; + private String exename; + private String pid; + private ImageDescriptor imageDescriptor; + private ISystemViewElementAdapter adapter; + private ISystemRemoteElementAdapter remoteAdapter; + private int rowNbr = 0; + + public SystemKillTableRow(Object element, int rowNbr) + { + super(element, rowNbr); + if (element instanceof SystemSimpleContentElement) + element = ((SystemSimpleContentElement)element).getData(); + this.element = element; + this.adapter = getAdapter(element); + this.remoteAdapter = getRemoteAdapter(element); + this.rowNbr = rowNbr; + if (adapter != null) + this.exename = adapter.getName(element); + else + { + if (element instanceof IRemoteProcess) + this.exename = ((IRemoteProcess)element).getName(); + } + if (element instanceof IRemoteProcess) + this.pid = "" + ((IRemoteProcess)element).getPid(); + if (adapter != null) + this.imageDescriptor = adapter.getImageDescriptor(element); + else this.imageDescriptor = SystemPlugin.getDefault().getImageDescriptor(ISystemIconConstants.ICON_SYSTEM_PROCESS_ID); + } + + /** + * Return the name of the item to be deleted + * @return display name of the item. + */ + public String getName() + { + return exename; + } + /** + * Return the resource type of the item to be deleted + * @return resource type of the item + */ + public String getType() + { + return pid; + } + /** + * Return the 0-based row number of this item + * @return 0-based row number + */ + public int getRowNumber() + { + return rowNbr; + } + + /** + * Returns an image descriptor for the image. More efficient than getting the image. + */ + public ImageDescriptor getImageDescriptor() + { + return imageDescriptor; + } + + /** + * Get the input object this row represents + */ + public Object getElement() + { + return element; + } + /** + * Get the input object adapter for the input object this row represents + */ + public ISystemViewElementAdapter getAdapter() + { + return adapter; + } + /** + * Get the input object remote adapter for the input object this row represents + */ + public ISystemRemoteElementAdapter getRemoteAdapter() + { + return remoteAdapter; + } + /** + * Return true if this is a remote object + */ + public boolean isRemote() + { + return (remoteAdapter != null); + } + + /** + * Returns the implementation of ISystemViewElement for the given + * object. Returns null if the adapter is not defined or the + * object is not adaptable. + */ + protected ISystemViewElementAdapter getAdapter(Object o) + { + return SystemAdapterHelpers.getAdapter(o); + } + + /** + * Returns the implementation of ISystemRemoteElement for the given + * object. Returns null if this object does not adaptable to this. + */ + protected ISystemRemoteElementAdapter getRemoteAdapter(Object o) + { + return SystemAdapterHelpers.getRemoteAdapter(o); + } + + public String toString() + { + return exename; + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/propertypages/ProcessServicesPropertyPage.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/propertypages/ProcessServicesPropertyPage.java new file mode 100644 index 00000000000..6c834f8b1e3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/propertypages/ProcessServicesPropertyPage.java @@ -0,0 +1,93 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.propertypages; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.core.servicesubsystem.IServiceSubSystemConfiguration; +import org.eclipse.rse.core.subsystems.ISubSystemConfiguration; +import org.eclipse.rse.model.IHost; +import org.eclipse.rse.model.ISystemRegistry; +import org.eclipse.rse.subsystems.processes.servicesubsystem.IProcessServiceSubSystemConfiguration; +import org.eclipse.rse.subsystems.processes.servicesubsystem.ProcessServiceSubSystem; +import org.eclipse.rse.ui.propertypages.ServicesPropertyPage; +import org.eclipse.rse.ui.widgets.services.FactoryServiceElement; +import org.eclipse.rse.ui.widgets.services.ServiceElement; + + +public class ProcessServicesPropertyPage extends ServicesPropertyPage +{ + private IProcessServiceSubSystemConfiguration _currentFactory; + protected ProcessServiceSubSystem getProcessServiceSubSystem() + { + return (ProcessServiceSubSystem)getElement(); + } + + protected ServiceElement[] getServiceElements() + { + ProcessServiceSubSystem subSystem = getProcessServiceSubSystem(); + + IHost host = subSystem.getHost(); + _currentFactory = (IProcessServiceSubSystemConfiguration)subSystem.getParentRemoteProcessSubSystemFactory(); + IProcessServiceSubSystemConfiguration[] factories = getProcessServiceSubSystemFactories(host.getSystemType()); + + + // create elements for each + ServiceElement[] elements = new ServiceElement[factories.length]; + for (int i = 0; i < factories.length; i++) + { + IProcessServiceSubSystemConfiguration factory = factories[i]; + elements[i] = new FactoryServiceElement(host, factory); + if (factory == _currentFactory) + { + elements[i].setSelected(true); + } + } + + return elements; + } + + protected IProcessServiceSubSystemConfiguration[] getProcessServiceSubSystemFactories(String systemType) + { + List results = new ArrayList(); + ISystemRegistry sr = SystemPlugin.getTheSystemRegistry(); + ISubSystemConfiguration[] factories = sr.getSubSystemConfigurationsBySystemType(systemType); + + for (int i = 0; i < factories.length; i++) + { + ISubSystemConfiguration factory = factories[i]; + if (factory instanceof IProcessServiceSubSystemConfiguration) + { + results.add(factory); + } + } + + return (IProcessServiceSubSystemConfiguration[])results.toArray(new IProcessServiceSubSystemConfiguration[results.size()]); + } + + protected IServiceSubSystemConfiguration getCurrentServiceSubSystemFactory() + { + return _currentFactory; + } + + public void setSubSystemFactory(ISubSystemConfiguration factory) + { + _currentFactory = (IProcessServiceSubSystemConfiguration)factory; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/ISystemProcessPropertyConstants.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/ISystemProcessPropertyConstants.java new file mode 100644 index 00000000000..9ffd7119390 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/ISystemProcessPropertyConstants.java @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +public interface ISystemProcessPropertyConstants +{ + public static final String P_PREFIX = org.eclipse.rse.ui.ISystemIconConstants.PREFIX; + + // PROCESS PROPERTIES + public static String P_PROCESS_PID = P_PREFIX+"process.pid"; + public static String P_PROCESS_NAME = P_PREFIX+"process.name"; + public static String P_PROCESS_UID = P_PREFIX+"process.uid"; + public static String P_PROCESS_USERNAME = P_PREFIX+"process.username"; + public static String P_PROCESS_PPID = P_PREFIX+"process.ppid"; + public static String P_PROCESS_GID = P_PREFIX+"process.gid"; + public static String P_PROCESS_STATE = P_PREFIX+"process.state"; + public static String P_PROCESS_TGID = P_PREFIX+"process.tgid"; + public static String P_PROCESS_TRACERPID = P_PREFIX+"process.tracerpid"; + public static String P_PROCESS_VMSIZE = P_PREFIX+"process.vmsize"; + public static String P_PROCESS_VMRSS = P_PREFIX+"process.vmrss"; + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubSystemFactoryAdapter.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubSystemFactoryAdapter.java new file mode 100644 index 00000000000..c46e026ed95 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubSystemFactoryAdapter.java @@ -0,0 +1,68 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +import java.util.Vector; + +import org.eclipse.jface.action.IAction; +import org.eclipse.rse.core.subsystems.ISubSystemConfiguration; +import org.eclipse.rse.filters.ISystemFilter; +import org.eclipse.rse.filters.ISystemFilterPool; +import org.eclipse.rse.processes.ui.actions.SystemNewProcessFilterAction; +import org.eclipse.rse.processes.ui.actions.SystemProcessUpdateFilterAction; +import org.eclipse.rse.ui.view.SubsystemFactoryAdapter; +import org.eclipse.swt.widgets.Shell; + + +public class RemoteProcessSubSystemFactoryAdapter extends SubsystemFactoryAdapter +{ + + SystemNewProcessFilterAction _newProcessFilterAction; + SystemProcessUpdateFilterAction _changeProcessFilterAction; + + Vector _additionalActions; + + /** + * Overridable parent method to return the action for creating a new filter. + * Returns new SystemNewFileFilterAction. + */ + protected IAction getNewFilterPoolFilterAction(ISubSystemConfiguration factory, ISystemFilterPool selectedPool, Shell shell) + { + if (_newProcessFilterAction == null) + { + _newProcessFilterAction = new SystemNewProcessFilterAction(shell, selectedPool); + } + return _newProcessFilterAction; + } + + + /** + * Overridable method to return the action for changing an existing filter. + * Returns new SystemProcessUpdateFilterAction. + */ + protected IAction getChangeFilterAction(ISubSystemConfiguration factory, ISystemFilter selectedFilter, Shell shell) + { + if (_changeProcessFilterAction == null) + { + _changeProcessFilterAction = new SystemProcessUpdateFilterAction(shell); + } + return _changeProcessFilterAction; + } + + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubsystemFactoryAdapterFactory.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubsystemFactoryAdapterFactory.java new file mode 100644 index 00000000000..41dd39d0b59 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/RemoteProcessSubsystemFactoryAdapterFactory.java @@ -0,0 +1,59 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.rse.core.subsystems.util.ISubsystemConfigurationAdapter; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessSubSystemConfiguration; + + +public class RemoteProcessSubsystemFactoryAdapterFactory implements IAdapterFactory +{ + + private ISubsystemConfigurationAdapter ssFactoryAdapter = new RemoteProcessSubSystemFactoryAdapter(); + + /** + * @see IAdapterFactory#getAdapterList() + */ + public Class[] getAdapterList() + { + return new Class[] {ISubsystemConfigurationAdapter.class}; + } + /** + * Called by our plugin's startup method to register our adaptable object types + * with the platform. We prefer to do it here to isolate/encapsulate all factory + * logic in this one place. + */ + public void registerWithManager(IAdapterManager manager) + { + manager.registerAdapters(this, IRemoteProcessSubSystemConfiguration.class); + } + /** + * @see IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class) + */ + public Object getAdapter(Object adaptableObject, Class adapterType) + { + Object adapter = null; + if (adaptableObject instanceof IRemoteProcessSubSystemConfiguration) + adapter = ssFactoryAdapter; + + return adapter; + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessStatesContentProvider.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessStatesContentProvider.java new file mode 100644 index 00000000000..1197ecdcc69 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessStatesContentProvider.java @@ -0,0 +1,135 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +import java.util.HashMap; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; + + +/** + * Content provider for any widget that wishes to get the names of all possible + * states of a process. Also contains a utility methods for getting the translated + * information about individual process states. + * @author mjberger + * + */ +public class SystemProcessStatesContentProvider implements ISystemProcessRemoteConstants, IStructuredContentProvider +{ + private HashMap strIndices; + + /** + * Constructor + */ + public SystemProcessStatesContentProvider() + { + strIndices = new HashMap(); + // construct a mapping from unique state names to integers. Each integer + // is the index of the associated state name in the array of translated + // state name strings. + for (int i = 0; i < ALL_STATES_STR.length; i++) + { + strIndices.put(ALL_STATES_STR[i], new Integer(i)); + } + } + + /** + * @return a String array containing the translated names of all the process states. + */ + public static String[] getStates() + { + return new String[] + { + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ACTIVE_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_IDLE_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_NONEXISTENT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_PAGING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_RUNNING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_SLEEPING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_TRACED_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_WAITING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOMBIE_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_SINGLE_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQRECEIVEWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQSENDWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_COMSYSKERNELWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_SEMAPHOREWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_QUIESCEFROZEN_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_FILESYSKERNELWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSPAUSEWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATEDTASKS_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_SWAPPEDOUT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATED_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_OTHERKERNELWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_CANCELLED_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MULTITHREAD_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MEDIUMWEIGHTTHREAD_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_ASYNCHRONOUSTHREAD_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_PTRACEKERNELWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_RUNNING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_SLEEPING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_STOPPED_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_INITIALPROCESSTHREAD_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_DETACHED_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_WAITINGFORCHILD_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_FORKING_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSWAIT_VALUE, + SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ZOS_ZOMBIE_VALUE + }; + + } + + /** + * Given the unique name/code representing a process state, returns + * the translated string for the process state. + * @param state the unique name/code for a process state. + * @return the associated translated name, or "" if a matching one cannot be found + */ + public String getStateString(String state) + { + Integer index = (Integer) strIndices.get(state); + if (index == null) return ""; + String[] resources = getStates(); + if (index.intValue() >= resources.length) return ""; + return resources[index.intValue()]; + } + + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) + */ + public Object[] getElements(Object inputElement) + { + return getStates(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() + { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.java new file mode 100644 index 00000000000..f676856abf6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.java @@ -0,0 +1,103 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +import org.eclipse.osgi.util.NLS; + + +public class SystemProcessesViewResources extends NLS +{ + private static String BUNDLE_NAME = "org.eclipse.rse.processes.ui.view.SystemProcessesViewResources"; + + // PROCESS PROPERTIES + public static String RESID_PROPERTY_PROCESS_PID_LABEL; + public static String RESID_PROPERTY_PROCESS_NAME_LABEL; + public static String RESID_PROPERTY_PROCESS_UID_LABEL; + public static String RESID_PROPERTY_PROCESS_USERNAME_LABEL; + public static String RESID_PROPERTY_PROCESS_PPID_LABEL; + public static String RESID_PROPERTY_PROCESS_GID_LABEL; + public static String RESID_PROPERTY_PROCESS_STATE_LABEL; + public static String RESID_PROPERTY_PROCESS_TGID_LABEL; + public static String RESID_PROPERTY_PROCESS_TRACERPID_LABEL; + public static String RESID_PROPERTY_PROCESS_VMSIZE_LABEL; + public static String RESID_PROPERTY_PROCESS_VMRSS_LABEL; + + public static String RESID_PROPERTY_PROCESS_PID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_NAME_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_UID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_USERNAME_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_PPID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_GID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_STATE_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_TGID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_TRACERPID_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_VMSIZE_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_VMSIZE_VALUE; + public static String RESID_PROPERTY_PROCESS_VMRSS_TOOLTIP; + public static String RESID_PROPERTY_PROCESS_VMRSS_VALUE; + + public static String RESID_PROPERTY_PROCESS_DEFAULTFILTER_LABEL; + public static String RESID_PROPERTY_PROCESS_MYPROCESSESFILTER_LABEL; + + // Property sheet values: Processes + public static String RESID_PROPERTY_PROCESS_TYPE; + public static String RESID_PROPERTY_PROCESS_TYPE_ROOT; + public static String RESID_PROPERTY_PROCESS_TYPE_ERROR_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_RUNNING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_SLEEPING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_WAITING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOMBIE_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_TRACED_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_PAGING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ACTIVE_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_IDLE_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_NONEXISTENT_VALUE; + + // zOS states + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_SINGLE_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQRECEIVEWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQSENDWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_COMSYSKERNELWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_SEMAPHOREWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_QUIESCEFROZEN_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_FILESYSKERNELWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSPAUSEWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATEDTASKS_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_SWAPPEDOUT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATED_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_OTHERKERNELWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_CANCELLED_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MULTITHREAD_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MEDIUMWEIGHTTHREAD_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_ASYNCHRONOUSTHREAD_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_PTRACEKERNELWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_RUNNING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_SLEEPING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_STOPPED_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_INITIALPROCESSTHREAD_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_DETACHED_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_WAITINGFORCHILD_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_FORKING_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSWAIT_VALUE; + public static String RESID_PROPERTY_PROCESS_TYPE_ZOS_ZOMBIE_VALUE; + + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, SystemProcessesViewResources.class); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.properties b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.properties new file mode 100644 index 00000000000..19d9b1abce2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemProcessesViewResources.properties @@ -0,0 +1,84 @@ +################################################################################ +# Copyright (c) 2005, 2006 IBM Corporation. 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: +# {Name} (company) - description of contribution. +################################################################################ + + +#============================================================= +# PROCESS PROPERTIES +#============================================================= +RESID_PROPERTY_PROCESS_TYPE=Process +RESID_PROPERTY_PROCESS_TYPE_ROOT=Init (Root Process) +RESID_PROPERTY_PROCESS_TYPE_ERROR_VALUE=Error +RESID_PROPERTY_PROCESS_TYPE_RUNNING_VALUE=Running +RESID_PROPERTY_PROCESS_TYPE_SLEEPING_VALUE=Sleeping (Interruptible) +RESID_PROPERTY_PROCESS_TYPE_WAITING_VALUE=Waiting (Disk Sleep) +RESID_PROPERTY_PROCESS_TYPE_ZOMBIE_VALUE=Zombie +RESID_PROPERTY_PROCESS_TYPE_TRACED_VALUE=Traced (Stopped) +RESID_PROPERTY_PROCESS_TYPE_PAGING_VALUE=Paging +RESID_PROPERTY_PROCESS_TYPE_ACTIVE_VALUE=Active (AIX only) +RESID_PROPERTY_PROCESS_TYPE_IDLE_VALUE=Idle (AIX only) +RESID_PROPERTY_PROCESS_TYPE_NONEXISTENT_VALUE=Non-existent (AIX only) + +RESID_PROPERTY_PROCESS_TYPE_ZOS_SINGLE_VALUE=Single task (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQRECEIVEWAIT_VALUE=Message queue receive wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MSGQSENDWAIT_VALUE=Message queue send wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_COMSYSKERNELWAIT_VALUE=Communication system kernel wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_SEMAPHOREWAIT_VALUE=Semaphore operation wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_QUIESCEFROZEN_VALUE=Quiesce frozen (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_FILESYSKERNELWAIT_VALUE=File system kernel wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSPAUSEWAIT_VALUE=MVS Pause wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATEDTASKS_VALUE=One or more pthread created tasks (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_SWAPPEDOUT_VALUE=Swapped out (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_PTHREADCREATED_VALUE=Pthread created (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_OTHERKERNELWAIT_VALUE=Other kernel wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_CANCELLED_VALUE=Canceled (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MULTITHREAD_VALUE=Multi-thread (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MEDIUMWEIGHTTHREAD_VALUE=Medium weight thread (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_ASYNCHRONOUSTHREAD_VALUE=Asynchronous thread (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_PTRACEKERNELWAIT_VALUE=Ptrace kernel wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_RUNNING_VALUE=Running (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_SLEEPING_VALUE=Sleeping (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_STOPPED_VALUE=Stopped (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_INITIALPROCESSTHREAD_VALUE=Initial process thread (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_DETACHED_VALUE=Detached thread (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_WAITINGFORCHILD_VALUE=Waiting for child (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_FORKING_VALUE=Forking (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_MVSWAIT_VALUE=MVS wait (z/OS) +RESID_PROPERTY_PROCESS_TYPE_ZOS_ZOMBIE_VALUE=Zombie (z/OS) + +RESID_PROPERTY_PROCESS_PID_LABEL=Process ID +RESID_PROPERTY_PROCESS_NAME_LABEL=Executable Name +RESID_PROPERTY_PROCESS_UID_LABEL=User ID +RESID_PROPERTY_PROCESS_USERNAME_LABEL=Username +RESID_PROPERTY_PROCESS_PPID_LABEL=Parent PID +RESID_PROPERTY_PROCESS_GID_LABEL=Group ID +RESID_PROPERTY_PROCESS_STATE_LABEL=State +RESID_PROPERTY_PROCESS_TGID_LABEL=Task Group ID +RESID_PROPERTY_PROCESS_TRACERPID_LABEL=Tracer PID +RESID_PROPERTY_PROCESS_VMSIZE_LABEL=VM Size +RESID_PROPERTY_PROCESS_VMRSS_LABEL=VM RSS +RESID_PROPERTY_PROCESS_PID_TOOLTIP=The system ID number of the process +RESID_PROPERTY_PROCESS_NAME_TOOLTIP=The executable associated with the process +RESID_PROPERTY_PROCESS_UID_TOOLTIP=The user ID of the owner of the process +RESID_PROPERTY_PROCESS_USERNAME_TOOLTIP=The username of the owner of the process +RESID_PROPERTY_PROCESS_PPID_TOOLTIP=The process ID of the parent of the process +RESID_PROPERTY_PROCESS_GID_TOOLTIP=The group ID of the owner of the process +RESID_PROPERTY_PROCESS_STATE_TOOLTIP=The state in which the process currently is +RESID_PROPERTY_PROCESS_TGID_TOOLTIP=The task group to which process belongs +RESID_PROPERTY_PROCESS_TRACERPID_TOOLTIP=The tracer process ID of the process +RESID_PROPERTY_PROCESS_VMSIZE_TOOLTIP=The amount of virtual memory taken up by this process +RESID_PROPERTY_PROCESS_VMSIZE_VALUE=&1 kilobytes +RESID_PROPERTY_PROCESS_VMRSS_TOOLTIP=The amount of virtual memory resident set size of this process (actual RAM taken up by the process) +RESID_PROPERTY_PROCESS_VMRSS_VALUE=&1 kilobytes \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewProcessAdapterFactory.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewProcessAdapterFactory.java new file mode 100644 index 00000000000..1f7bf8e170b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewProcessAdapterFactory.java @@ -0,0 +1,60 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.rse.core.SystemBasePlugin; +import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess; +import org.eclipse.rse.ui.view.AbstractSystemRemoteAdapterFactory; +import org.eclipse.rse.ui.view.ISystemViewElementAdapter; +import org.eclipse.ui.views.properties.IPropertySource; + + +public class SystemViewProcessAdapterFactory extends AbstractSystemRemoteAdapterFactory +{ + private SystemViewRemoteProcessAdapter processAdapter = new SystemViewRemoteProcessAdapter(); + + /** + * Called by our plugin's startup method to register our adaptable object types + * with the platform. We prefer to do it here to isolate/encapsulate all factory + * logic in this one place. + */ + public void registerWithManager(IAdapterManager manager) + { + manager.registerAdapters(this, IRemoteProcess.class); + } + /** + * @see IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class) + */ + public Object getAdapter(Object adaptableObject, Class adapterType) + { + Object adapter = null; + if (adaptableObject instanceof IRemoteProcess) + adapter = processAdapter; + + if ((adapter != null) && (adapterType == IPropertySource.class)) + { + ((ISystemViewElementAdapter)adapter).setPropertySourceInput(adaptableObject); + } + else if (adapter == null) + { + SystemBasePlugin.logWarning("No adapter found for object of type: " + adaptableObject.getClass().getName()); + } + return adapter; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewRemoteProcessAdapter.java b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewRemoteProcessAdapter.java new file mode 100644 index 00000000000..648903b2cd6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/src/org/eclipse/rse/processes/ui/view/SystemViewRemoteProcessAdapter.java @@ -0,0 +1,485 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.processes.ui.view; + + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.rse.core.SystemBasePlugin; +import org.eclipse.rse.core.SystemPlugin; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.model.ISystemMessageObject; +import org.eclipse.rse.model.ISystemResourceSet; +import org.eclipse.rse.model.SystemMessageObject; +import org.eclipse.rse.model.SystemRemoteResourceSet; +import org.eclipse.rse.processes.ui.ProcessesPlugin; +import org.eclipse.rse.processes.ui.actions.SystemKillProcessAction; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; +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.RemoteProcessSubSystem; +import org.eclipse.rse.ui.ISystemContextMenuConstants; +import org.eclipse.rse.ui.ISystemMessages; +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.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.PropertyDescriptor; + + +public class SystemViewRemoteProcessAdapter extends AbstractSystemViewAdapter + implements ISystemViewElementAdapter, ISystemRemoteElementAdapter, ISystemMessages, + ISystemProcessPropertyConstants, ISystemProcessRemoteConstants +{ + private SystemCopyToClipboardAction copyClipboardAction; + public boolean canDrag(Object element) + { + // DKM - this is just for copy + return true; + } + + public boolean canDrag(SystemRemoteResourceSet elements) + { + // DKM - this is just for copy + return true; + } + + public Object doDrag(Object element, boolean sameSystemType, IProgressMonitor monitor) + { + return getText(element); + } + + public ISystemResourceSet doDrag(SystemRemoteResourceSet set, IProgressMonitor monitor) + { + return set; + } + + private static final Object[] EMPTY_LIST = new Object[0]; + private static PropertyDescriptor[] propertyDescriptorArray = null; + private SystemKillProcessAction killProcessAction; + + public void addActions(SystemMenuManager menu, + IStructuredSelection selection, Shell parent, String menuGroup) + { + if (killProcessAction == null) + killProcessAction = new SystemKillProcessAction(shell); + menu.add(ISystemContextMenuConstants.GROUP_CHANGE, killProcessAction); + + + if (copyClipboardAction == null) + { + Clipboard clipboard = SystemPlugin.getTheSystemRegistry().getSystemClipboard(); + copyClipboardAction = new SystemCopyToClipboardAction(shell, clipboard); + } + menu.add(menuGroup, copyClipboardAction); + } + + public ISubSystem getSubSystem(Object element) + { + if (element instanceof IRemoteProcess) + { + IRemoteProcess process = (IRemoteProcess)element; + return process.getParentRemoteProcessSubSystem(); + } + return super.getSubSystem(element); + } + + public ImageDescriptor getImageDescriptor(Object element) + { + //return SystemPlugin.getDefault().getImageDescriptor(ISystemIconConstants.ICON_SYSTEM_PROCESS_ID); + return ProcessesPlugin.getDefault().getImageDescriptorFromPath("icons/full/obj16/activeprocess_obj.gif"); + } + + public String getText(Object element) + { + String text = ((IRemoteProcess) element).getLabel(); + return (text == null) ? "" : text; + } + + /** + * Used for stuff like clipboard text copy + */ + 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(); + } + + public String getType(Object element) + { + IRemoteProcess process = (IRemoteProcess) element; + if (process.isRoot()) + return SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE_ROOT; + else return SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TYPE; + } + + 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; + } + + public boolean hasChildren(Object element) + { + // TODO Auto-generated method stub + return false; + } + + public Object[] getChildren(Object element) + { + IRemoteProcess process = (IRemoteProcess) element; + RemoteProcessSubSystem ss = process.getParentRemoteProcessSubSystem(); + IHostProcessFilter orgRpfs = process.getFilterString(); + + Object[] children = null; + + try + { + children = ss.listAllProcesses(orgRpfs, process.getContext()); + if ((children == null) || (children.length == 0)) + { + children = EMPTY_LIST; + } + } + /*catch (InterruptedException exc) + { + children = new SystemMessageObject[1]; + children[0] = new SystemMessageObject(SystemPlugin.getPluginMessage(MSG_EXPAND_CANCELLED), ISystemMessageObject.MSGTYPE_CANCEL, element); + }*/ + catch (Exception exc) + { + children = new SystemMessageObject[1]; + children[0] = new SystemMessageObject(SystemPlugin.getPluginMessage(MSG_EXPAND_FAILED), ISystemMessageObject.MSGTYPE_ERROR, element); + SystemBasePlugin.logError("Exception resolving file filter strings", exc); + } + return children; + } + + protected IPropertyDescriptor[] internalGetPropertyDescriptors() + { + + if (propertyDescriptorArray == null) + { + int nbrOfProperties = ISystemProcessRemoteConstants.PROCESS_ATTRIBUTES_COUNT; + + propertyDescriptorArray = new PropertyDescriptor[nbrOfProperties]; + + int idx = -1; + + // pid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_PID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_PID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_PID_TOOLTIP); + + // name + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_NAME, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_NAME_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_NAME_TOOLTIP); + + // state + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_STATE, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_STATE_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_STATE_TOOLTIP); + + // uid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_UID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_UID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_UID_TOOLTIP); + + // username + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_USERNAME, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_USERNAME_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_USERNAME_TOOLTIP); + + // ppid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_PPID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_PPID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_PPID_TOOLTIP); + + // gid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_GID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_GID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_GID_TOOLTIP); + + // tgid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_TGID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TGID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TGID_TOOLTIP); + + // tracerpid + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_TRACERPID, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TRACERPID_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_TRACERPID_TOOLTIP); + + // virtual memory size + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_VMSIZE, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMSIZE_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMSIZE_TOOLTIP); + + // virtual memory rss + propertyDescriptorArray[++idx] = createSimplePropertyDescriptor(P_PROCESS_VMRSS, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMRSS_LABEL, SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMRSS_TOOLTIP); + + } + return propertyDescriptorArray; + } + + /** + * Returns the current value for the named property. + * @return the current value of the given property + */ + protected Object internalGetPropertyValue(Object key) + { + return getPropertyValue(key, true); + } + + /** + * 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 + */ + public Object getPropertyValue(Object property, boolean formatted) + { + String name = (String) property; + IRemoteProcess process = (IRemoteProcess) propertySourceInput; + + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_GID)) + { + if (formatted) + { + return "" + process.getGid(); + } + else + { + return new Long(process.getGid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_NAME)) + { + return process.getName(); + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_PID)) + { + if (formatted) + { + return "" + process.getPid(); + } + else + { + return new Long(process.getPid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_PPID)) + { + if (formatted) + { + return "" + process.getPPid(); + } + else + { + return new Long(process.getPPid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_STATE)) + { + if (formatted) + { + return formatState(process.getState()); + } + else + { + return process.getState(); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_TGID)) + { + if (formatted) + { + return "" + process.getTgid(); + } + else + { + return new Long(process.getTgid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_TRACERPID)) + { + if (formatted) + { + return "" + process.getTracerPid(); + } + else + { + return new Long(process.getTracerPid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_UID)) + { + if (formatted) + { + return "" + process.getUid(); + } + else + { + return new Long(process.getUid()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_USERNAME)) + { + return process.getUsername(); + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_VMSIZE)) + { + if (formatted) + { + return sub(SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMSIZE_VALUE, MSG_SUB1, Long.toString(process.getVmSizeInKB())); + } + else + { + return new Long(process.getVmSizeInKB()); + } + } + if (name.equals(ISystemProcessPropertyConstants.P_PROCESS_VMRSS)) + { + if (formatted) + { + return sub(SystemProcessesViewResources.RESID_PROPERTY_PROCESS_VMRSS_VALUE, MSG_SUB1, Long.toString(process.getVmRSSInKB())); + } + else + { + return new Long(process.getVmRSSInKB()); + } + } + else + return null; //super.getPropertyValue(name); + } + + protected String formatState(String state) + { + if (state == null) return ""; + state = state.trim(); + String longState = ""; + String[] allStates = state.split(","); + if (allStates == null) return longState; + + SystemProcessStatesContentProvider zstates = new SystemProcessStatesContentProvider(); + for (int i = 0; i < allStates.length; i++) + { + longState = longState + allStates[i].charAt(0) + "-" + zstates.getStateString(allStates[i]); + if (i < allStates.length - 1) + longState = longState + ", "; + } + return longState; + } + + /** + * 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"; + } + + /** + * Given a remote object, returns it remote parent object. Eg, given a process, return the process that + * spawned it. + *

+ * 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(Shell shell, Object element) 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(Shell shell, Object element) throws Exception + { + String[] pids = EMPTY_STRING_LIST; + + IRemoteProcess process = (IRemoteProcess) element; + String parentName = "" + process.getPPid(); + if (parentName.equals("-1")) // given a root? + return pids; // not much we can do. Should never happen: you can't rename a root! + + Object[] children = getChildren(process.getParentRemoteProcess()); + 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(); + + 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 getSubSystemFactoryId(Object element) + { + IRemoteProcess process = (IRemoteProcess) element; + return process.getParentRemoteProcessSubSystem().getSubSystemConfiguration().getId(); + } + + public boolean refreshRemoteObject(Object oldElement, Object newElement) + { + /*if (oldElement instanceof IRemoteProcess) + { + IRemoteProcess oldProcess = (IRemoteProcess) oldElement; + IRemoteProcess newProcess = (IRemoteProcess) newElement; + oldProcess.getParentRemoteProcessSubSystem().setAllProperties(newProcess.getAllProperties()); + return hasChildren(oldElement); + }*/ + return false; + } + + public boolean supportsUserDefinedActions(Object object) + { + return false; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.processes.ui/systemmessages.xml b/rse/plugins/org.eclipse.rse.processes.ui/systemmessages.xml new file mode 100644 index 00000000000..8aef95ea730 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.processes.ui/systemmessages.xml @@ -0,0 +1,50 @@ + + + + + + + + + + Maximum VM size must be greater than minimum VM size. + + + + You do not have permission to kill the process. + You must own the process or be root in order to kill this process. + + + Sending a kill signal... + + + + Sending the signal %1 to the process %2... + + + + Kill of the process %1 failed + The remote system reported the following: %2 + + + Problem occurred during remote process query + Could not access the /proc filesystem. You might not have permission to access it. + + + + + \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/.classpath b/rse/plugins/org.eclipse.rse.services/.classpath new file mode 100644 index 00000000000..e2ec6637df2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.services/.cvsignore b/rse/plugins/org.eclipse.rse.services/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/rse/plugins/org.eclipse.rse.services/.project b/rse/plugins/org.eclipse.rse.services/.project new file mode 100644 index 00000000000..fe86041f3a4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/.project @@ -0,0 +1,28 @@ + + + org.eclipse.rse.services + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/rse/plugins/org.eclipse.rse.services/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.services/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..fc738754219 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %plugin.name +Bundle-SymbolicName: org.eclipse.rse.services +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.rse.services.Activator +Bundle-Vendor: Eclipse.org +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime +Eclipse-LazyStart: true +Export-Package: org.eclipse.rse.services, + org.eclipse.rse.services.clientserver, + org.eclipse.rse.services.clientserver.archiveutils, + org.eclipse.rse.services.clientserver.java, + org.eclipse.rse.services.clientserver.messages, + org.eclipse.rse.services.clientserver.processes, + org.eclipse.rse.services.clientserver.processes.handlers, + org.eclipse.rse.services.clientserver.search, + org.eclipse.rse.services.clientserver.util.tar, + org.eclipse.rse.services.files, + org.eclipse.rse.services.processes, + org.eclipse.rse.services.search, + org.eclipse.rse.services.shells +Bundle-ClassPath: clientserver.jar, + services.jar diff --git a/rse/plugins/org.eclipse.rse.services/about.html b/rse/plugins/org.eclipse.rse.services/about.html new file mode 100644 index 00000000000..6f6b96c4c87 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

February 24, 2005

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content.

+ + + \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/build.properties b/rse/plugins/org.eclipse.rse.services/build.properties new file mode 100644 index 00000000000..16baa859797 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/build.properties @@ -0,0 +1,14 @@ +bin.includes = META-INF/,\ + about.html,\ + plugin.properties,\ + services.jar,\ + clientserver.jar +src.includes = META-INF/,\ + about.html,\ + plugin.properties +jars.compile.order = clientserver.jar,\ + services.jar +source.clientserver.jar = clientserver/ +output.clientserver.jar = bin/ +source.services.jar = src/ +output.services.jar = bin/ diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/FileTypeMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/FileTypeMatcher.java new file mode 100644 index 00000000000..dd3356707f2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/FileTypeMatcher.java @@ -0,0 +1,286 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * This class offers file type matching. A file type is the extension part of a file + * name, minus the dot. For example, "java" and "class" are types. + *

+ * Recently added is support for full file names, such as "manifest.mf", and even + * extension-less names which use the placeholder ".null" for the extension, as in + * "makefile.null" so as to dis-ambiguate from extensions like "cpp". + *

+ * This supports being given a list of file types, via the constructor, to match on. It + * will return true from the {@link #matches(String)} method if the given file name ends + * in an extension that matches one of the given types. + *

+ * By default, all matching is done case-insensitive, but this can be overridden in the + * constructor or by calling {@link #setCaseSensitive(boolean)}. + *

+ * For file name matching, use {@link org.eclipse.rse.services.clientserver.NamePatternMatcher} instead. + */ +public class FileTypeMatcher implements IMatcher +{ + + /** + * The delimiter that starts the extension part + */ + public static final char SEP_EXTENSION = '.'; + private String[] orgTypes, types; + private String[] orgNames, names; + private boolean caseSensitive = false; + + /** + * Constructor for case-insensitive matching + * + * @param types Array of file types to match on. These should not include the dot. Eg, "java" + */ + public FileTypeMatcher(String[] types) + { + this(types, false); + } + /** + * Constructor when specifying if matching is case-sensitive or not + * + * @param types Array of file types to match on. These should not include the dot. Eg, "java" + * @param caseSensitive true if to consider case when matching + */ + public FileTypeMatcher(String[] types, boolean caseSensitive) + { + setTypes(types); + setCaseSensitive(caseSensitive); + } + + /** + * Reset the types used to match on + */ + public void setTypes(String[] types) + { + this.types = types; + this.orgTypes = types; + setCaseSensitive(caseSensitive); + } + /** + * Reset the types and names used to match on + */ + public void setTypesAndNames(String[] types, String[] names) + { + this.types = types; + this.orgTypes = types; + this.names = names; + this.orgNames = names; + setCaseSensitive(caseSensitive); + } + /** + * Reset the types and names used to match on + */ + public void setTypesAndNames(String[] typesAndNames) + { + Vector typesVector = new Vector(); + Vector namesVector = new Vector(); + for (int idx=0; idx= 0) && (dotIdx < lastPos)) + { + if (!caseSensitive) + type = fileName.substring(dotIdx+1).toLowerCase(); // strip off + else + type = fileName.substring(dotIdx+1); + for (int idx=0; !matches && (idx0) && + (token.indexOf('.') == -1)) + v.addElement(token); + } + String[] types = new String[v.size()]; + for (int idx=0; idx0) && + (token.indexOf('.') != -1)) + v.addElement(token); + } + String[] names = new String[v.size()]; + for (int idx=0; idx + * This supports one wildcard character ('*") anywhere in + * the name, or one at the beginning and end of the name. + *

    + *
  1. ABC
  2. + *
  3. *
  4. + *
  5. ABC*
  6. + *
  7. *ABC
  8. + *
  9. AB*C
  10. + *
  11. *ABC*
  12. + *
+ *

+ * This pattern matching class also optionally supports additional + * advanced patterns beyond the stricter PDM style. These allow + * for two '*'s anywhere in the name. + *

    + *
  1. AB*C*
  2. + *
  3. *A*C
  4. + *
  5. A*B*C
  6. + *
+ *

+ * Quoted names are supported. + *

+ * All matching is case-sensitive! + *

+ * Instantiate this class for a given generic name, and then + * call matches(String input) for each input name to see if it + * matches the pattern. + *

+ * To enable the advanced patterns, pass true to the constructor. + */ +public class NamePatternMatcher implements IMatcher +{ + + /** + * Wildcard character: * + */ + public static final char WILDCARD = '*'; + private static final String WILDCARD_DOUBLED = "**"; + /** + * Example: Quoted name delimiter: " + */ + public static final char QUOTE = '"'; + /** + * Example: ABC + */ + public static final int SCALAR = 0; + /** + * Example: * + */ + public static final int ALL = 1; + /** + * Example: ABC* + */ + public static final int WILDCARD_END = 2; + /** + * Example: *ABC + */ + public static final int WILDCARD_START = 4; + /** + * Example: A*C + */ + public static final int WILDCARD_MIDDLE = 8; + /** + * Example: *ABC* + */ + public static final int WILDCARD_START_END = 16; + /* + * Example: A*C* + */ + public static final int WILDCARD_MIDDLE_END = 32; + /** + * Example: *A*F + */ + public static final int WILDCARD_START_MIDDLE = 64; + /** + * Example: A*C*F + */ + public static final int WILDCARD_MIDDLE_MIDDLE = 128; + + + // used in writeInfo debugging method + private static final int[] TYPES_IDX = {SCALAR,ALL,WILDCARD_END,WILDCARD_START,WILDCARD_MIDDLE, + WILDCARD_START_END,WILDCARD_MIDDLE_END,WILDCARD_START_MIDDLE,WILDCARD_MIDDLE_MIDDLE}; + private static final String[] TYPES = {"SCALAR","ALL","END","START","MIDDLE","START_END","MIDDLE_END","START_MIDDLE","MIDDLE_MIDDLE"}; + + private String genericName, part1, part2, part3; + private int part1len,part2len,part3len,part12len,part123len; + private int patternType; + private boolean quotedName, validName; + private boolean caseSensitive = true; + /** + * Constructor for traditional-style only patterns, which allows + * for one asterisk anywhere in the name,or one asterisk each at the + * beginning or end of the name. + *

+ * If you don't know for sure the input is generic or valid, after + * constructing call: + * + *

  • {@link #isValid()} to determine if given generic name was valid.
  • + *
  • {@link #isGeneric()} to determine if given generic name had a wildcard.
  • + * + *

    + * If curious, you can also subsequently call: + * + *

  • {@link #getPatternType()} to determine which type of pattern the generic name follows.
  • + * + *

    + * Once constructed for a valid name, you can call + * + *

  • {@link #matches(String)} for each name to see if it matches this generic name pattern. + * + *

    + * Quoted names are supported. + *

    + * All matching is case-sensitive! + * + * @param genericName generic name to do pattern matching for (ie, ABC*DEF) + */ + public NamePatternMatcher(String genericName) + { + this(genericName, false, true); + } + /** + * Constructor for traditional-style patterns PLUS advanced + * patterns ABC*DEF* and A*C*F. + *

    + * If you don't know for sure the input is generic or valid, after + * constructing call: + * + *

  • {@link #isValid()} to determine if given generic name was valid.
  • + *
  • {@link #isGeneric()} to determine if given generic name had a wildcard.
  • + * + *

    + * If curious, you can also subsequently call: + * + *

  • {@link #getPatternType()} to determine which type of pattern the generic name follows.
  • + * + *

    + * Once constructed for a valid name, you can call + * + *

  • {@link #matches(String)} for each name to see if it matches this generic name pattern. + * + *

    + * Quoted names are supported. + * + * @param genericName generic name to do pattern matching for (ie, ABC*DEF) + * @param advanced true if you want to support the advanced patterns. + * @param caseSensitive true if the names are case-sensitive, false if case insensitive + */ + public NamePatternMatcher(String genericName, boolean advanced, boolean caseSensitive) + { + this.caseSensitive = caseSensitive; + genericName = genericName.trim(); + int len = 0; + // determine if given a null name + if ((genericName == null) || (genericName.length()==0)) + validName = false; + else + validName = true; // for now + if (validName) + { + len = genericName.length(); + // determine if given generic name is a quoted name + quotedName = genericName.charAt(0) == QUOTE; + if (quotedName && ((len==1) || (genericName.charAt(len-1)!=QUOTE))) + validName = false; + if (!quotedName && !caseSensitive) + genericName = genericName.toLowerCase(); + } + if (validName) + { + // change *BLANK into 10 blanks + if (genericName.equals("*BLANK")) + genericName = " "; + // away we go... + int firstCharPos = quotedName ? 1 : 0; + int lastCharPos = quotedName ? len-2 : len-1; + char firstChar = genericName.charAt(firstCharPos); + char lastChar = genericName.charAt(lastCharPos); + // determine type of generic name. 6 flavors including SCALAR... + int wildcardOccurrences = countOccurrencesOf(genericName, WILDCARD); + if (wildcardOccurrences==0) + { + patternType = SCALAR; + } + else if (wildcardOccurrences==1) + { + if ((!quotedName && (len == 1)) || (quotedName && (len ==3)) || genericName.equals("*ALL") || genericName.equals("\"*ALL\"") || genericName.equals("*LIBL")) + patternType = ALL; + else if (firstChar == WILDCARD) + { + patternType = WILDCARD_START; + part2 = genericName.substring(firstCharPos+1,lastCharPos+1); + } + else if (lastChar == WILDCARD) + { + patternType = WILDCARD_END; + part1 = genericName.substring(firstCharPos,lastCharPos); + } + else + { + patternType = WILDCARD_MIDDLE; + int wcPos = genericName.indexOf(WILDCARD); + part1 = genericName.substring(firstCharPos,wcPos); + part2 = genericName.substring(wcPos+1,lastCharPos+1); + } + } + else if (wildcardOccurrences==2) + { + if (!advanced && (lastChar != WILDCARD) && (firstChar != WILDCARD)) + validName = false; + else if (genericName.indexOf(WILDCARD_DOUBLED) >= 0) + validName = false; + else if ((firstChar == WILDCARD) && (lastChar == WILDCARD)) // pdm-style + { + patternType = WILDCARD_START_END; + part1 = genericName.substring(firstCharPos+1,lastCharPos); + } + else if (lastChar == WILDCARD) // advanced: A*C* + { + patternType = WILDCARD_MIDDLE_END; + int wcPos = genericName.indexOf(WILDCARD); + part1 = genericName.substring(firstCharPos,wcPos); + part2 = genericName.substring(wcPos+1,lastCharPos); + part1len = part1.length(); + part2len = part2.length(); + part12len = part1len + part2len; + } + else if (firstChar == WILDCARD) // advanced: *B*C + { + patternType = WILDCARD_START_MIDDLE; + int wcPos = genericName.lastIndexOf(WILDCARD); + part1 = genericName.substring(firstCharPos+1,wcPos); + part2 = genericName.substring(wcPos+1,lastCharPos+1); + part1len = part1.length(); + part2len = part2.length(); + part12len = part1len + part2len; + } + else // advanced: A*C*F + { + patternType = WILDCARD_MIDDLE_MIDDLE; + int wcPos1 = genericName.indexOf(WILDCARD); + int wcPos2 = genericName.lastIndexOf(WILDCARD); + part1 = genericName.substring(firstCharPos,wcPos1); + part2 = genericName.substring(wcPos1+1,wcPos2); + part3 = genericName.substring(wcPos2+1,lastCharPos+1); + part1len = part1.length(); + part2len = part2.length(); + part12len = part1len + part2len; + part123len = part12len + part3.length(); + } + } + else + validName = false; + } + this.genericName = genericName; + } + /** + * Test if a host name matches the pattern of this generic name. + * @param input Scalar name like ABCDEF + * @return true if given name matches this generic name pattern. + */ + public boolean matches(String input) + { + boolean matches = false; + if (validName) + { + if ((input.length()>2) && + (input.charAt(0) == QUOTE)) + input = input.substring(1,input.length()-1); + else if (!caseSensitive) + input = input.toLowerCase(); + switch (patternType) + { + case SCALAR: + matches = input.equals(genericName); + break; + case ALL: + matches = true; + break; + case WILDCARD_END: + matches = input.startsWith(part1); + break; + case WILDCARD_START: + matches = input.endsWith(part2); + break; + case WILDCARD_MIDDLE: + matches = input.startsWith(part1) && input.endsWith(part2); + break; + case WILDCARD_START_END: + matches = (input.indexOf(part1) >= 0); + break; + case WILDCARD_MIDDLE_END: + if (input.startsWith(part1) && (input.length()>=part12len)) + matches = (input.indexOf(part2,part1len) >= 0); + else + matches = false; + break; + case WILDCARD_START_MIDDLE: // *B*F + if (input.endsWith(part2) && (input.length()>=part12len)) + { + int idx = input.indexOf(part1); + int startOfEndPart = input.length() - part2len; + matches = ((idx >= 0) && (idx+part1len <= startOfEndPart)); + } + else + matches = false; + break; + case WILDCARD_MIDDLE_MIDDLE: // A*C*D + if (input.startsWith(part1) && input.endsWith(part3) && (input.length()>=part123len)) + { + int idx = input.indexOf(part2); + int startOfEndPart = input.length() - part3len; + matches = ((idx >= 0) && (idx >= part1len) && (idx <= startOfEndPart)); + } + else + matches = false; + break; + } + } + return matches; + } + + /** + * Was generic name given in the constructor a valid scalar or generic name? + * @return true if name contained 0, 1 or 2 wildcards. + */ + public boolean isValid() + { + return validName; + } + /** + * Was generic name given in the constructor a valid generic name (one or 2 '*'s)? + */ + public boolean isGeneric() + { + return patternType != SCALAR; + } + /** + * Was quoted name given in the constructor a quoted name like "abcDEF"? + */ + public boolean isQuoted() + { + return quotedName; + } + /** + * What type of pattern is it? One of: + * {@link #SCALAR}, {@link #ALL}, {@link #WILDCARD_END}, {@link #WILDCARD_START}, {@link #WILDCARD_MIDDLE}, + * {@link #WILDCARD_START_END}, or {@link #WILDCARD_MIDDLE_END} + */ + public int getPatternType() + { + return patternType; + } + /** + * Helper method. + * Count occurrences of given character in given string. + * Does NOT take into account quoted names. + */ + private static int countOccurrencesOf(String haystack, char needle) + { + int count = 0; + for (int idx=0; idx= 0) + return false; + } + else if (wildcardOccurrences > 2) + return false; + return true; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/PathUtility.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/PathUtility.java new file mode 100644 index 00000000000..7d7ec6217ed --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/PathUtility.java @@ -0,0 +1,140 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import org.eclipse.rse.services.clientserver.archiveutils.AbsoluteVirtualPath; +import org.eclipse.rse.services.clientserver.archiveutils.ArchiveHandlerManager; + +public class PathUtility +{ + + public static String normalizeWindows(String path) + { + if (path == null || path.length() < 2) return path; + boolean containsForwardSlash = false; + boolean containsDoubleSlashes = false; + boolean endsWithSlash = false; + + if (path.indexOf("/") != -1) containsForwardSlash = true; + if (path.indexOf("\\\\") != -1) containsDoubleSlashes = true; + if (path.endsWith("\\") || path.endsWith("/")) endsWithSlash = true; + + boolean needsNormalizing = containsForwardSlash || containsDoubleSlashes || endsWithSlash; + if (!needsNormalizing) return path; + + if (containsForwardSlash) + { + path = path.replace('/', '\\'); + containsDoubleSlashes = (path.indexOf("\\\\") != -1); + } + + /* DKM - replaceAll is causing exception + while (containsDoubleSlashes) + { + path = path.replaceAll("\\\\", "\\"); + containsDoubleSlashes = (path.indexOf("\\\\") != -1); + } + */ + if (endsWithSlash) + { + if (!(path.length() == 3)) path = path.substring(0, path.length() - 1); + } + return path; + } + + public static String normalizeUnix(String path) + { + if (path == null || path.length() < 2) return path; + boolean containsBackSlash = false; + boolean containsDoubleSlashes = false; + boolean endsWithSlash = false; + + if (path.indexOf("\\") != -1) containsBackSlash = true; + if (path.indexOf("//") != -1) containsDoubleSlashes = true; + if (path.endsWith("\\") || path.endsWith("/")) endsWithSlash = true; + + boolean needsNormalizing = containsBackSlash || containsDoubleSlashes || endsWithSlash; + if (!needsNormalizing) return path; + + if (containsBackSlash) + { + path = path.replaceAll("\\", "/"); + containsDoubleSlashes = (path.indexOf("//") != -1); + } + + while (containsDoubleSlashes) + { + path = path.replaceAll("//", "/"); + containsDoubleSlashes = (path.indexOf("//") != -1); + } + + if (endsWithSlash) + { + if (!(path.length() == 1)) path = path.substring(0, path.length() - 1); + } + return path; + + } + + public static String normalizeVirtualWindows(String path) + { + if (path == null || path.length() < 2) return path; + AbsoluteVirtualPath avp = new AbsoluteVirtualPath(path); + String realPart = avp.getContainingArchiveString(); + if (ArchiveHandlerManager.isVirtual(realPart)) + realPart = normalizeVirtualWindows(realPart); + else realPart = normalizeWindows(realPart); + return realPart + ArchiveHandlerManager.VIRTUAL_SEPARATOR + avp.getVirtualPart(); + } + + public static String normalizeVirtualUnix(String path) + { + if (path == null || path.length() < 2) return path; + AbsoluteVirtualPath avp = new AbsoluteVirtualPath(path); + String realPart = avp.getContainingArchiveString(); + if (ArchiveHandlerManager.isVirtual(realPart)) + realPart = normalizeVirtualUnix(realPart); + else realPart = normalizeUnix(realPart); + return realPart + ArchiveHandlerManager.VIRTUAL_SEPARATOR + avp.getVirtualPart(); + } + + public static String normalizeUnknown(String path) + { + if (path == null || path.length() < 2) return path; + if (path.charAt(1) == ':') + if (path.indexOf(ArchiveHandlerManager.VIRTUAL_CANONICAL_SEPARATOR) == -1) + return normalizeWindows(path); + else return normalizeVirtualWindows(path); + else if (path.charAt(0) == '/') + if (path.indexOf(ArchiveHandlerManager.VIRTUAL_CANONICAL_SEPARATOR) == -1) + return normalizeUnix(path); + else return normalizeVirtualUnix(path); + else return path; + } + + public static String getSeparator(String path) + { + if (path.length() > 1 && path.charAt(1) == ':') + { + return "\\"; + } + else + { + return "/"; + } + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/RegexPatternMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/RegexPatternMatcher.java new file mode 100644 index 00000000000..fb6b274803e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/RegexPatternMatcher.java @@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A pattern matcher used for search that uses regex + */ +public class RegexPatternMatcher implements ISearchPatternMatcher +{ + private Pattern _regexPattern; + + public RegexPatternMatcher(String pattern) + { + _regexPattern = Pattern.compile(pattern); + } + + public boolean stringMatches(String compareString) + { + Matcher matcher = _regexPattern.matcher(compareString); + return matcher.matches(); + + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringCompare.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringCompare.java new file mode 100644 index 00000000000..0fad92d6eaf --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringCompare.java @@ -0,0 +1,125 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +/** + * Utility class for comparing a wildcard string to another string + */ +public class StringCompare +{ + + /** + * Constructor + */ + public StringCompare() + { + } + + /** + * Compare two strings + * + * @param pattern the pattern to match + * @param compareStr the string to compare against the pattern + * @param noCase indicates whether the strings should be compared based on case + * @return true if the compare string matches the pattern + */ + public static boolean compare(String pattern, String compareStr, boolean noCase) + { + if ((pattern == null) || (compareStr == null)) + return false; + + if (noCase) + { + pattern = pattern.toUpperCase(); + compareStr = compareStr.toUpperCase(); + } + + String currentMatch = new String(""); + + int iText = 0; + int iPattern = 0; + int lastStar = 0; + int len = compareStr.length(); + + int patternLen = pattern.length(); + + while (iPattern < patternLen) + { + char p = pattern.charAt(iPattern++); + if (p == '*') + { + + if (iPattern >= patternLen) + { + while (iText < len) + { + iText++; + } + return true; + } + else + { + lastStar = iPattern; + } + } + else + { + if (iText >= len) + { + return false; + } + else + { + char t = compareStr.charAt(iText++); + if (p == t) + { + if ((lastStar > 0) && (iPattern >= patternLen) && (iText < len)) + { + } + else + { + continue; + } + + } + else + { + if (lastStar == 0) + { + return false; + } + } + + int matched = iPattern - lastStar - 1; + iPattern = lastStar; + + iText -= matched; + } + } + } + + if (iText >= len) + { + return true; + } + else + { + return false; + } + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringComparePatternMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringComparePatternMatcher.java new file mode 100644 index 00000000000..5929d4780e2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/StringComparePatternMatcher.java @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +/* + * A pattern matcher for search that uses wildcard based compares + */ +public class StringComparePatternMatcher implements ISearchPatternMatcher +{ + private String _pattern; + + public StringComparePatternMatcher(String pattern) + { + _pattern = pattern; + } + + public boolean stringMatches(String compareString) + { + return StringCompare.compare(_pattern, compareString, true); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemEncodingUtil.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemEncodingUtil.java new file mode 100644 index 00000000000..d8c616ce739 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemEncodingUtil.java @@ -0,0 +1,387 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * A singleton class that contains useful methods related to encodings. + */ +public class SystemEncodingUtil { + + private static SystemEncodingUtil instance; + public static String ENCODING_UTF_8 = "UTF-8"; + + /** + * Constructor to create the utility class. + */ + private SystemEncodingUtil() { + super(); + } + + /** + * Returns the singleton instance of the utility class. + * @return the singleton instance. + */ + public static SystemEncodingUtil getInstance() { + + if (instance == null) { + instance = new SystemEncodingUtil(); + } + + return instance; + } + + /** + * Gets the encoding of the environment. This is the encoding being used by the JVM, + * which by default is the machine encoding, unless changed explicitly. + * @return the evironment encoding. + */ + public String getEnvironmentEncoding() { + return System.getProperty("file.encoding"); + } + + /** + * Returns whether the file is an XML file. + * @param filePath the file path. + * @return true if the file is an XML file, false otherwise. + */ + public boolean isXML(String filePath) { + + int index = filePath.lastIndexOf("."); + + // check if there is a "." + if (index == -1) { + return false; + } + else { + + // check if the name ends with "." + if (index == filePath.length() - 1) { + return false; + } + else { + String extension = filePath.substring(index+1); + + if (extension.equalsIgnoreCase("xml") || extension.equalsIgnoreCase("xmi")) { + return true; + } + else { + return false; + } + } + } + } + + /** + * Gets the encoding of an XML file. + * @param filePath the file path. + * @return the encoding, or null if the encoding could not be determined. + */ + public String getXMLFileEncoding(String filePath) throws IOException { + + String encoding = null; + + // this is an implementation of the encoding detection algorithm + // as specified in Appendix F of the XML specification + + FileInputStream stream = new FileInputStream(filePath); + + // try to get the encoding if the file starts with a BOM + String encodingGuess = getEncodingFromBOM(stream); + + stream.close(); + + // if no BOM, read in bytes corresponding to the first four chars in the header, i.e. "null if there is no BOM. + */ + public String getEncodingFromBOM(String filePath) throws IOException { + FileInputStream stream = new FileInputStream(filePath); + + String encoding = getEncodingFromBOM(stream); + + stream.close(); + + return encoding; + } + + /** + * Gets the encoding from the Byte Order Mark (BOM). + * @param filePath the file path. + * @return the encoding, or null if there is no BOM. + */ + private String getEncodingFromBOM(InputStream stream) throws IOException { + + byte[] bomBytes = new byte[4]; + + // read the first three bytes + stream.read(bomBytes, 0, 3); + + // check if UTF-8 BOM + if (bomBytes[0] == 0xEF && bomBytes[1] == 0xBB && bomBytes[2] == 0xBF) { + return SystemEncodingUtil.ENCODING_UTF_8; + } + + // now read the fourth byte + stream.read(bomBytes, 3, 1); + + // check if it matches some other encoding BOM + + // UCS-4, big-endian order (1234 order) + if (bomBytes[0] == 0x00 && bomBytes[1] == 0x00 && bomBytes[2] == 0xFE && bomBytes[3] == 0xFF) { + return null; + } + // UCS-4, little-endian order (4321 order) + else if (bomBytes[0] == 0xFF && bomBytes[1] == 0xFE && bomBytes[2] == 0x00 && bomBytes[3] == 0x00) { + return null; + } + // UCS-4, unusual octet order (2143) + else if (bomBytes[0] == 0x00 && bomBytes[1] == 0x00 && bomBytes[2] == 0xFF && bomBytes[3] == 0xFE) { + return null; + } + // UCS-4, unusual octet order (3412) + else if (bomBytes[0] == 0xFE && bomBytes[1] == 0xFF && bomBytes[2] == 0x00 && bomBytes[3] == 0x00) { + return null; + } + // UTF-16, big-endian order + else if (bomBytes[0] == 0xFE && bomBytes[1] == 0xFF && !(bomBytes[2] == 0x00 && bomBytes[3] == 0x00)) { + return "UnicodeBig"; + } + // UTF-16, little-endian order + else if (bomBytes[0] == 0xFF && bomBytes[1] == 0xFE && !(bomBytes[2] == 0x00 && bomBytes[3] == 0x00)) { + return "UnicodeLittle"; + } + // not a BOM + else { + return null; + } + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemFileClassifier.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemFileClassifier.java new file mode 100644 index 00000000000..cc7a28f0237 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemFileClassifier.java @@ -0,0 +1,324 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; + +import org.eclipse.rse.services.clientserver.archiveutils.AbsoluteVirtualPath; +import org.eclipse.rse.services.clientserver.archiveutils.ArchiveHandlerManager; +import org.eclipse.rse.services.clientserver.java.BasicClassFileParser; + + +/** + * This singleton class classifies a file on the remote system. + */ +public class SystemFileClassifier { + + private static SystemFileClassifier instance; + + /** + * Constructor. + */ + private SystemFileClassifier() { + super(); + } + + /** + * Returns the singleton instance. + * @return the singleton instance. + */ + public static SystemFileClassifier getInstance() { + + if (instance == null) { + instance = new SystemFileClassifier(); + } + + return instance; + } + + /** + * Classifies the file with the given absolute path. The absolute path can represent a virtual file. + * By default, returns "file". + * @param absolutePath the absolute path. + * @return the classification. + */ + public String classifyFile(String absolutePath) { + + // first check if the absolute path is virtual + boolean isVirtual = ArchiveHandlerManager.isVirtual(absolutePath); + + // if virtual, classify using archive handler manager + if (isVirtual) { + return classifyVirtual(absolutePath); + } + // otherwise, we classify using our way + else { + return classifyNonVirtual(absolutePath); + } + } + + /** + * Classifies a virtual file with the given path. + * @param absolutePath the absolute path of the virtual file. + * @return the classification. + */ + protected String classifyVirtual(String absolutePath) { + + // create an abolute virtual path object + AbsoluteVirtualPath avp = new AbsoluteVirtualPath(absolutePath); + + // get the path of the containing archive + String archivePath = avp.getContainingArchiveString(); + + // get the virtual part of the file path + String virtualPath = avp.getVirtualPart(); + + // get archive file + File archiveFile = new File(archivePath); + + // get classification of virtual file + return ArchiveHandlerManager.getInstance().getClassification(archiveFile, virtualPath); + } + + /** + * Classifies a non-virtual file with the given path. + * @param absolutePath the absolute path of the file. + * @return the classification. + */ + protected String classifyNonVirtual(String absolutePath) { + + // default type + String type = "file"; + + File file = new File(absolutePath); + + // check if file exists + if (!file.exists()) { + return type; + } + + // find out if we are on Windows + boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("win"); + + // for Windows, we only detect *.exe and *.dll files + if (isWindows) + { + absolutePath = absolutePath.toLowerCase(); + // classify *.class file + if (absolutePath.endsWith(".class")) { + type = classifyClassFile(absolutePath); + } + // *.exe files are binary executables + else if (absolutePath.endsWith(".exe")) { + type = "executable(binary)"; + } + // *.dll files are of type "module" + else if (absolutePath.endsWith(".dll")) { + type = "module"; + } + + return type; + } + + // get specified encoding if any + String encoding = System.getProperty("dstore.stdin.encoding"); + + // otherwise, default to system encoding + if (encoding == null || encoding.equals("")) { + encoding = System.getProperty("file.encoding"); + } + + // create command "sh -c file " + String args[] = new String[3]; + args[0] = "sh"; + args[1] = "-c"; + args[2] = "file " + absolutePath; + + BufferedReader poutReader = null; + + try { + Process childProcess = Runtime.getRuntime().exec(args); + InputStreamReader reader = new InputStreamReader(childProcess.getInputStream(), encoding); + poutReader = new BufferedReader(reader); + + // get line of output + String line = poutReader.readLine(); + + if (line != null) { + line = line.trim(); + + // classify from line of output + type = getClassification(absolutePath, line); + + // close stream + poutReader.close(); + + // if it a symbolic link, then get the canonical path and classify it as well + if (type.equals("link")) { + String canonicalPath = file.getCanonicalPath(); + return type + "(" + classifyNonVirtual(canonicalPath) + ")" + ":" + canonicalPath; + } + else { + return type; + } + } + } + catch (UnsupportedEncodingException e) { + // TODO: log it + return type; + } + catch (IOException e) { + // TODO: log it + return type; + } + + return type; + } + + /** + * Classifies from the given line of classification output. + * @param absolutePath the absolute path of the file that was classified. + * @param line the line of output to parse. + * @return the classification. + */ + protected String getClassification(String absolutePath, String line) { + + // default type + String type = "file"; + + // look for colon + int colon = line.indexOf(':'); + + // name appears before colon + String name = line.substring(0, colon); + + // the full type appears after the colon + String fulltype = line.substring(colon + 1, line.length()).trim(); + + // if it is a *.class file, then we look for main method and qulaified class name + // as part of the classification + if (name.endsWith(".class")) { + type = classifyClassFile(absolutePath); + } + + // check if it is a shared library + boolean matchesLib = (fulltype.indexOf("shared object") > -1) || + (fulltype.indexOf("object module") > -1) || + (fulltype.indexOf("archive") > -1); + + // check if it is an executable + boolean matchesExe = (fulltype.indexOf("executable") > -1); + + // check if it is a script + boolean matchesScript = (fulltype.indexOf("script") > -1); + + // shared library + if (matchesLib) { + + // all *.a, *.so and *.so.* files are of type "module" + if (name.endsWith(".a") || name.endsWith(".so") || (name.indexOf(".so.") > 0)) { + type = "module"; + } + } + + // a script file + else if (matchesScript) { + + // an executable script file + if (matchesExe) { + type = "executable(script)"; + } + // non-executable script file + else { + type = "script"; + } + } + + // binary executable + else if (matchesExe) { + type = "executable(binary)"; + } + + // on iSeries we look for "OS/400 object" as a type + else if (fulltype.indexOf("OS/400 object") > -1) { + type = "OS/400 object"; + } + + // finally, if the full type contains the symbolic link string, then type is simply "link" + else if (fulltype.startsWith("symbolic link to")) { + type = "link"; + } + + return type; + } + + /** + * Classifies a class file. + * @param absolutePath the absolute path of the class file. + * @return the classification. + */ + protected String classifyClassFile(String absolutePath) { + + // default type + String type = "file"; + + // input stream to file + FileInputStream stream = null; + + // class file parser + BasicClassFileParser parser = null; + + boolean isExecutable = false; + + try { + stream = new FileInputStream(absolutePath); + + // use class file parser to parse the class file + parser = new BasicClassFileParser(stream); + parser.parse(); + + // query if it is executable, i.e. whether it has main method + isExecutable = parser.isExecutable(); + } + catch (IOException e) { + // TODO: log it + + // we assume not executable + isExecutable = false; + } + + // if it is executable, then also get qualified class name + if (isExecutable) { + type = "executable(java"; + + String qualifiedClassName = parser.getQualifiedClassName(); + + if (qualifiedClassName != null) { + type = type + ":" + qualifiedClassName; + } + + type = type + ")"; + } + + return type; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemSearchString.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemSearchString.java new file mode 100644 index 00000000000..b01bd482812 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/SystemSearchString.java @@ -0,0 +1,153 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + + +/** + * This class represents search string. + */ +public class SystemSearchString { + + /** + * Constant indicating that the depth is infinite, -1. + */ + public static final int DEPTH_INFINITE = -1; + + protected String textString; + protected boolean isCaseSensitive; + protected boolean isTextStringRegex; + protected String fileNamesString; + protected boolean isFileNamesRegex; + protected boolean includeArchives; + protected boolean includeSubfolders; + protected String classificationString; + + /** + * Creates a new search string. + * @param textString the text string. + * @param isCaseSensitive true if the search should be case sensitive, false otherwise. + * @param isTextStringRegex true if the text string is a regular expression, false otherwise. + * @param fileNamesString the file names pattern. + * @param isFileNamesRegex true if the file names string is a regular expression, false otherwise. + * @param includeArchives true to search inside archives, false otherwise. + * @param includeSubfolders true to search subfolders, false otherwise. + */ + public SystemSearchString(String textString, boolean isCaseSensitive, boolean isTextStringRegex, + String fileNamesString, boolean isFileNamesRegex, boolean includeArchives, + boolean includeSubfolders) { + this(textString, isCaseSensitive, isTextStringRegex, fileNamesString, isFileNamesRegex, includeArchives, + includeSubfolders, ""); + } + + /** + * Creates a new search string that allows search to be restricted to files with a certain classification. + * @param textString the text string. + * @param isCaseSensitive true if the search should be case sensitive, false otherwise. + * @param isTextStringRegex true if the text string is a regular expression, false otherwise. + * @param fileNamesString the file names pattern. + * @param isFileNamesRegex true if the file names string is a regular expression, false otherwise. + * @param includeArchives true to search inside archives, false otherwise. + * @param includeSubfolders true to search subfolders, false otherwise. + * @param classificationString the classification string that file classifications should match with. + */ + public SystemSearchString(String textString, boolean isCaseSensitive, boolean isTextStringRegex, + String fileNamesString, boolean isFileNamesRegex, boolean includeArchives, + boolean includeSubfolders, String classificationString) { + this.textString = textString; + this.isCaseSensitive = isCaseSensitive; + this.isTextStringRegex = isTextStringRegex; + this.fileNamesString = fileNamesString; + this.isFileNamesRegex = isFileNamesRegex; + this.includeArchives = includeArchives; + this.includeSubfolders = includeSubfolders; + this.classificationString = classificationString; + } + + /** + * Returns the text string. + * @return the text string. + */ + public String getTextString() { + return textString; + } + + /** + * Returns whether the search is case sensitive. + * @return true if the search is case sensitive, false otherwise. + */ + public boolean isCaseSensitive() { + return isCaseSensitive; + } + + /** + * Returns whether the text string is a regular expression. + * @return true if the text string is a regular expression, false otherwise. + */ + public boolean isTextStringRegex() { + return isTextStringRegex; + } + + /** + * Returns the file names string. + * @return the file names string. + */ + public String getFileNamesString() { + return fileNamesString; + } + + /** + * Returns whether the file names string is a regular expression. + * @return true if the file names string is a regular expression, false otherwise. + */ + public boolean isFileNamesRegex() { + return isFileNamesRegex; + } + + /** + * Returns whether archives should be searched. + * @return true to search archives, false otherwise. + */ + public boolean isIncludeArchives() { + return includeArchives; + } + + /** + * Returns whether subfolders should be searched. + * @return true to search subfolders, false otherwise. + */ + public boolean isIncludeSubfolders() { + return includeSubfolders; + } + + /** + * Returns the classification string that file classifications should match with. + * @return the classification. + */ + public String getClassificationString() { + return classificationString; + } + + /** + * Writes the contents of the search string + * @see java.lang.Object#toString() + */ + public String toString() { + return textString + " - " + isCaseSensitive + " - " + isTextStringRegex + " - " + + fileNamesString + " - " + isFileNamesRegex + " - " + includeArchives + " - " + + includeSubfolders + " - " + classificationString; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/VirtualSearchResult.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/VirtualSearchResult.java new file mode 100644 index 00000000000..10c1be35ca0 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/VirtualSearchResult.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver; + +import org.eclipse.rse.services.clientserver.archiveutils.VirtualChild; + +/** + * @author mjberger + * + * Represents a search result in a virtual file. + */ +public final class VirtualSearchResult +{ + private VirtualChild _virtualChild; + private long _lineNumber; + private String _matchingLine; + + public VirtualSearchResult(VirtualChild vc, long lineNumber, String matchingLine) + { + _virtualChild = vc; + _lineNumber = lineNumber; + _matchingLine = matchingLine; + } + + public long getLineNumber() + { + return _lineNumber; + } + + public String getMatchingLine() { + return _matchingLine; + } + + public VirtualChild getVirtualChild() { + return _virtualChild; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/AbsoluteVirtualPath.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/AbsoluteVirtualPath.java new file mode 100644 index 00000000000..8519cb4feed --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/AbsoluteVirtualPath.java @@ -0,0 +1,138 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +/** + * @author mjberger + * + * Represents an absolute virtual path, which contains a real part + * (the part of the path that locates the containing archive) and a + * virtual part (the part that locates the file in the virtual file + * system within the archive). + */ +public class AbsoluteVirtualPath +{ + + protected AbsoluteVirtualPath _realPart; + protected String _realPartName; + protected String _virtualPart; + protected boolean _isVirtual; + protected String _absVirtualPath; + + /** + * Sets up a new AbsoluteVirtualPath object, by parsing absolutePath + * into a "real" part (the containing archive) and a "virtual" part (the path to + * the entry in the archive). Note that the real part is also an AbsoluteVirtualPath + * in order to account for nested archives. + */ + public AbsoluteVirtualPath(String absolutePath) + { + String sep = ArchiveHandlerManager.VIRTUAL_SEPARATOR; + _absVirtualPath = ArchiveHandlerManager.cleanUpVirtualPath(absolutePath); + int i = _absVirtualPath.lastIndexOf(sep); + if (i == -1) + { + // no more nesting, this is the actual container archive. + _absVirtualPath = absolutePath; // fix for defect 51898 and related defects + _virtualPart = ""; + _realPartName = _absVirtualPath; + _realPart = this; + _isVirtual = false; + } + else + { + // there could be nesting further below, so parse out the real part + // by recursively calling the constructor. + _virtualPart = _absVirtualPath.substring(i+sep.length()); + _realPartName = _absVirtualPath.substring(0,i); + _realPart = new AbsoluteVirtualPath(_realPartName); + _isVirtual = true; + } + } + + /** + * @return Whether or not this AbsoluteVirtualPath is virtual. + */ + public boolean isVirtual() + { + return _isVirtual; + } + + /** + * @return The AbsoluteVirtualPath of the archive that contains the object specified + * by this AbsoluteVirtualPath. Note that the archive can itself be virtual as well. + */ + public AbsoluteVirtualPath getContainingArchivePath() + { + return _realPart; + } + + /** + * @return The name of the AbsoluteVirtualPath of the archive that contains the object + * specified by this AbsoluteVirtualPath. + */ + public String getContainingArchiveString() + { + return _realPartName; + } + + /** + * @return The virtual path to the virtual object referred to by this AbsoluteVirtualPath. + */ + public String getVirtualPart() + { + return _virtualPart; + } + + /** + * Returns this AbsoluteVirtualPath as a string. + */ + public String toString() + { + return _absVirtualPath; + } + + /** + * Sets the virtual part of this AbsoluteVirtualPath to be newVirtualPart + */ + public void setVirtualPart(String newVirtualPart) + { + _virtualPart = newVirtualPart; + if (newVirtualPart == "") + { + int i = _absVirtualPath.lastIndexOf(ArchiveHandlerManager.VIRTUAL_SEPARATOR); + _absVirtualPath = _absVirtualPath.substring(0, i); + _isVirtual = _realPart._isVirtual; + } + else + { + _absVirtualPath = _realPartName + ArchiveHandlerManager.VIRTUAL_SEPARATOR + newVirtualPart; + } + } + + public String getName() + { + return _absVirtualPath.substring(_absVirtualPath.lastIndexOf("/") + 1); + } + + public String getPath() + { + String path = _absVirtualPath.substring(0, _absVirtualPath.lastIndexOf("/")); + return path; + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ArchiveHandlerManager.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ArchiveHandlerManager.java new file mode 100644 index 00000000000..310ed92b9fc --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ArchiveHandlerManager.java @@ -0,0 +1,500 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; + +/** + * This class manages all the Archive Handlers that correspond to the archive file that the system + * would like to deal with. It contains methods for registering handlers with file types, as well as + * utilities for getting at the contents of archives that the Manager represents. + * This class is designed to be a singleton class, so the best way to use it is + * to use statements of the form "ArchiveHandlerManager.getInstance().method". + * @author mjberger + */ +public class ArchiveHandlerManager +{ + // The string that separates the virtual part of an absolute path from the real part + public static final String VIRTUAL_SEPARATOR = "#virtual#/"; + public static final String VIRTUAL_CANONICAL_SEPARATOR = "#virtual#"; + + // the singleton instance + protected static ArchiveHandlerManager _instance = new ArchiveHandlerManager(); + + // a mapping from Files to ISystemArchiveHandlers + protected HashMap _handlers; + + // a mapping from Strings (file extensions) to Classes (the type of handler to use) + protected HashMap _handlerTypes; + + /** + * @return The singleton instance of this class. + */ + public static ArchiveHandlerManager getInstance() + { + return _instance; + } + + public ArchiveHandlerManager() + { + _handlers = new HashMap(); + _handlerTypes = new HashMap(); + } + + /** + * Returns the children of an object in the virtual file system. + * @param file The archive in whose virtual file system the children reside. + * @param virtualpath The parent virtual object whose children this method is to return. To + * get the top level virtualchildren in the archive, set virtualpath to "" or null. + * @return An array of VirtualChild objects representing the children of the virtual object + * in file referred to by virtualpath. If no class implementing + * ISystemArchiveHandler can be found that corresponds to file, then this method returns null. + * If the virtual object has no children, this method also returns null. + * @throws IOException if there was a problem getting the registered handler for the + * file. This usually means the archive is corrupted. + */ + public VirtualChild[] getContents(File file, String virtualpath) throws IOException + { + if (virtualpath == null) virtualpath = ""; + ISystemArchiveHandler handler = getRegisteredHandler(file); + if (handler == null || !handler.exists()) throw new IOException(); + return handler.getVirtualChildren(virtualpath); + } + + /** + * Returns the children of an object in the virtual file system that are folders. + * @param file The archive in whose virtual file system the children reside. + * @param virtualpath The parent virtual object whose children this method is to return. To + * get the top level virtualchildren in the archive, set virtualpath to "" or null. + * @return An array of VirtualChild objects representing the children of the virtual object + * in file referred to by virtualpath that are themselves folders. + * If no class implementing ISystemArchiveHandler can be found that corresponds to file, then + * this method returns null. If the virtual object has no children, this method also returns null. + */ + public VirtualChild[] getFolderContents(File file, String virtualpath) + { + if (virtualpath == null) virtualpath = ""; + ISystemArchiveHandler handler = getRegisteredHandler(file); + if (handler == null) return null; + return handler.getVirtualChildFolders(virtualpath); + } + + /** + * Tests whether a file is an known type of archive. + * @param file the file to test. + * @return true if and only if the file is an archive whose + * type is registered with the ArchiveHandlerManager. + */ + public boolean isArchive(File file) + { + if (_handlers.containsKey(file)) + { + return true; + } + else + { + if (_handlerTypes.containsKey(getExtension(file))) + { + return true; + } + else + { + return false; + } + } + + } + + /** + * Tests whether a file is an known type of archive, based on the file name. + * @param file the name of the file to test. + * @return true if and only if the file is an archive whose + * type is registered with the ArchiveHandlerManager. + */ + public boolean isRegisteredArchive(String filename) + { + if (_handlerTypes.containsKey(getExtension(filename))) + { + return true; + } + else + { + return false; + } + } + /** + * @param file the file whose extension we are computing. + * @return the extension of file. "Extension" is + * defined as any letters in the filename after the last ".". + * Returns "" if there is no extension. + */ + protected String getExtension(File file) + { + String filename = file.getName(); + int i = filename.lastIndexOf("."); + if (i == -1) return ""; + return filename.substring(i+1).toLowerCase(); + } + + /** + * @param filename the name of the file whose extension we are computing. + * @return the extension of filename. "Extension" is + * defined as any letters in the filename after the last ".". + * Returns "" if there is no extension. + */ + protected String getExtension(String filename) + { + int i = filename.lastIndexOf("."); + if (i == -1) return ""; + return filename.substring(i+1).toLowerCase(); + } + + /** + * Given the absolute path to a virtual object, returns that object + * as a VirtualChild. + * @param fullyQualifiedName The absolute path to the object. Usually consists + * of the fullyQualifiedName of the archive, followed by the virtual path separator + * (defined in ArchiveHandlerManager.VIRTUAL_SEPARATOR) followed by the virtual path to + * the object within the archive's virtual file system. + */ + public VirtualChild getVirtualObject(String fullyQualifiedName) + { + String cleanName = cleanUpVirtualPath(fullyQualifiedName); + AbsoluteVirtualPath avp = new AbsoluteVirtualPath(cleanName); + if (!avp.isVirtual()) return new VirtualChild("", new File(avp.getContainingArchiveString())); + String zipfile = avp.getContainingArchiveString(); + File file = new File(zipfile); + ISystemArchiveHandler handler = getRegisteredHandler(file); + if (handler == null) return new VirtualChild(avp.getVirtualPart(), new File(avp.getContainingArchiveString())); + VirtualChild vc = handler.getVirtualFile(avp.getVirtualPart()); + return vc; + } + + /** + * Returns the registered handler for the File file. If + * no handler exists for that file yet, create it. If the extension of + * file is not registered, then returns null. + */ + public ISystemArchiveHandler getRegisteredHandler(File file) + { + ISystemArchiveHandler handler = null; + if (_handlers.containsKey(file)) + { + handler = (ISystemArchiveHandler) _handlers.get(file); + } + + if (handler != null && handler.exists()) + { + return handler; + } + else { + // find registered handler based on file's extension + String ext = getExtension(file); + if (!_handlerTypes.containsKey(ext)) + { + System.out.println("Unknown archive file type: " + ext); + return null; + } + else + { + Class handlerType = (Class) _handlerTypes.get(ext); + Constructor newHandlerType = getProperConstructor(handlerType); + Object[] files = new Object[1]; + files[0] = file; + try + { + handler = (ISystemArchiveHandler) newHandlerType.newInstance(files); + } + catch (InvocationTargetException e) + { + Throwable target = e.getCause(); + System.out.println(e.getMessage()); + e.printStackTrace(); + System.out.println("Could not instantiate handler for " + file.getName()); + return null; + + } + catch (Exception e) + { + System.out.println(e.getMessage()); + System.out.println("Could not instantiate handler for " + file.getName()); + return null; + } + _handlers.put(file, handler); + return handler; + } + } + } + + public Constructor getProperConstructor(Class handlerType) + { + Constructor[] constructors = handlerType.getConstructors(); + for (int i = 0; i < constructors.length; i++) + { + if (constructors[i].getParameterTypes().length != 1) + { + continue; + } + else if (!constructors[i].getParameterTypes()[0].equals(File.class)) + { + continue; + } + else return constructors[i]; + } + return null; // should never get to this point + } + + /** + * Registers an extension and a handler type. + * @param ext The extension to register with the ArchiveHandlerManager + * @param handlerType The class of handler to register with ext. + * Note that any class passed in must implement ISystemArchiveHandler. + * @return Whether or not the registration was successful. + */ + public boolean setRegisteredHandler(String ext, Class handlerType) + { + if (!handlerHasProperConstructor(handlerType)) + { + System.out.println("Cannot register archive handler " + handlerType); + System.out.println(handlerType + " does not contain a constructor whose signature is 'Constructor(File file)'"); + return false; + } + if (handlerImplementsISystemArchiveHandler(handlerType)) + { + if (_handlerTypes.containsKey(ext)) _handlerTypes.remove(ext); + _handlerTypes.put(ext, handlerType); + return true; + } + else + { + System.out.println("Cannot register archive handler " + handlerType); + System.out.println("Neither " + handlerType + ", nor any of its superclasses implements ISystemArchiveHandler."); + return false; + } + } + + /** + * Returns whether or not handlerType has a constructor that takes only one + * parameter, a java.io.File. + */ + protected boolean handlerHasProperConstructor(Class handlerType) + { + Constructor[] constructors = handlerType.getConstructors(); + boolean ok = false; + for (int i = 0; i < constructors.length; i++) + { + if (constructors[i].getParameterTypes().length == 1) + { + if (constructors[i].getParameterTypes()[0].equals(File.class)) + { + ok = true; + break; + } + } + } + return ok; + } + + /** + * Returns whether or not handlerType or one of its superclasses implements ISystemArchiveHandler. + */ + protected boolean handlerImplementsISystemArchiveHandler(Class handlerType) + { + Class[] interfaces = handlerType.getInterfaces(); + boolean okay = false; + for (int i = 0; i < interfaces.length; i++) + { + if (interfaces[i].getName().equals(ISystemArchiveHandler.class.getName())) okay = true; + } + if (!okay) + { + Class superclass = handlerType.getSuperclass(); + if (superclass.getName().equals(Object.class.getName())) return false; + return handlerImplementsISystemArchiveHandler(superclass); + } + else return true; + } + + /** + * Removes the handler associated with file, freeing the file + * to be used by other processes. + */ + public void disposeOfRegisteredHandlerFor(File file) + { + _handlers.remove(file); + } + + /** + * Tests whether the absolute path given by path + * refers to a virtual object. + * @param path + * @return True if and only if the absolute path refers to a virtual object. + */ + public static boolean isVirtual(String path) + { + return path.indexOf(VIRTUAL_CANONICAL_SEPARATOR) != -1; + } + + /** + * Converts the virtual path given by fullVirtualName + * to the standard virtual form ('/' as separator, no leading or trailing '/'s) + * @param fullVirtualName the path to convert + * @return the new path in standard form + */ + public static String cleanUpVirtualPath(String fullVirtualName) + { + int j = fullVirtualName.indexOf(VIRTUAL_CANONICAL_SEPARATOR); + if (j == -1 && fullVirtualName.indexOf(":") != -1) return fullVirtualName; + String realPart = ""; + String newPath = fullVirtualName; + if (j != -1) + { + realPart = fullVirtualName.substring(0, j) + VIRTUAL_SEPARATOR; + newPath = fullVirtualName.substring(j + VIRTUAL_SEPARATOR.length()); + } + // use only forward slash separator + newPath = newPath.replace('\\', '/'); + + //get rid of any double slashes + int i = newPath.indexOf("//"); + while (i != -1) + { + newPath = newPath.substring(0,i) + newPath.substring(i+1); + i = newPath.indexOf("//"); + } + + // get rid of any leading or trailing slashes + if (j != -1 && newPath.startsWith("/")) newPath = newPath.substring(1); + if (newPath.endsWith("/")) newPath = newPath.substring(0, newPath.length() - 1); + return realPart + newPath; + } + + /** + * Disposes of all registered handlers. + */ + public void dispose() + { + _handlers.clear(); + } + + public boolean createEmptyArchive(File newFile) + { + if (!isRegisteredArchive(newFile.getName())) + { + System.out.println("Could not create new archive."); + System.out.println(newFile + " is not a registered type of archive."); + return false; + } + + if (newFile.exists()) + { + if (!newFile.isFile()) + { + System.out.println("Could not create new archive."); + System.out.println(newFile + " is not a file."); + return false; + } + if (!newFile.delete()) + { + System.out.println("Could not create new archive."); + System.out.println(newFile + " could not be deleted."); + return false; + } + } + + try + { + if (!newFile.createNewFile()) + { + System.out.println("Could not create new archive."); + System.out.println(newFile + " could not be created."); + return false; + } + } + catch (IOException e) + { + System.out.println("Could not create new archive."); + System.out.println(e.getMessage()); + return false; + } + + ISystemArchiveHandler handler = getRegisteredHandler(newFile); + return handler.create(); + } + + /** + * Returns the extensions for archive types that have been registered + * with the ArchiveHandlerManager. + */ + public String[] getRegisteredExtensions() + { + Object[] exts = _handlerTypes.keySet().toArray(); + String[] extensions = new String[exts.length]; + for (int i = 0; i < exts.length; i++) + { + extensions[i] = (String) exts[i]; + } + return extensions; + } + + public String getComment(File archive) + { + ISystemArchiveHandler handler = getRegisteredHandler(archive); + if (handler == null || !handler.exists()) return ""; + return handler.getArchiveComment(); + } + + public long getExpandedSize(File archive) + { + ISystemArchiveHandler handler = getRegisteredHandler(archive); + if (handler == null || !handler.exists()) return 0; + VirtualChild[] allEntries = handler.getVirtualChildrenList(); + int total = 0; + for (int i = 0; i < allEntries.length; i++) + { + total += allEntries[i].getSize(); + } + return total; + } + + /** + * Returns the classification for the entry in a archive with the given virtual path. + * @param file the archive file. + * @param virtualPath the virtual path. + * @return the classification for the virtual file. + */ + public String getClassification(File file, String virtualPath) { + + // if archive file is null, or if it does not exist, or if the virtual path + // is null, then return null for the classification + if (file == null || !file.exists()) { + return null; + } + + // get archive handler + ISystemArchiveHandler handler = getRegisteredHandler(file); + + if (handler == null || !handler.exists()) { + return null; + } + + return handler.getClassification(virtualPath); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandler.java new file mode 100644 index 00000000000..f7ae942d198 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandler.java @@ -0,0 +1,371 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.File; +import java.io.InputStream; + +import org.eclipse.rse.services.clientserver.ISystemFileTypes; +import org.eclipse.rse.services.clientserver.search.SystemSearchLineMatch; +import org.eclipse.rse.services.clientserver.search.SystemSearchStringMatcher; + + +/** + * @author mjberger + * An interface that allows implementing classes to create their own + * Handlers for various types of Archive files, ie: zip, jar, tar, rpm + */ +public interface ISystemArchiveHandler +{ + + /** + * Turns the archive that this handler represents into a new, empty archive. + * (The archive could not exist before, in which case this would be a true + * creation). + * @return Whether or not the blank archive was successfuly created. + */ + public boolean create(); + + /** + * @return an array containing all the entries in the archive file + * in a flat format, where the entries' filenames are prepended by + * the path to the entry within the virtual file system. If there + * are no entries in the file, returns an array of size 0. + */ + public VirtualChild[] getVirtualChildrenList(); + + /** + * @return an array containing all the entries in the archive file + * in a flat format, whose full paths begin with the String parent. + * Returns an array of length 0 if there are no such entries. + */ + public VirtualChild[] getVirtualChildrenList(String parent); + + /** + * @return an array containing the virtual children of the virtual + * directory named fullVirtualName. If fullVirtualName is "", + * returns the top level in the virtual file system tree. If there are no + * values to return, returns null. + */ + public VirtualChild[] getVirtualChildren(String fullVirtualName); + + /** + * @return an array containing the virtual children of the virtual + * directory named fullVirtualName that are themselves directories. + * If fullVirtualName is "", + * returns the top level of directories in the virtual file system tree. + * If there are no values to return, returns null. + */ + public VirtualChild[] getVirtualChildFolders(String fullVirtualName); + + /** + * @return the virtual File or Folder referred to by fullVirtualName. + * This method never returns null. In cases where the VirtualChild does not + * physically exist in the archive, this method returns a new VirtualChild object + * whose exists() method returns false. + */ + public VirtualChild getVirtualFile(String fullVirtualName); + + /** + * @return Whether or not the virtual file or folder named fullVirtualName + * exists in the archive (physically). + */ + public boolean exists(String fullVirtualName); + + /** + * @return Whether or not the handler exists. Usually false if the archive + * is corrupted or unreadable. + */ + public boolean exists(); + + /** + * @return the archive that this handler deals with + */ + public File getArchive(); + + /** + * @return the current timestamp (last modified) for the entry in the archive named + * fullVirtualName + */ + public long getTimeStampFor(String fullVirtualName); + + /** + * @return the current size (uncompressed) for the entry in the archive named + * fullVirtualName + */ + public long getSizeFor(String fullVirtualName); + + /** + * Extracts the virtual file named fullVirtualName from the archive, + * placing the results in destination. + * @param fullVirtualName The full path and name of the virtual file in the archive. + * @param destination The destination file for the extracted virtual file. + * @return true iff the extraction is successful + */ + public boolean extractVirtualFile(String fullVirtualName, File destination); + + /** + * Extracts the virtual file named fullVirtualName from the archive, + * placing the results in destination. Extracts to the native encoding, but assumes + * that the source was archived using sourceEncoding if isText is true. + * @param fullVirtualName The full path and name of the virtual file in the archive. + * @param destination The destination file for the extracted virtual file. + * @param sourceEncoding The encoding of the file in the archive. + * @param isText Whether or not the virtual file is a text file. + * @return true iff the extraction is successful + */ + public boolean extractVirtualFile(String fullVirtualName, File destination, String sourceEncoding, boolean isText); + + /** + * Extracts the directory dir (and its children) from + * the archive and places the results in the directory destinationParent. + * @param dir The full name of the virtual directory to extract + * @param destinationParent A handle to the directory in which the extracted + * directory will be placed as a subdirectory. + * @return true iff the extraction is successful + */ + public boolean extractVirtualDirectory(String dir, File destinationParent); + + /** + * Extracts the directory dir (and its children) from + * the archive and places the results in the directory destinationParent. + * Extracts to the native encoding (if isText), but assumes + * that the source was archived using sourceEncoding. + * @param dir The full name of the virtual directory to extract + * @param destinationParent A handle to the directory in which the extracted + * directory will be placed as a subdirectory. + * @param sourceEncoding The encoding of the files in the archive. + * @param isText Whether or not the files in the directory are text files + * @return true iff the extraction is successful + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, String sourceEncoding, boolean isText); + + /** + * Extracts the directory dir (and its children) from + * the archive and places the results in the directory destinationParent. + * The results will be named destination.getName() rather than dir's name. + * @param dir The full name of the virtual directory to extract + * @param destinationParent A handle to the directory in which the extracted + * directory will be placed as a subdirectory. + * @param destination A handle to the directory that will be created. Whatever + * contents are in that directory will be replaced with what is extracted from + * the archive. + * @return true iff the extraction is successful + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, File destination); + + /** + * Extracts the directory dir (and its children) from + * the archive and places the results in the directory destinationParent. + * The results will be named destination.getName() rather than dir's name. + * Extracts to the native encoding (if isText), but assumes + * that the source was archived using sourceEncoding. + * @param dir The full name of the virtual directory to extract + * @param destinationParent A handle to the directory in which the extracted + * directory will be placed as a subdirectory. + * @param destination A handle to the directory that will be created. Whatever + * contents are in that directory will be replaced with what is extracted from + * the archive. + * @param sourceEncoding The encoding of the files in the archive. + * @param isText Whether or not the files to be extracted in the directory are all text files + * @return true iff the extraction is successful + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, File destination, String sourceEncoding, boolean isText); + + /** + * Compresses the file file and adds it to the archive, + * placing it in the virtual directory virtualPath. Pass the + * name as the parameter name. If the virtual path does not exist + * in the archive, create it. If file is a directory, copy it and + * its contents into the archive, maintaining the tree structure. + * @return true if and only if the add was successful + */ + public boolean add(File file, String virtualPath, String name); + + /** + * Compresses the file file and adds it to the archive, + * saving it in the encoding specified by encoding if the isText is true. + * placing it in the virtual directory virtualPath. Pass the + * name as the parameter name. If the virtual path does not exist + * in the archive, create it. If file is a directory, copy it and + * its contents into the archive, maintaining the tree structure. + * @return true if and only if the add was successful + */ + public boolean add(File file, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText); + + /** + * Compresses the bytes in the InputStream stream and adds them as an entry to the archive, + * saving them in the encoding specified by encoding if isText is true, and + * placing it in the virtual directory virtualPath. Pass the + * name as the parameter name. If the virtual path does not exist + * in the archive, create it. + * @return true if and only if the add was successful + */ + public boolean add(InputStream stream, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText); + + /** + * Compresses the file file and adds it to the archive, + * saving it in the encoding specified by encoding if the isText is true. + * placing it in the virtual directory virtualPath. Pass the + * name as the parameter name. If the virtual path does not exist + * in the archive, create it. If file is a directory, copy it and + * its contents into the archive, maintaining the tree structure. + * @return true if and only if the add was successful + */ + public boolean add(File file, String virtualPath, String name, String sourceEncoding, String targetEncoding, ISystemFileTypes typeRegistery); + + /** + * A generalization of the add method. + * Compresses the array of files files and adds each of them to the archive, placing them + * in the virtual directory virtualPath. Pass the names of the files + * as the parameter names, where files[i] has the name names[i]. + * If the virtual path does not exist in the archive, create it. + * @return true if and only if the add was successful + */ + public boolean add(File[] files, String virtualPath, String[] names); + + /** + * A generalization of the add method. + * Compresses the array of files files and adds each of them to the archive, placing them + * in the virtual directory virtualPath. Save the i'th file in the i'th encoding (if isText[i] is true) + * specified by encodings. Pass the names of the files + * as the parameter names, where files[i] has the name names[i]. + * If the virtual path does not exist in the archive, create it. + * @return true if and only if the add was successful + */ + public boolean add(File[] files, String virtualPath, String[] names, String[] sourceEncodings, String[] targetEncodings, boolean[] isText); + + /** + * Compress the file file and replace the virtual file + * referred to by fullVirtualName with the compressed file. + * Pass the name of the file as the parameter name. + * @return true if and only if the replace was successful + */ + public boolean replace(String fullVirtualName, File file, String name); + + /** + * Compress the InputStream stream and replace the virtual file + * referred to by fullVirtualName with the compressed stream. + * Pass the name of the new entry as the parameter name, the + * encoding of the entry as encoding and whether or not the entry + * isText or not. + * @return true if and only if the replace was successful + */ + public boolean replace(String fullVirtualName, InputStream stream, String name, String sourceEncoding, String targetEncoding, boolean isText); + + /** + * Deletes the entry fullVirtualName from the archive, and returns + * whether or not the deletion was successful. + */ + public boolean delete(String fullVirtualName); + + /** + * Renames the entry fullVirtualName to the new name + * newName while still leaving the entry in the same virtual + * directory. Returns true if and only if the rename was successfull. + */ + public boolean rename(String fullVirtualName, String newName); + + /** + * Moves the entry fullVirtualName to the location + * specified by destinationVirtualPath, while leaving the entry with + * the same name as before. Returns true if and only if the move was successfull. + */ + public boolean move(String fullVirtualName, String destinationVirtualPath); + + /** + * Replaces the full name and path of the entry fullVirtualName + * with the new full name and path newFullVirtualName. + * Returns true if and only if the operation was successfull. + */ + public boolean fullRename(String fullVirtualName, String newFullVirtualName); + + /** + * Extracts and returns the specified list of virtual files from the archive. + * @param fullNames The list of files to return + * @return An array of handles to the extracted files. If fullNames has length 0 + * then this method returns an array of length 0. + */ + public File[] getFiles(String[] fullNames); + + /** + * Creates a new, empty folder in the archive. If parent folders do not exist either, creates them. + * @param fullVirtualName The full name and path of the new folder within the virtual file system. + * @return Whether or not the creation was successful. + */ + public boolean createFolder(String fullVirtualName); + + /** + * Creates a new, empty file in the archive. If parent folders do not exist either, creates them. + * @param fullVirtualName The full name and path of the new file within the virtual file system. + * @return Whether or not the creation was successful. + */ + public boolean createFile(String fullVirtualName); + + /** + * Gets the archive-type specific standard name for the VirtualChild + * vc. For example, for Zips, if vc is a directory, then + * the standard name must end with a "/". + */ + public String getStandardName(VirtualChild vc); + + /** + * Searches for text within a virtual file in this archive. + * A good implementation will not actually extract the file to disk. + * @param fullVirtualName the virtual file to search. + * @param matcher the pattern matcher to use. + * @return an array of match objects corresponding to lines where matches were found. + * Returns an empty array if there are no results. + */ + public SystemSearchLineMatch[] search(String fullVirtualName, SystemSearchStringMatcher matcher); + + /** + * Gets the user-defined comment for a specific entry in the archive. + * @param fullVirtualName The entry who's comment is desired + * @return the comment as a String or "" if there is none + */ + public String getCommentFor(String fullVirtualName); + + /** + * Gets the amount of space taken up by a specific entry in the archive + * when it is in compressed form. Compare with getSizeFor(String) which gets + * the size of the entry after it is decompressed. + * @param fullVirtualName The entry who's compressed size is desired + * @return the compressed size of the specified entry, or 0 if the entry is not + * found. If the archive is not a compression type (ie. tar), return the same as getSizeFor(String). + */ + public long getCompressedSizeFor(String fullVirtualName); + + /** + * Gets the method used to compress a specific entry in the archive. + * @param fullVirtualName The entry who's compression method is desired + * @return The compression method of the specified entry, or "" if none. + */ + public String getCompressionMethodFor(String fullVirtualName); + + /** + * @return The comment associated with this archive, or "" if there is none. + */ + public String getArchiveComment(); + + /** + * Returns the classification for the entry with the given path. + * @param fullVirtualName the virtual name. + * @return the classification. + */ + public String getClassification(String fullVirtualName); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandlerConstants.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandlerConstants.java new file mode 100644 index 00000000000..0091603918c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/ISystemArchiveHandlerConstants.java @@ -0,0 +1,38 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +/** + * Interface for general archive handler constants. + */ +public interface ISystemArchiveHandlerConstants { + + /** + * Zip archive extension, "zip". + */ + public static final String ZIP_ARCHIVE_EXTENSION = "zip"; + + /** + * Jar archive extension, "jar". + */ + public static final String JAR_ARCHIVE_EXTENSION = "jar"; + + /** + * Tar archive extension, "tar". + */ + public static final String TAR_ARCHIVE_EXTENSION = "tar"; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemArchiveUtil.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemArchiveUtil.java new file mode 100644 index 00000000000..ffe8f90156d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemArchiveUtil.java @@ -0,0 +1,67 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.File; +import java.util.HashSet; + +public class SystemArchiveUtil { + + /** + * Helper method to delete a directory. Deletes the children of the directory before + * deleting the directory itself. This method is required because a directory can not be deleted if it + * is not empty. + * @return true if the deletion was successful, false otherwise. + */ + public static boolean delete(File file) { + HashSet set = new HashSet(); + return recursiveDelete(file, set); + } + + /** + * Recursively delete a file. + * @param file the file or directory. + * @param found a set of files that have been considered. + * @return true if deletion successful, false otherwise. + */ + protected static boolean recursiveDelete(File file, HashSet found) { + boolean success = true; + found.add(file); + File[] children = file.listFiles(); + + if (children != null) { + + for (int i = 0; i < children.length; i++) { + + if (!found.contains(children[i])) { + + success = recursiveDelete(children[i], found); + + if (!success) { + return false; + } + } + } + } + + if (file.exists()) { + success = file.delete(); + } + + return success; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemJarHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemJarHandler.java new file mode 100644 index 00000000000..660386b3812 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemJarHandler.java @@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.File; +import java.io.IOException; + +/** + * @author mjberger + * Implements an ISystemArchiveHandler for Java JAR files. + */ +public class SystemJarHandler extends SystemZipHandler +{ + + public SystemJarHandler(File file) throws IOException + { + super(file); + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemTarHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemTarHandler.java new file mode 100644 index 00000000000..5c71200a163 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemTarHandler.java @@ -0,0 +1,2262 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Vector; + +import org.eclipse.rse.services.clientserver.ISystemFileTypes; +import org.eclipse.rse.services.clientserver.java.BasicClassFileParser; +import org.eclipse.rse.services.clientserver.search.SystemSearchLineMatch; +import org.eclipse.rse.services.clientserver.search.SystemSearchStringMatchLocator; +import org.eclipse.rse.services.clientserver.search.SystemSearchStringMatcher; +import org.eclipse.rse.services.clientserver.util.tar.ITarConstants; +import org.eclipse.rse.services.clientserver.util.tar.TarEntry; +import org.eclipse.rse.services.clientserver.util.tar.TarFile; +import org.eclipse.rse.services.clientserver.util.tar.TarOutputStream; + + +/** + * This class deals with tar files. + */ +public class SystemTarHandler implements ISystemArchiveHandler { + + protected File file; + protected long modTimeDuringCache; + protected VirtualFileSystem vfs; + + /** + * This class represents a virtual file system. A virtual file system is simply a data structure that + * helps manage the contents of an archive file. It provides services that a handler can use. + */ + private class VirtualFileSystem { + + private VirtualFileNode rootNode; + + /** + * Constructor for the virtual file system. + * @param root the root entry. + */ + public VirtualFileSystem(VirtualChild root) { + this.rootNode = new VirtualFileNode(root); + } + + /** + * Adds the entry to the tree according to its full path. Creates the parents + * of the entry if they don't exist. + * If the entry already exists in the tree, it is overwritten. + * @param entry the entry to be added to the tree. + */ + public void addEntry(VirtualChild entry) { + addEntry(entry, true); + } + + /** + * Adds the entry to the tree according to its full path. Creates the parents + * of the entry if they don't exist. + * @param entry the entry to be added to the tree. + * @param replace whether to replace if an entry with the same path + * already exists in the tree. + */ + public void addEntry(VirtualChild entry, boolean replace) { + + String path = entry.fullName; + + VirtualFileNode parentNode = rootNode; + + int idx = path.indexOf("/"); + String name = path; + + String segPath = ""; + + // ensure each segment exists or is created if it does not exist + while (idx > 0) { + name = path.substring(0, idx); + path = path.substring(idx+1); + + segPath = segPath + name + "/"; + + boolean exists = parentNode.childExists(name); + + // only create new parent if it does not already exist + if (!exists) { + VirtualChild child = new VirtualChild(SystemTarHandler.this, segPath); + child.isDirectory = true; + parentNode.addChild(name, new VirtualFileNode(child), true); + } + + // the new parent is the child (which may have been created) + parentNode = parentNode.getChild(name); + + idx = path.indexOf("/"); + } + + parentNode.addChild(path, new VirtualFileNode(entry), replace); + } + + /** + * Removes the entry from the tree. + * @param entry the entry to be removed from the tree. + * @return the removed virtual child, or null if the entry + * does not exist. + */ + public VirtualChild removeEntry(VirtualChild entry) { + return removeEntry(entry.fullName); + } + + /** + * Removes the entry with the given path from the tree. + * @param path path of the entry to be removed from the tree. + * @return the removed virtual child, or null if the entry + * does not exist. + */ + public VirtualChild removeEntry(String path) { + + // strip out trailing separator + if (path.charAt(path.length()-1) == '/') { + path = path.substring(0, path.length()-1); + } + + // get the parent node + VirtualFileNode parent = getParentNode(path); + + // get the name of the entry + String name = null; + + int idx = path.lastIndexOf('/'); + + if (idx == -1) { + name = path; + } + else { + name = path.substring(idx+1); + } + + // remove the entry from the parent + VirtualFileNode removedChild = parent.removeChild(name); + + if (removedChild == null) { + return null; + } + else { + return removedChild.getEntry(); + } + } + + /** + * Gets an entry from the given path. + * @param path the path of the entry. + * @return the entry, or null if the entry does not exist. + */ + public VirtualChild getEntry(String path) { + VirtualFileNode node = getNode(path); + + if (node == null) { + return null; + } + else { + return node.getEntry(); + } + } + + /** + * Returns an array of children of the given entry. + * @param entry the parent entry. + * @return an array of children, or an empty array if none exists. Returns null + * if the parent entry isn't a directory. + */ + public VirtualChild[] getChildren(VirtualChild entry) { + return getChildren(entry.fullName); + } + + /** + * Returns an array of children folders of the given entry. + * @param entry the parent entry. + * @return an array of children, or an empty array if none exists. Returns null + * if the parent entry isn't a directory. + */ + public VirtualChild[] getChildrenFolders(VirtualChild entry) { + return getChildrenFolders(entry.fullName); + } + + /** + * Returns an array of children of the entry with the given path. + * @param the path of the parent entry, or "" to indicate the root entry. + * @return an array of children, or an empty array if none exists, or if the entry is not a directory. + */ + public VirtualChild[] getChildren(String path) { + VirtualFileNode node = getNode(path); + + if (node == null) { + return new VirtualChild[0]; + } + + VirtualFileNode[] childNodes = node.getChildren(); + VirtualChild[] children = new VirtualChild[childNodes.length]; + + for (int i = 0; i < children.length; i++) { + children[i] = childNodes[i].getEntry(); + } + + return children; + } + + /** + * Returns an array of children folders of the entry with the given path. + * @param the path of the parent entry, or "" to indicate the root entry. + * @return an array of children, or an empty array if none exists, or if the entry is not a directory. + */ + public VirtualChild[] getChildrenFolders(String path) { + VirtualFileNode node = getNode(path); + VirtualFileNode[] childNodes = node.getChildrenFolders(); + VirtualChild[] children = new VirtualChild[childNodes.length]; + + for (int i = 0; i < children.length; i++) { + children[i] = childNodes[i].getEntry(); + } + + return children; + } + + /** + * Gets the parent entry. + * @param entry the entry whose parent we want. + * @return the parent of the entry, or null if the parent does not exist. + */ + public VirtualChild getParent(VirtualChild entry) { + VirtualFileNode node = getParentNode(entry.fullName); + + if (node == null) { + return null; + } + else { + return node.getEntry(); + } + } + + /** + * Returns the parent node for the entry with the given path. + * @param path the path of the entry whose parent we want. + * @return the node representing the parent entry, or null if the parent + * node doesn't exist. + */ + private VirtualFileNode getParentNode(String path) { + + // strip out trailing separator + if (path.charAt(path.length()-1) == '/') { + path = path.substring(0, path.length()-1); + } + + int idx = path.lastIndexOf('/'); + + if (idx == -1) { + return rootNode; + } + else { + return getNode(path.substring(0, idx)); + } + } + + /** + * Returns the node representing the entry with the given path. + * @param path the path of the entry, or "" to indicate the root node. + * @return the node at the given path, or null if no such node exists. + */ + private VirtualFileNode getNode(String path) { + + if (path.equals("")) { + return rootNode; + } + + // strip out trailing separator + if (path.charAt(path.length()-1) == '/') { + path = path.substring(0, path.length()-1); + } + + int idx = 0; + int jdx = 0; + VirtualFileNode tempNode = rootNode; + boolean done = false; + + while (true) { + jdx = path.indexOf('/', idx); + + if (jdx == -1) { + jdx = path.length(); + done = true; + } + + String tempName = path.substring(idx, jdx); + tempNode = tempNode.getChild(tempName); + + if (tempNode == null) { + return null; + } + + if (!done) { + idx = jdx + 1; + } + else { + break; + } + } + + return tempNode; + } + } + + /** + * This class represents a node in the tree. + */ + private class VirtualFileNode { + + private static final int MODE_ALL = 1; + private static final int MODE_FILES_ONLY = 2; + private static final int MODE_FOLDERS_ONLY = 3; + + private VirtualChild entry; + private HashMap map; + private boolean isDir; + + /** + * Constructor for the virtual file node. + * @param name the name of the node. + * @param entry the entry that this node represents. + */ + public VirtualFileNode(VirtualChild entry) { + this.entry = entry; + this.isDir = entry.isDirectory; + this.map = new HashMap(); + } + + /** + * Returns the entry represented by this node. + * @return the entry represented by this node. + */ + public VirtualChild getEntry() { + return entry; + } + + /** + * Returns whether the node represents a directory or a file. + * @return true if the node represents a directory, false otherwise; + */ + public boolean isDir() { + return isDir; + } + + /** + * Adds a child if this node is a directory. + * @param childName the name with which to identify the child. + * @param child the child. + * @param replace true to replace an existing child with the same + * name (if any), false otherwise. If true, and there + * is an existing child that is a directory, then its children will be added to + * to the new child. + */ + public void addChild(String childName, VirtualFileNode child, boolean replace) { + + if (isDir) { + + // if replace is true, replace an existing node (if any) with this one + // note that is a + if (replace) { + + // get the existing child + VirtualFileNode oldChild = getChild(childName); + + // if there is an existing child which is a directory, and we want to replace it + // with a directory + if (oldChild != null && oldChild.isDir() && child.isDir()) { + Iterator iter = oldChild.getChildrenNames(); + + while (iter.hasNext()) { + String name = (String)(iter.next()); + VirtualFileNode grandChild = oldChild.getChild(name); + child.addChild(name, grandChild, true); + } + } + + map.put(childName, child); + } + // otherwise first check if it already exists, and only add if it doesn't + else { + boolean exists = childExists(childName); + + if (!exists) { + map.put(childName, child); + } + } + } + } + + /** + * Removes the child with the given name only if the node is a directory. + * @param childName the name of the child. + * @return the child that was removed, or null if a child with + * the given name wasn't found or this node isn't a directory. + */ + public VirtualFileNode removeChild(String childName) { + + if (isDir) { + return (VirtualFileNode)map.remove(childName); + } + else { + return null; + } + } + + /** + * Gets the child with the given name. + * @param childName the name of the child. + * @return the child with the given name, or null if a child with + * the given name wasn't found or this node isn't a directory. + */ + public VirtualFileNode getChild(String childName) { + + if (isDir) { + return (VirtualFileNode)map.get(childName); + } + else { + return null; + } + } + + /** + * Returns an array of children. + * @return an array of children, or an empty array if none exists, or if the node is not a directory. + */ + public VirtualFileNode[] getChildren() { + return getChildren(MODE_ALL); + } + + /** + * Returns an array of children that are folders. + * @return an array of children, or an empty array if none exists, or if the node is not a directory. + */ + public VirtualFileNode[] getChildrenFolders() { + return getChildren(MODE_FOLDERS_ONLY); + } + + /** + * Returns an array of children. + * @param mode the mode. One of MODE_ALL, MODE_FILES_ONLY and MODE_FOLDERS_ONLY. + * @return an array of children, or an empty array if none exists, or if the node is not a directory. + */ + public VirtualFileNode[] getChildren(int mode) { + + if (isDir) { + + // if we want all children (i.e. files and folders), then this + // is probably quicker than getting each value and casting + if (mode == MODE_ALL) { + int num = map.size(); + VirtualFileNode[] children = new VirtualFileNode[num]; + map.values().toArray(children); + return children; + } + // either we want only files or only folders + else { + Vector v = new Vector(); + Iterator iter = map.values().iterator(); + + while (iter.hasNext()) { + VirtualFileNode node = (VirtualFileNode)iter.next(); + boolean isDir = node.isDir(); + + if (mode == MODE_FILES_ONLY && !isDir) { + v.add(node); + } + else if (mode == MODE_FOLDERS_ONLY && isDir) { + v.add(node); + } + } + + VirtualFileNode[] children = new VirtualFileNode[v.size()]; + v.toArray(children); + return children; + } + } + else { + return new VirtualFileNode[0]; + } + } + + /** + * Returns whether the child with the given name exists. + * @param childName the name of the child. + * @return true if the child exists, falseotherwise. + * Returns false if this node isn't a directory. + */ + public boolean childExists(String childName) { + + if (isDir) { + return map.containsKey(childName); + } + else { + return false; + } + } + + /** + * Returns an iterator of the names of all the children of this node. + * @return a iterator of all the names of the children, or null if the node + * is not a directory. + */ + public Iterator getChildrenNames() { + + if (isDir) { + return map.keySet().iterator(); + } + else { + return null; + } + } + } + + /** + * Constructor for handler. Calls init. + * @param file the tar file. + */ + public SystemTarHandler(File file) throws IOException { + super(); + init(file); + createCache(); + modTimeDuringCache = file.lastModified(); + } + + /** + * Initializes the handler from the given file and does caching. + * @param file + * @throws IOException + */ + protected void init(File file) throws IOException { + this.file = file; + } + + /** + * Reads the contents of the tar file, and caches the entries. + */ + protected void createCache() { + + TarFile tarFile = getTarFile(); + + Enumeration entries = tarFile.entries(); + + VirtualChild root = new VirtualChild(this); + root.isDirectory = true; + + vfs = new VirtualFileSystem(root); + + while (entries.hasMoreElements()) { + TarEntry entry = (TarEntry)entries.nextElement(); + VirtualChild child = getVirtualChild(entry); + vfs.addEntry(child); + } + } + + /** + * Gets a tar file from the underlying file. + * @return the tar file, or null if the tar file does not exist. + */ + protected TarFile getTarFile() { + + TarFile tarFile = null; + + try { + tarFile = new TarFile(file); + } + catch (IOException e) { + // TODO: log error + } + + return tarFile; + } + + /** + * Updates the cache if the tar file has changed since the last time + * we cached. Will not change the cache if the tar file hasn't been + * updated. Other methods should call this method before performing + * any operations on the cache and the underlying tar file. + */ + protected void updateCache() throws IOException { + File newFile = new File(file.getAbsolutePath()); + long modTime = newFile.lastModified(); + + // if the modified time of the file is not the same as the modified time before last + // cache, then recreate cache + if (modTime != modTimeDuringCache) { + // reinitialize + init(newFile); + createCache(); + modTimeDuringCache = newFile.lastModified(); + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildrenList() + */ + public VirtualChild[] getVirtualChildrenList() { + + // this method does not read from cache + Vector v = new Vector(); + + TarFile tarFile = getTarFile(); + Enumeration entries = tarFile.entries(); + + while (entries.hasMoreElements()) { + TarEntry entry = (TarEntry)entries.nextElement(); + VirtualChild child = new VirtualChild(this, entry.getName()); + child.isDirectory = entry.isDirectory(); + v.add(child); + } + + int numOfChildren = v.size(); + + VirtualChild[] children = new VirtualChild[numOfChildren]; + + for (int i = 0; i < numOfChildren; i++) { + children[i] = (VirtualChild)v.get(i); + } + + return children; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildrenList(java.lang.String) + */ + public VirtualChild[] getVirtualChildrenList(String parent) { + parent = ArchiveHandlerManager.cleanUpVirtualPath(parent); + + // this method does not read from cache + Vector v = new Vector(); + + TarFile tarFile = getTarFile(); + Enumeration entries = tarFile.entries(); + + while (entries.hasMoreElements()) { + TarEntry entry = (TarEntry)entries.nextElement(); + + // only add those entries that have names that begin with the parent name + // also check that the entry name isn't just the parent name + '/' (i.e. still the same + // as the parent) + if (entry.getName().startsWith(parent) && !entry.getName().equals(parent + "/")) { + VirtualChild child = new VirtualChild(this, entry.getName()); + child.isDirectory = entry.isDirectory(); + v.add(child); + } + } + + int numOfChildren = v.size(); + + VirtualChild[] children = new VirtualChild[numOfChildren]; + + for (int i = 0; i < numOfChildren; i++) { + children[i] = (VirtualChild)v.get(i); + } + + return children; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildren(java.lang.String) + */ + public VirtualChild[] getVirtualChildren(String fullVirtualName) { + + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return new VirtualChild[0]; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + return vfs.getChildren(fullVirtualName); + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildFolders(java.lang.String) + */ + public VirtualChild[] getVirtualChildFolders(String fullVirtualName) { + + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return new VirtualChild[0]; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + return vfs.getChildrenFolders(fullVirtualName); + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualFile(java.lang.String) + */ + public VirtualChild getVirtualFile(String fullVirtualName) { + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + if (fullVirtualName == null || fullVirtualName.equals("")) { + return new VirtualChild(this); + } + + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return new VirtualChild(this, fullVirtualName); + } + + VirtualChild entry = vfs.getEntry(fullVirtualName); + + // if entry is null, then create a new virtual child object + // for which exists will return false + if (entry == null) { + entry = new VirtualChild(this, fullVirtualName); + } + + return entry; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#exists(java.lang.String) + */ + public boolean exists(String fullVirtualName) { + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + if (fullVirtualName == null || fullVirtualName.equals("")) { + return false; + } + + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + VirtualChild child = vfs.getEntry(fullVirtualName); + + if (child != null) { + return true; + } + else { + return false; + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getArchive() + */ + public File getArchive() { + return file; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getTimeStampFor(java.lang.String) + */ + public long getTimeStampFor(String fullVirtualName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // get the entry with that name + TarEntry entry = getTarFile().getEntry(fullVirtualName); + + // if the entry exists, return its last modified time + if (entry != null) { + return entry.getModificationTime(); + } + // otherwise return the last modified time of the file + // TODO: is this correct? + else { + return file.lastModified(); + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getSizeFor(java.lang.String) + */ + public long getSizeFor(String fullVirtualName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // get the entry with that name + TarEntry entry = getTarFile().getEntry(fullVirtualName); + + // if the entry exists, return the size + if (entry != null) { + return entry.getSize(); + } + // otherwise return 0 + // TODO: is this correct? + else { + return 0; + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualFile(java.lang.String, java.io.File) + */ + public boolean extractVirtualFile(String fullVirtualName, File destination) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + TarEntry entry = getTarFile().getEntry(fullVirtualName); + + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + // if the entry is a directory, simply create the destination and set the last modified time to + // the entry's last modified time + if (entry.isDirectory()) { + + // if destination exists, then delete it + if (destination.exists()) { + destination.delete(); + } + + // create destination directory, and set the last modified time to + // the entry's last modified time + destination.mkdirs(); + destination.setLastModified(entry.getModificationTime()); + return true; + } + + // entry is not a directory + InputStream inStream = null; + OutputStream outStream = null; + + try { + inStream = getTarFile().getInputStream(entry); + + if (inStream == null) { + destination.setLastModified(entry.getModificationTime()); + return false; // TODO: return true or false? + } + + outStream = new FileOutputStream(destination); + + byte[] buf = new byte[ITarConstants.BLOCK_SIZE]; + int numRead = inStream.read(buf); + + while (numRead > 0) { + outStream.write(buf, 0, numRead); + numRead = inStream.read(buf); + } + } + catch (IOException e) { + // TODO: log error + } + finally { + + try { + + if (outStream != null) { + outStream.close(); + } + + if (inStream != null) { + inStream.close(); + } + } + catch (IOException e) { + // TODO: log error + } + + // finished creating and writing to the file, so now set the last modified time + // to the entry's last modified time + destination.setLastModified(entry.getModificationTime()); + + } + return true; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File) + */ + public boolean extractVirtualDirectory(String fullVirtualName, File destinationParent) { + return extractVirtualDirectory(fullVirtualName, destinationParent, (File) null); + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File, java.io.File) + */ + public boolean extractVirtualDirectory(String fullVirtualName, File destinationParent, File destination) { + + // if the destination directory doesn't exist, create it + if (!destinationParent.exists()) { + + if (!destinationParent.mkdirs()) { + // TODO: log error + return false; // quit if we fail to create the destination directory + } + } + // otherwise if the destination directory does exist, but is not a directory, then quit + else if (!destinationParent.isDirectory()) { + return false; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + VirtualChild dir = vfs.getEntry(fullVirtualName); + + if (dir == null || !dir.isDirectory) { + return false; + } + + if (destination == null) { + + if (fullVirtualName.equals("")) { + destination = destinationParent; + } + else { + destination = new File(destinationParent, dir.name); + } + } + + File topDir = destination; + String topDirPath = topDir.getAbsolutePath(); + + // TODO: why are we checking that destination and destination parent are not equal? + if (!destination.equals(destinationParent)) { + + if (destination.isFile() && destination.exists()) { + SystemArchiveUtil.delete(destination); + } + + destination.mkdirs(); + } + + // if the directory does not exist, try to create it + if (!topDir.exists() && !topDir.mkdirs()) { + // TODO: log error + return false; // log error and quit if we fail to create the directory + } + else { + extractVirtualFile(fullVirtualName, topDir); + } + + // get the children of this directory + VirtualChild[] children = vfs.getChildren(fullVirtualName); + + for (int i = 0; i < children.length; i++) { + VirtualChild tempChild = children[i]; + String childPath = topDirPath + File.separator + tempChild.name; + File childFile = new File(childPath); + + // if the child is a directory, then we need to extract it and its children + if (tempChild.isDirectory) { + + // and now extract its children + extractVirtualDirectory(tempChild.fullName, childFile, (File) null); + } + // otherwise if the child is a file, simply extract it + else { + extractVirtualFile(tempChild.fullName, childFile); + } + } + + return true; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File, java.lang.String, java.lang.String) + */ + public boolean add(File file, String virtualPath, String name) { + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + + if (!file.isDirectory()) { + + // if it exists, call replace + if (exists(virtualPath + "/" + name)) { + return replace(virtualPath + "/" + name, file, name); + } + else { + File[] files = new File[1]; + files[0] = file; + String[] names = new String[1]; + names[0] = name; + return add(files, virtualPath, names); + } + } + else { + Vector children = new Vector(); + listAllFiles(file, children); + int numOfChildren = children.size(); + File[] sources = new File[numOfChildren + 1]; + String[] newNames = new String[numOfChildren + 1]; + int charsToTrim = file.getParentFile().getAbsolutePath().length() + 1; + for (int i = 0; i < numOfChildren; i++) + { + sources[i] = (File)children.get(i); + newNames[i] = sources[i].getAbsolutePath().substring(charsToTrim); + newNames[i] = newNames[i].replace('\\','/'); + + if (sources[i].isDirectory() && !newNames[i].endsWith("/")) { + newNames[i] = newNames[i] + "/"; + } + } + + sources[numOfChildren] = file; + newNames[numOfChildren] = name; + + if (!newNames[numOfChildren].endsWith("/")) { + newNames[numOfChildren] = newNames[numOfChildren] + "/"; + } + + return add(sources, virtualPath, newNames); + } + } + + /** + * Helper method. . . populates found with a + * collapsed list of all nodes in the subtree + * of the file system rooted at parent. + */ + public void listAllFiles(File parent, Vector found) { + + File[] children = parent.listFiles(); + + for (int i = 0; i < children.length; i++) { + + if (children[i].isDirectory()) { + listAllFiles(children[i], found); + } + + found.add(children[i]); + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File[], java.lang.String, java.lang.String[]) + */ + public boolean add(File[] files, String virtualPath, String[] names) { + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + + int numFiles = files.length; + + for (int i = 0; i < numFiles; i++) { + + if (!files[i].exists() || !files[i].canRead()) { + return false; + } + + // if the entry already exists, then we should do a replace + // TODO (KM): should we simply replace and return? + // I think we should check each entry and replace or create for each one + if (exists(virtualPath + "/" + names[i])) { + return replace(virtualPath + "/" + names[i], files[i], names[i]); + } + } + + try { + + // open a new temp file which will be our destination for the new tar file + File outFile = new File(file.getAbsolutePath() + "temp"); + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(outFile)); + + // get all the entries in the current tar + VirtualChild[] children = getVirtualChildrenList(); + + // if it is an empty temp file, no need to recreate it + if (children.length != 0) { + createTar(children, outStream, (HashSet)null); + } + + // for each new file to add + for (int i = 0; i < numFiles; i++) { + + String childVirtualPath = virtualPath + "/" + names[i]; + + TarEntry newEntry = createTarEntry(files[i], childVirtualPath); + + // append the additional entry to the tar file + appendFile(files[i], newEntry, outStream); + + // add the new entry to the cache, so that the cache is updated + VirtualChild temp = getVirtualChild(newEntry); + vfs.addEntry(temp); + } + + // close output stream + outStream.close(); + + // replace the current tar file with the new one, and do not update cache since + // we just did + replaceFile(outFile, false); + + } + catch (IOException e) { + // TODO: log error + return false; + } + + return true; + } + + /** + * Create a tar file from the given virtual child objects, using the given output stream and omitting + * the children in the given set. + * @param children an array of virtual children from which to create a tar file. + * @param outStream the tar output stream to use. + * @param omitChildren the set of names for children that should be omitted from the given array of virtual children. + * @throws IOException if an I/O exception occurs. + */ + protected void createTar(VirtualChild[] children, TarOutputStream outStream, HashSet omitChildren) throws IOException { + + // TODO: if all children are to be deleted, we leave the tar file with a dummy entry + if (omitChildren != null && children.length == omitChildren.size()) { + return; + } + + TarFile tarFile = getTarFile(); + + // go through each child + for (int i = 0; i < children.length; i++) { + + // if entry name is in the omit set, then do not include it + if (omitChildren != null && omitChildren.contains(children[i].fullName)) { + continue; + } + + // if child is a directory, then just add an entry for it + // there is no data + if (children[i].isDirectory) { + + // include a '/' at the end, since it is a directory + TarEntry nextEntry = tarFile.getEntry(children[i].fullName + "/"); + + // put the entry + outStream.putNextEntry(nextEntry); + + // close the entry + outStream.closeEntry(); + } + // otherwise child is a file, so add an entry for it + // and then add data (i.e. file contents). + else { + + TarEntry nextEntry = tarFile.getEntry(children[i].fullName); + + // get the input stream for the file contents + InputStream inStream = tarFile.getInputStream(nextEntry); + + // put the entry + outStream.putNextEntry(nextEntry); + + // write data + byte[] buf = new byte[ITarConstants.BLOCK_SIZE]; + int numRead = inStream.read(buf); + + while (numRead > 0) { + outStream.write(buf, 0, numRead); + numRead = inStream.read(buf); + } + + // close input stream + inStream.close(); + + // close entry, but do not close the output stream + outStream.closeEntry(); + } + } + } + + /** + * Appends a file to a tar output stream, using the given entry that represents the file. + * @param file the file to be appended to the tar output stream. + * @param entry the entry which represents the file. + * @param outStream the tar output stream. + * @throws IOException if an I/O error occurs. + */ + protected void appendFile(File file, TarEntry entry, TarOutputStream outStream) throws IOException { + + // put the next entry in the output stream + outStream.putNextEntry(entry); + + // now write data if it is a file + // there is no data for folders + if (!file.isDirectory()) { + BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(file)); + + byte[] buf = new byte[ITarConstants.BLOCK_SIZE]; + int numRead = inStream.read(buf); + + while (numRead > 0) { + outStream.write(buf, 0, numRead); + numRead = inStream.read(buf); + } + + // close the input stream + inStream.close(); + } + + // close the entry + outStream.closeEntry(); + } + + /** + * Creates a tar entry for a file with the given virtual path. The entry + * will contain the size and last modified time of the file. The entry's + * checksum will be calculated. + * @param file the file for which to create a tar entry. + * @param name the virtual path for the entry. + * @return the tar entry representing the given file. + */ + protected TarEntry createTarEntry(File file, String virtualPath) { + + String fullName = virtualPath; + + // if directory, end with a '/' + if (file.isDirectory()) { + + if (!fullName.endsWith("/")) { + fullName = fullName + "/"; + } + } + + // strip out leading '/' + // TODO (KM): Why? + if (fullName.startsWith("/")) { + fullName = fullName.substring(1); + } + + // create a new entry and set its size and last modified time + TarEntry entry = new TarEntry(fullName); + + // set the size if the file is not a directory + if (!file.isDirectory()) { + long size = file.length(); + entry.setSize(size); + } + else { + entry.setSize(0); + } + + // set modified time + long lastModified = file.lastModified(); + entry.setModificationTime(lastModified); + + // set the user name + String userName = System.getProperty("user.name"); + + if (userName != null) { + entry.setUserName(userName); + } + + // set user permissions + boolean canRead = file.canRead(); + boolean canWrite = file.canWrite(); + + // getting execute permission is a bit tricky + // need to go through security manager + boolean canExecute = false; + + // first get the system security manager + SecurityManager sm = System.getSecurityManager(); + + // if there is no security manager then create a new one + if (sm == null) { + sm = new SecurityManager(); + } + + try { + + // if security manager successfully created, check permission + if (sm != null) { + + // create a file permission to check execute + FilePermission permission = new FilePermission(file.getAbsolutePath(), "execute"); + + // this call will throw a SecurityException if permission does not exist + sm.checkPermission(permission); + canExecute = true; + } + else { + canExecute = false; + } + } + catch(SecurityException e) { + canExecute = false; + } + + entry.setUserMode(canRead, canWrite, canExecute); + + // calculate checksum + entry.calculateChecksum(); + + return entry; + } + + /** + * Changes a tar entry according to the file information and given path. The given path + * will be the new name of the entry. The size and last modified fields will be changed + * to the file's size and last modified time. The entry's checksum will be calculated. + * @param entry the entry that needs to be changed. + * @param file the file for which the tar entry is being changed. + * @param virtualPath the virtual path for the entry. + * @return the changed entry. + */ + protected TarEntry changeTarEntry(TarEntry entry, File file, String virtualPath) { + + // TODO (KM): This does not update the permissions in the entry according to the + // file permissions on disk. Need to look at how to retrieve permissions for owner, group + // and other, and then have to set these in the entry accordingly. + + String fullName = virtualPath; + + // if directory, end with a '/' + if (file.isDirectory()) { + + if (!fullName.endsWith("/")) { + fullName = fullName + "/"; + } + } + + // strip out leading '/' + // TODO (KM): Why? + if (fullName.startsWith("/")) { + fullName = fullName.substring(1); + } + + // change entry name + entry.setName(fullName); + + // update size field in entry + if (!file.isDirectory()) { + long size = file.length(); + entry.setSize(size); + } + else { + entry.setSize(0); + } + + // update last modified field in entry + long lastModified = file.lastModified(); + entry.setModificationTime(lastModified); + + // calculate checksum + entry.calculateChecksum(); + + return entry; + } + + /** + * Returns a virtual child given a tar entry. + * @param entry a tar entry. + * @return the virtual child that represents the tar entry. + */ + protected VirtualChild getVirtualChild(TarEntry entry) { + VirtualChild child = new VirtualChild(this, entry.getName()); + child.isDirectory = entry.isDirectory(); + return child; + } + + /** + * Replaces the old tar file managed by the handler with the given file, and optionally update + * the cache. + * @param newFile the new tar file. + * @param updateCache true to update the cache, false otherwise. + * Only specify false if the cache has already been updated to reflect the + * contents of this new file. + * @throws IOException if an I/O problem occurs. + */ + protected void replaceFile(File newFile, boolean updateCache) throws IOException { + String name = file.getAbsolutePath(); + + // create a temp file (in case something goes wrong) + File tempFile = new File(name + ".old"); + + // rename current file to tempFile + file.renameTo(tempFile); + + // rename the new file to the file this handler manages + newFile.renameTo(file); + + // reinitialize + init(file); + + // if we do not want to update the cache, we set the last modified time during cache to + // the modified time of the file, so when we call updateCache, it'll do nothing + if (!updateCache) { + modTimeDuringCache = file.lastModified(); + } + + // update cache if necessary + updateCache(); + + // delete the temporary file + tempFile.delete(); + } + + + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#replace(java.lang.String, java.io.File, java.lang.String) + */ + public boolean replace(String fullVirtualName, File file, String name) { + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + if (!file.exists() && !file.canRead()) { + return false; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // if the virtual file does not exist, we actually want to add + if (!exists(fullVirtualName)) { + return add(file, fullVirtualName, name); + } + + try { + + // open a new temp file which will be our destination for the new tar file + File outFile = new File(getArchive().getAbsolutePath() + "temp"); + + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(outFile)); + + // get all the entries + VirtualChild[] children = getVirtualChildrenList(); + + // create a set of omissions + HashSet omissions = new HashSet(); + + // add the virtual file to be replaced + omissions.add(fullVirtualName); + + // create the temp tar + createTar(children, outStream, omissions); + + // now append the new file to the tar + String parentVirtualPath = null; + + int i = fullVirtualName.lastIndexOf("/"); + + // if the virtual name has no '/', then we will replace it with the + // new name + if (i == -1) { + parentVirtualPath = ""; + } + // otherwise, we get the parent path to which the new name will be appended + else { + parentVirtualPath = fullVirtualName.substring(0, i); + } + + String virtualPath = parentVirtualPath + "/" + name; + + // get the existing entry for the file + TarFile tarFile = getTarFile(); + TarEntry entry = tarFile.getEntry(fullVirtualName); + + // update the entry with the file information + entry = changeTarEntry(entry, file, virtualPath); + + // now append this entry to the output stream + appendFile(file, entry, outStream); + + // remove old entry from cache + vfs.removeEntry(vfs.getEntry(fullVirtualName)); + + // add the new entry to cache + VirtualChild temp = getVirtualChild(entry); + vfs.addEntry(temp); + + // close output stream + outStream.close(); + + // replace the current tar file with the new one, and do not update cache since + // we just did + replaceFile(outFile, false); + + return true; + } + catch (IOException e) { + // TODO: log error + return false; + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#delete(java.lang.String) + */ + public boolean delete(String fullVirtualName) { + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + VirtualChild child = getVirtualFile(fullVirtualName); + VirtualChild[] omitArray = new VirtualChild[0]; + + // child does not exist, so quit + if (!child.exists()) { + return false; + } + + // child is a directory, so get its children since we need to delete them as well + if (child.isDirectory) { + omitArray = getVirtualChildrenList(fullVirtualName); + } + + try { + + // open a new temp file which will be our destination for the new tar file + File outFile = new File(file.getAbsolutePath() + "temp"); + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(outFile)); + + // get all the entries in the current tar + VirtualChild[] children = getVirtualChildrenList(); + + // create a set to hold omissions + HashSet omissions = new HashSet(); + + // add the child to it + omissions.add(child.fullName); + + // now go through array of children to be deleted + // this will be of length 0 if the child is not a directory + for (int i = 0; i < omitArray.length; i++) { + omissions.add(omitArray[i].fullName); + } + + // create the tar + createTar(children, outStream, omissions); + + // delete the child from the cache (this will also delete its children if it + // is a directory) + vfs.removeEntry(child); + + // close output stream + outStream.close(); + + // replace the current tar file with the new one, and do not update cache since + // we just did + replaceFile(outFile, false); + + return true; + } + catch (IOException e) { + // TODO: log error + return false; + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#rename(java.lang.String, java.lang.String) + */ + public boolean rename(String fullVirtualName, String newName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + int i = fullVirtualName.lastIndexOf("/"); + + // if the original does not have any separator, simply rename it. + if (i == -1) { + return fullRename(fullVirtualName, newName); + } + // otherwise, get the parent path and append the new name to it. + else { + String fullNewName = fullVirtualName.substring(0, i+1) + newName; + return fullRename(fullVirtualName, fullNewName); + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#move(java.lang.String, java.lang.String) + */ + public boolean move(String fullVirtualName, String destinationVirtualPath) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + destinationVirtualPath = ArchiveHandlerManager.cleanUpVirtualPath(destinationVirtualPath); + + int i = fullVirtualName.lastIndexOf("/"); + + // if the original does not have any separator, simply append it to the destination path. + if (i == -1) { + return fullRename(fullVirtualName, destinationVirtualPath + "/" + fullVirtualName); + } + // otherwise, get the last segment (the name) and append that to the destination path. + else { + String name = fullVirtualName.substring(i); + return fullRename(fullVirtualName, destinationVirtualPath + name); + } + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#fullRename(java.lang.String, java.lang.String) + */ + public boolean fullRename(String fullVirtualName, String newFullVirtualName) { + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + newFullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(newFullVirtualName); + VirtualChild child = getVirtualFile(fullVirtualName); + + // if the virtual file to be renamed does not exist, then quit + if (!child.exists()) { + return false; + } + + try { + + // open a new temp file which will be our destination for the new tar file + File outFile = new File(file.getAbsolutePath() + "temp"); + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(outFile)); + + // get all the entries + VirtualChild[] children = getVirtualChildrenList(); + + // the rename list + // a hashmap containing old name, new name associations for each + // child that has to be renamed + HashMap names = new HashMap(); + + // if the entry to rename is a directory, we need to rename all + // its children entries + if (child.isDirectory) { + + // add the entry itself to the rename list + // include '/' in both the old name and the new name since it is a directory + names.put(fullVirtualName + "/", newFullVirtualName + "/"); + + // get all the children of the entry to be renamed + VirtualChild[] childrenArray = getVirtualChildrenList(fullVirtualName); + + // now we need to get the relative path of each child with respect to the virtual name + // and append the relative path to the new virtual name + for (int i = 0; i < childrenArray.length; i++) { + + int j = fullVirtualName.length(); + + // get the relative path with respect to the virtual name + String suffix = childrenArray[i].fullName.substring(j); + + // add the relative path to the new virtual name + String newName = newFullVirtualName + suffix; + + // if a child is a directory, ensure that '/'s are added both for the old name + // and the new name + if (childrenArray[i].isDirectory) { + names.put(childrenArray[i].fullName + "/", newName + "/"); + } + else { + names.put(childrenArray[i].fullName, newName); + } + } + } + // otherwise entry is not a directory, so simply add it to the rename list + else { + names.put(fullVirtualName, newFullVirtualName); + } + + // create tar with renamed entries + createTar(children, outStream, names); + + // close the output stream + outStream.close(); + + // replace the current tar file with the new one, and force an update of the cache. + // TODO: we force a fresh update of the cache because it is seemingly complicated + // to do the delta upgrade of the cache. But investigate this, since it will + // probably be more efficient + replaceFile(outFile, true); + + return true; + } + catch (IOException e) { + // TODO: log error + return false; + } + } + + /** + * Creates a tar file from the given virtual child objects, using the given output stream and renaming entries + * according to hash map entries. + * @param children an array of virtual children from which to create a tar file. + * @param outStream the tar output stream to use. + * @param renameMap a map containing associations between old names and new names. Old names are the keys + * in the map, and the values are the new names. + * @throws IOException if an I/O exception occurs. + */ + protected void createTar(VirtualChild[] children, TarOutputStream outStream, HashMap renameMap) throws IOException { + + TarFile tarFile = getTarFile(); + + // go through each child + for (int i = 0; i < children.length; i++) { + + VirtualChild child = children[i]; + String oldPath = child.getArchiveStandardName(); + String newPath = oldPath; + boolean needToRename = false; + + // if entry is to be renamed, get the new path + if (renameMap.containsKey(oldPath)) { + newPath = (String)(renameMap.get(oldPath)); + child.renameTo(newPath); + needToRename = true; + } + + TarEntry nextEntry = tarFile.getEntry(oldPath); + + // if child is a directory, then just add an entry for it + // there is no data + if (children[i].isDirectory) { + + // if we need to rename the entry, then do so now + if (needToRename) { + nextEntry = changeTarEntryName(nextEntry, newPath); + } + + // put the entry + outStream.putNextEntry(nextEntry); + + // close the entry + outStream.closeEntry(); + } + // otherwise child is a file, so add an entry for it + // and then add data (i.e. file contents). + else { + + // get the input stream for the file contents + InputStream inStream = tarFile.getInputStream(nextEntry); + + // if we need to rename the entry, then do so now + // this must be done after we have obtained the input stream + // since tarFile.getInputStream() depends on the entry name + if (needToRename) { + nextEntry = changeTarEntryName(nextEntry, newPath); + } + + // put the entry + outStream.putNextEntry(nextEntry); + + // write data + byte[] buf = new byte[ITarConstants.BLOCK_SIZE]; + int numRead = inStream.read(buf); + + while (numRead > 0) { + outStream.write(buf, 0, numRead); + numRead = inStream.read(buf); + } + + // close input stream + inStream.close(); + + // close entry, but do not close the output stream + outStream.closeEntry(); + } + } + } + + /** + * Changes the name of a tar entry. Also calculates the new checksum for the entry. + * @param entry the entry for which the name has to be changed. + * @param newName the new name for the entry. + * @return the changed entry. + */ + protected TarEntry changeTarEntryName(TarEntry entry, String newName) { + + // change entry path + entry.setName(newName); + + // calculate checksum + entry.calculateChecksum(); + + return entry; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getFiles(java.lang.String[]) + */ + public File[] getFiles(String[] fullNames) { + + File[] files = new File[fullNames.length]; + + for (int i = 0; i < fullNames.length; i++) { + String name; + String fullName = fullNames[i]; + fullName = ArchiveHandlerManager.cleanUpVirtualPath(fullName); + int j = fullName.lastIndexOf("/"); + + if (j == -1) { + name = fullName; + } + else { + name = fullName.substring(j+1); + } + + try { + files[i] = File.createTempFile(name, "virtual"); + files[i].deleteOnExit(); + extractVirtualFile(fullNames[i], files[i]); + } + catch (IOException e) { + // TODO: log error + return null; + } + } + + return files; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#createFolder(java.lang.String) + */ + public boolean createFolder(String fullVirtualName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + fullVirtualName = fullVirtualName + "/"; + return createVirtualObject(fullVirtualName); + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#createFile(java.lang.String) + */ + public boolean createFile(String fullVirtualName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + return createVirtualObject(fullVirtualName); + } + + /** + * Creates a virtual object that does not already exist in the virtual file system. + * Creates an empty file in the tar file. + * @param name the name of the virtual object. + * @return true if the object was created successfully, false otherwise. + */ + protected boolean createVirtualObject(String name) { + + // update our cache before accessing cache + try { + updateCache(); + } + catch (IOException e) { + // TODO: log error + return false; + } + + // if the object already exists, return false + if (exists(name)) { + return false; + } + + try { + + // open a new temp file which will be our destination for the new tar file + File outFile = new File(file.getAbsolutePath() + "temp"); + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(outFile)); + + // get all the entries + VirtualChild[] children = getVirtualChildrenList(); + + // if it is an empty temp file, no need to recreate it + if (children.length != 0) { + createTar(children, outStream, (HashSet)null); + } + + // append an empty file to the tar file + TarEntry newEntry = appendEmptyFile(outStream, name); + + // add to cache + VirtualChild temp = getVirtualChild(newEntry); + vfs.addEntry(temp); + + // close the output stream + outStream.close(); + + // replace the current tar file with the new one, but do not update the cache + // since we have already updated to the cache + replaceFile(outFile, false); + + return true; + } + catch (IOException e) { + // TODO: log error + return false; + } + } + + /** + * Creates a new tar entry and appends it to the tar output stream with the given name. + * @param outStream the tar output stream. + * @param name the name of the new tar entry. + * @return the newly created tar entry. + * @throws IOException if an I/O error occurs. + */ + protected TarEntry appendEmptyFile(TarOutputStream outStream, String name) throws IOException { + + // create a new entry with size 0 and the last modified time as the current time + TarEntry newEntry = new TarEntry(name); + newEntry.setSize(0); + newEntry.setModificationTime(System.currentTimeMillis()); + + // set the user name + String userName = System.getProperty("user.name"); + + if (userName != null) { + newEntry.setUserName(userName); + } + + // set user permissions + boolean canRead = file.canRead(); + boolean canWrite = file.canWrite(); + + // getting execute permission is a bit tricky + // need to go through security manager + boolean canExecute = false; + + // first get the system security manager + SecurityManager sm = System.getSecurityManager(); + + // if there is no security manager then create a new one + if (sm == null) { + sm = new SecurityManager(); + } + + try { + + // if security manager successfully created, check permission + if (sm != null) { + + // create a file permission to check execute + FilePermission permission = new FilePermission(file.getAbsolutePath(), "execute"); + + // this call will throw a SecurityException if permission does not exist + sm.checkPermission(permission); + canExecute = true; + } + else { + canExecute = false; + } + } + catch(SecurityException e) { + canExecute = false; + } + + newEntry.setUserMode(canRead, canWrite, canExecute); + + // calculate checksum + newEntry.calculateChecksum(); + + // put the entry + outStream.putNextEntry(newEntry); + + // close the entry + outStream.closeEntry(); + + return newEntry; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getStandardName(org.eclipse.rse.services.clientserver.archiveutils.VirtualChild) + */ + public String getStandardName(VirtualChild vc) { + + if (vc.isDirectory) { + return vc.fullName + "/"; + } + + return vc.fullName; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#create() + */ + public boolean create() { + + try { + + // create output stream + TarOutputStream outStream = new TarOutputStream(new FileOutputStream(file)); + + // close output stream, so we have an empty tar file + outStream.close(); + + // recreate cache + createCache(); + + // set cache time + modTimeDuringCache = file.lastModified(); + } + catch (IOException e) { + return false; + } + + return true; + } + + public SystemSearchLineMatch[] search(String fullVirtualName, SystemSearchStringMatcher matcher) { + // if the search string is empty or if it is "*", then return no matches + // since it is a file search + if (matcher.isSearchStringEmpty() || matcher.isSearchStringAsterisk()) { + return new SystemSearchLineMatch[0]; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + VirtualChild vc = getVirtualFile(fullVirtualName); + + if (!vc.exists() || vc.isDirectory) { + return new SystemSearchLineMatch[0]; + } + + TarFile tarFile = getTarFile(); + TarEntry entry = tarFile.getEntry(fullVirtualName); + InputStream is = null; + + try { + tarFile.getInputStream(entry); + + if (is == null) { + return new SystemSearchLineMatch[0]; + } + + InputStreamReader isr = new InputStreamReader(is); + BufferedReader bufReader = new BufferedReader(isr); + + SystemSearchStringMatchLocator locator = new SystemSearchStringMatchLocator(bufReader, matcher); + SystemSearchLineMatch[] matches = locator.locateMatches(); + + if (matches == null) { + return new SystemSearchLineMatch[0]; + } + else { + return matches; + } + } + catch (IOException e) { + // TODO: log error + return new SystemSearchLineMatch[0]; + } + } + + public boolean exists() + { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getCommentFor(java.lang.String) + */ + public String getCommentFor(String fullVirtualName) + { + return ""; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getCompressedSizeFor(java.lang.String) + */ + public long getCompressedSizeFor(String fullVirtualName) + { + return getSizeFor(fullVirtualName); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getCompressionMethodFor(java.lang.String) + */ + public String getCompressionMethodFor(String fullVirtualName) + { + return ""; + } + + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getArchiveComment() + */ + public String getArchiveComment() + { + return ""; + } + + /** + * @param file + * @param virtualPath + * @param name + * @param encoding + * @param registry + * @return + */ + public boolean add(File file, String virtualPath, String name, + String encoding, ISystemFileTypes registry) { + return add(file, virtualPath, name); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean) + */ + public boolean add(File file, String virtualPath, String name, + String sourceEncoding, String targetEncoding, boolean isText) { + return add(file, virtualPath, name); + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File[], java.lang.String, java.lang.String[], java.lang.String[], java.lang.String[], boolean[]) + */ + public boolean add(File[] files, String virtualPath, String[] names, + String[] sourceEncodings, String[] targetEncodings, boolean[] isTexts) { + return add(files, virtualPath, names); + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File, java.io.File, java.lang.String, boolean) + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, + File destination, String sourceEncoding, boolean isText) { + return extractVirtualDirectory(dir, destinationParent, destination); + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File, java.lang.String, boolean) + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, + String sourceEncoding, boolean isText) { + return extractVirtualDirectory(dir, destinationParent); + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualFile(java.lang.String, java.io.File, java.lang.String, boolean) + */ + public boolean extractVirtualFile(String fullVirtualName, File destination, + String sourceEncoding, boolean isText) { + return extractVirtualFile(fullVirtualName, destination); + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getClassification(java.lang.String) + */ + public String getClassification(String fullVirtualName) { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // default type + String type = "file"; + + // if it's not a class file, we do not classify it + if (!fullVirtualName.endsWith(".class")) { + return type; + } + + // get the entry with that name + TarEntry entry = getTarFile().getEntry(fullVirtualName); + + // get the input stream for the entry + InputStream stream = null; + + // class file parser + BasicClassFileParser parser = null; + + boolean isExecutable = false; + + try { + stream = getTarFile().getInputStream(entry); + + // use class file parser to parse the class file + parser = new BasicClassFileParser(stream); + parser.parse(); + + // query if it is executable, i.e. whether it has main method + isExecutable = parser.isExecutable(); + } + catch (IOException e) { + // TODO: log it + + // we assume not executable + isExecutable = false; + } + + // if it is executable, then also get qualified class name + if (isExecutable) { + type = "executable(java"; + + String qualifiedClassName = parser.getQualifiedClassName(); + + if (qualifiedClassName != null) { + type = type + ":" + qualifiedClassName; + } + + type = type + ")"; + } + + return type; + } + + public boolean add(InputStream stream, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText) { + // TODO Auto-generated method stub + return false; + } + + public boolean add(File file, String virtualPath, String name, String sourceEncoding, String targetEncoding, ISystemFileTypes typeRegistery) { + // TODO Auto-generated method stub + return false; + } + + public boolean replace(String fullVirtualName, InputStream stream, String name, String sourceEncoding, String targetEncoding, boolean isText) { + // TODO Auto-generated method stub + return false; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemUniversalZipEntry.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemUniversalZipEntry.java new file mode 100644 index 00000000000..ae5f7a1cc39 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemUniversalZipEntry.java @@ -0,0 +1,148 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.util.zip.ZipEntry; + +/** + * @author mjberger + * + * This is a wrapper class for a ZipEntry object that contains some + * extra helper methods for processing the ZipEntry that are not included + * in java.util.zip.ZipEntry. + */ +public class SystemUniversalZipEntry +{ + + protected ZipEntry _entry; + protected String _entryFullName; + protected String _entryFullPath; + protected String _entryName; + protected String _extension; + protected boolean _nested; + + public SystemUniversalZipEntry(ZipEntry entry) + { + _entry = entry; + doNameProcessing(); + } + + /** + * Returns the ZipEntry associated with this SystemUniversalZipEntry + */ + public ZipEntry getEntry() + { + return _entry; + } + + /** + * Sets the ZipEntry associated with this SystemUniversalZipEntry + */ + public void setEntry(ZipEntry newEntry) + { + _entry = newEntry; + doNameProcessing(); + } + + private void doNameProcessing() + { + if (_entry.isDirectory()) + { + _entryFullName = _entry.getName().substring(0, _entry.getName().length()-1); + } + else + { + _entryFullName = _entry.getName(); + } + int endOfPathPosition = _entryFullName.lastIndexOf("/"); + if (endOfPathPosition != -1) + { + _entryFullPath = _entryFullName.substring(0,endOfPathPosition); + _entryName = _entryFullName.substring(endOfPathPosition+1); + } + else + { + _entryFullPath = ""; + _entryName = _entryFullName; + } + int i = _entryFullName.lastIndexOf("."); + if (i == -1) + { + _extension = ""; + } else _extension = _entryFullName.substring(i + 1); + if (_entryFullName.indexOf("/") != -1) _nested = true; + } + + /** + * Returns the full path to the entry within the ZipFile file structure. + * Note: this is NOT the full path to the ZipFile in the regular file + * system. + * @return a String containing the full path leading to the ZipEntry within + * the ZipFile file structure. Does not include the file name. + */ + public String getFullPath() + { + return _entryFullPath; + } + + /** + * Returns the full name associated with this entry (including path to the + * entry) within the ZipFile file structure. Note: this is NOT the full path to the + * ZipFile in the regular file system. + * @return a String containing the full name including path of the ZipEntry + * within the ZipFile file structure. Includes the file name. + */ + public String getFullName() + { + return _entryFullName; + } + + /** + * Returns only the filename associated with this entry in the ZipFile + * file structure. + * @return a String containing only the file name of this ZipEntry. + */ + public String getName() + { + return _entryName; + } + + /** + * Returns the extension of this entry, if the entry is a file, + * null string otherwise. + */ + public String getExtension() + { + return _extension; + } + + /** + * Returns whether or not this entry is nested within folders within the zip file. + */ + public boolean isNested() + { + return _nested; + } + + /** + * @return Whether or not this zipentry is a directory. + */ + public boolean isDirectory() + { + return _entry.isDirectory(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemZipHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemZipHandler.java new file mode 100644 index 00000000000..0721491b3ae --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/SystemZipHandler.java @@ -0,0 +1,2227 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Vector; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import org.eclipse.rse.services.clientserver.ISystemFileTypes; +import org.eclipse.rse.services.clientserver.SystemEncodingUtil; +import org.eclipse.rse.services.clientserver.java.BasicClassFileParser; +import org.eclipse.rse.services.clientserver.search.SystemSearchLineMatch; +import org.eclipse.rse.services.clientserver.search.SystemSearchStringMatchLocator; +import org.eclipse.rse.services.clientserver.search.SystemSearchStringMatcher; + + +/** + * @author mjberger + * Implements an ISystemArchiveHandler for ZIP files. + */ +public class SystemZipHandler implements ISystemArchiveHandler +{ + + protected ZipFile _zipfile; // The underlying zipfile associated with this handler. + protected HashMap _virtualFS; // The virtual file system formed by the entries in _zipfile. + //-------------------------------------------------------------------------------------------------------------------- + // Explanation of how the virtual file system is stored in a HashMap: + // + // _virtualFS is a HashMap of HashMaps. How does this suggest a tree structure? + // The keys in _virtualFS are all Strings. There is one key in _virtualFS for every directory + // in the virtual file system. The root directory has the key "". Associated with each key, is a value, and that value + // is itself another HashMap, representing the contents of that directory. In the "inner" HashMap, each key is + // a String giving the name of an object in the directory, and each associated value is a + // VirtualChild representing that object itself. + // + // Note that if the object is a directory, then + // the value representing it in the inner HashMap is still a VirtualChild, not another + // HashMap. There are only two levels of HashMaps in the virtual file system. If the + // object is a directory, then the VirtualChild object representing it will have + // isDirectory == true. We can then find the contents of this directory, by going + // back out to the outer HashMap, and retrieving the inner HashMap associated + // with our directory's name. + // + // This file system is designed for quick retrieval of virtual objects. + // Retrieving a single object whose full path is known can be done + // in worst case O(1) time rather than O(h) time for a tree file system with height h. + // Retrieving the children of an object takes worst case O(s) time, where s is the size + // of the inner HashMap containing those children. + // For insertion, the object must be inserted into its appropriate inner HashMap, + // and then the HashMaps for all ancestors must either be created or updated, so this + // takes worst case O(d) time, where d is the depth of the object in the virtual file tree. + // For deletion, the argument is similar, that this takes O(d) time. + // For renames, the worst case is O(n) time, where n is the number of nodes in the + // virtual file tree. This is because if we change the name of a directory under the root, + // then we must change all of its children's VirtualChild objects as well. It is advisable + // to just rebuild the tree for a rename. + // + // Building the tree from a list of entries in a zipfile takes O(nh) time, where n + // is the number of entries in the zipfile, and h is the maximum height of an entry in + // the virtual file system. + //-------------------------------------------------------------------------------------------------------------------- + + protected File _file; // The underlying file associated with this handler. + protected long _vfsLastModified; // The timestamp of the file that the virtual file system reflects. + protected boolean _exists; // Whether or not the zipfile "exists" (in order to exist, must be uncorrupted too) + + /** + * Creates a new SystemZipHandler and associates it with file. + * @param file The file that this handler will wrapper. + * @throws IOException If there is an error handling file + */ + public SystemZipHandler(File file) + { + _file = file; + _vfsLastModified = _file.lastModified(); + if (openZipFile()) + { + buildTree(); + closeZipFile(); + _exists = true; + } + else + { + _exists = false; + } + } + + /** + * Builds the virtual file system tree out of the entries in + * the zipfile. + * + */ + protected void buildTree() + { + _virtualFS = new HashMap(); + Enumeration entries = _zipfile.entries(); + while (entries.hasMoreElements()) + { + ZipEntry next = (ZipEntry) entries.nextElement(); + fillBranch(next); + } + } + + /** + * Populates an entire branch of the tree that comprises the + * virtual file system. The parameter is the leaf node, and from + * the virtual path of the parameter, we can deduce what the ancestors + * of the leaves are, and populate the tree from there. + * @param next The ZipEntry from which the branch will be built. + */ + protected void fillBranch(ZipEntry next) + { + VirtualChild nextChild; + if (next.getName().equals("/")) return; // dummy entry + if (!next.isDirectory()) + { + SystemUniversalZipEntry nextEntry = new SystemUniversalZipEntry(next); + nextChild = new VirtualChild(this, nextEntry.getFullName()); + } + else // it is a directory + { + SystemUniversalZipEntry nextEntry = new SystemUniversalZipEntry(next); + nextChild = new VirtualChild(this, nextEntry.getFullName()); + nextChild.isDirectory = true; + + if (!_virtualFS.containsKey(nextChild.fullName)) + { + _virtualFS.put(nextChild.fullName, new HashMap()); + } + + } + // key has not been encountered before, create a new + // element in the virtualFS. + if (!_virtualFS.containsKey(nextChild.path)) + { + recursivePopulate(nextChild.path, nextChild); + } + else // key has been encountered before, no need to recursively + // populate the subdirectories + { + HashMap hm = (HashMap) _virtualFS.get(nextChild.path); + hm.put(nextChild.name, nextChild); + } + } + + /** + * Actually does the work for the fillBranch method. Recursively + * inserts key/value pairs into the virtualFS, then uses the key + * to get the next parent (moving up one level) and thus recursively + * populates one branch. + */ + protected void recursivePopulate(String key, VirtualChild value) + { + // base case 1: key has been encountered before, finish recursing + if (_virtualFS.containsKey(key)) + { + HashMap hm = (HashMap) _virtualFS.get(key); + hm.put(value.name, value); + return; + } + + // else + HashMap newValue = new HashMap(); + newValue.put(value.name, value); + _virtualFS.put(key, newValue); + + // base case 2 + if (key.equals("")) + { + return; + } + else + { + int i = key.lastIndexOf("/"); + if (i == -1) // recursive last step + { + VirtualChild nextValue = new VirtualChild(this, key); + nextValue.isDirectory = true; + recursivePopulate("", nextValue); + return; + } + else // recursive step + { + String newKey = key.substring(0, i); + VirtualChild nextValue = new VirtualChild(this, key); + nextValue.isDirectory = true; + recursivePopulate(newKey, nextValue); + return; + } + + } + + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildrenList() + */ + public VirtualChild[] getVirtualChildrenList() + { + return getVirtualChildrenList(true); + } + + /** + * Same as getVirtualChildrenList(), but you can choose whether + * to leave the zip file open or closed upon return. + */ + public VirtualChild[] getVirtualChildrenList(boolean closeZipFile) + { + if (!_exists) return new VirtualChild[0]; + if (!updateVirtualFSIfNecessary()) return new VirtualChild[0]; + + if (openZipFile()) + { + Vector children = new Vector(); + Enumeration entries = _zipfile.entries(); + while (entries.hasMoreElements()) + { + ZipEntry next = (ZipEntry) entries.nextElement(); + SystemUniversalZipEntry nextEntry = new SystemUniversalZipEntry(next); + VirtualChild nextChild = new VirtualChild(this, nextEntry.getFullName()); + nextChild.isDirectory = next.isDirectory(); + children.add(nextChild); + } + VirtualChild[] retVal = new VirtualChild[children.size()]; + for (int i = 0; i < children.size(); i++) + { + retVal[i] = (VirtualChild) children.get(i); + } + if (closeZipFile) closeZipFile(); + return retVal; + } + else return new VirtualChild[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildrenList(java.lang.String) + */ + public VirtualChild[] getVirtualChildrenList(String parent) + { + return getVirtualChildrenList(parent, true); + } + + /** + * Same as getVirtualChildrenList(String parent) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public VirtualChild[] getVirtualChildrenList(String parent, boolean closeZipFile) + { + if (!_exists) return new VirtualChild[0]; + if (!updateVirtualFSIfNecessary()) return new VirtualChild[0]; + + if (openZipFile()) + { + parent = ArchiveHandlerManager.cleanUpVirtualPath(parent); + Vector children = new Vector(); + Enumeration entries = _zipfile.entries(); + while (entries.hasMoreElements()) + { + ZipEntry next = (ZipEntry) entries.nextElement(); + String nextName = ArchiveHandlerManager.cleanUpVirtualPath(next.getName()); + if (nextName.startsWith(parent) && !nextName.equals(parent+"/")) + { + SystemUniversalZipEntry nextEntry = new SystemUniversalZipEntry(next); + VirtualChild nextChild = new VirtualChild(this, nextEntry.getFullName()); + nextChild.isDirectory = next.isDirectory(); + children.add(nextChild); + } + } + VirtualChild[] retVal = new VirtualChild[children.size()]; + for (int i = 0; i < children.size(); i++) + { + retVal[i] = (VirtualChild) children.get(i); + } + if (closeZipFile) closeZipFile(); + return retVal; + } + else return new VirtualChild[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildren(java.lang.String) + */ + public VirtualChild[] getVirtualChildren(String fullVirtualName) + { + if (!_exists) return null; + if (!updateVirtualFSIfNecessary()) return null; + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + VirtualChild[] values = null; + if (_virtualFS.containsKey(fullVirtualName)) + { + HashMap hm = (HashMap) _virtualFS.get(fullVirtualName); + Object valueArray[] = hm.values().toArray(); + values = new VirtualChild[hm.size()]; + for (int i = 0; i < hm.size(); i++) + { + values[i] = (VirtualChild) valueArray[i]; + } + + } + return values; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualChildFolders(java.lang.String) + */ + public VirtualChild[] getVirtualChildFolders(String fullVirtualName) + { + if (!_exists) return null; + if (!updateVirtualFSIfNecessary()) return null; + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + Vector folders = new Vector(); + VirtualChild[] values = null; + if (_virtualFS.containsKey(fullVirtualName)) + { + HashMap hm = (HashMap) _virtualFS.get(fullVirtualName); + Object valueArray[] = hm.values().toArray(); + for (int i = 0; i < hm.size(); i++) + { + if (((VirtualChild) valueArray[i]).isDirectory) folders.add(valueArray[i]); + } + values = new VirtualChild[folders.size()]; + for (int i = 0; i < folders.size(); i++) + { + values[i] = (VirtualChild) folders.get(i); + } + } + return values; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getVirtualFile(java.lang.String) + */ + public VirtualChild getVirtualFile(String fullVirtualName) + { + if (!_exists) return new VirtualChild(this, fullVirtualName); + if (!updateVirtualFSIfNecessary()) return new VirtualChild(this, fullVirtualName); + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + if (fullVirtualName == "" || fullVirtualName == null) return new VirtualChild(this); + int i = fullVirtualName.lastIndexOf("/"); + String path; + String name; + if (i == -1) + { + path = ""; + name = fullVirtualName; + } + else + { + path = fullVirtualName.substring(0, i); + name = fullVirtualName.substring(i+1); + } + HashMap hm = (HashMap) _virtualFS.get(path); + if (hm == null) return new VirtualChild(this, fullVirtualName); + VirtualChild vc = (VirtualChild) hm.get(name); + if (vc == null) return new VirtualChild(this, fullVirtualName); + return vc; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#exists(java.lang.String) + */ + public boolean exists(String fullVirtualName) + { + if (!_exists) return false; + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + if (fullVirtualName == "" || fullVirtualName == null) return false; + + if (_vfsLastModified == _file.lastModified()) + { + int i = fullVirtualName.lastIndexOf("/"); + String path; + String name; + if (i == -1) + { + path = ""; + name = fullVirtualName; + } + else + { + path = fullVirtualName.substring(0, i); + name = fullVirtualName.substring(i+1); + } + HashMap hm = (HashMap) _virtualFS.get(path); + if (hm == null) return false; + if (hm.get(name) == null) return false; + return true; + } + else + { + boolean retval = false; + boolean keepOpen = _zipfile != null; + if (openZipFile()) + { + try + { + safeGetEntry(fullVirtualName); + retval = true; + } + catch (IOException e) + { + try + { + safeGetEntry(fullVirtualName + "/"); + retval = true; + } + catch (IOException f) + { + retval = false; + } + } + buildTree(); + _vfsLastModified = _file.lastModified(); + if (!keepOpen) closeZipFile(); + return retval; + } + else + { + System.out.println("Could not open the ZipFile " + _file.toString()); + return false; + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getArchive() + */ + public File getArchive() + { + return _file; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getTimeStampFor(java.lang.String) + */ + public long getTimeStampFor(String fullVirtualName) + { + return getTimeStampFor(fullVirtualName, true); + } + + /** + * Same as getTimeStampFor(String fullVirtualName) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public long getTimeStampFor(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return 0; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + } + catch (IOException e) + { + if (closeZipFile) closeZipFile(); + return _file.lastModified(); + } + if (closeZipFile) closeZipFile(); + return entry.getTime(); + } + else return _file.lastModified(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getSizeFor(java.lang.String) + */ + public long getSizeFor(String fullVirtualName) + { + return getSizeFor(fullVirtualName, true); + } + + public long getSizeFor(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return 0; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + } + catch (IOException e) + { + if (closeZipFile) closeZipFile(); + return 0; + } + if (closeZipFile) closeZipFile(); + return entry.getSize(); + } + else return 0; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualFile(java.lang.String, java.io.File) + */ + public boolean extractVirtualFile(String fullVirtualName, File destination) + { + return extractVirtualFile(fullVirtualName, destination, true, SystemEncodingUtil.ENCODING_UTF_8, false); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualFile(java.lang.String, java.io.File, java.lang.String, boolean) + */ + public boolean extractVirtualFile(String fullVirtualName, File destination, String sourceEncoding, boolean isText) + { + return extractVirtualFile(fullVirtualName, destination, true, sourceEncoding, isText); + } + + /** + * Same as extractVirtualFile(String fullVirtualName, File destination) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public boolean extractVirtualFile(String fullVirtualName, File destination, boolean closeZipFile, String sourceEncoding, boolean isText) + { + if (!_exists) return false; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + if (entry.isDirectory()) + { + destination.delete(); + destination.mkdirs(); + destination.setLastModified(entry.getTime()); + if (closeZipFile) closeZipFile(); + return true; + } + InputStream is = _zipfile.getInputStream(entry); + if (is == null) + { + destination.setLastModified(entry.getTime()); + if (closeZipFile) closeZipFile(); + return true; + } + BufferedInputStream reader = new BufferedInputStream(is); + + if (!destination.exists()) + { + File parentFile = destination.getParentFile(); + if (!parentFile.exists()) + parentFile.mkdirs(); + destination.createNewFile(); + } + BufferedOutputStream writer = new BufferedOutputStream( + new FileOutputStream(destination)); + + byte[] buf = new byte[1024]; + int numRead = reader.read(buf); + + while (numRead > 0) + { + if (isText) + { + String bufString = new String(buf, sourceEncoding); + byte[] convertedBuf = bufString.getBytes(); + int newSize = convertedBuf.length; + writer.write(convertedBuf, 0, newSize); + } + else + { + writer.write(buf, 0, numRead); + } + numRead = reader.read(buf); + } + writer.close(); + reader.close(); + } + catch (IOException e) + { + if (_virtualFS.containsKey(fullVirtualName)) + { + destination.delete(); + destination.mkdirs(); + destination.setLastModified(_file.lastModified()); + if (closeZipFile) closeZipFile(); + return true; + } + System.out.println(e.getMessage()); + if (closeZipFile) closeZipFile(); + return false; + } + destination.setLastModified(entry.getTime()); + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File) + */ + public boolean extractVirtualDirectory(String dir, File destinationParent) + { + return extractVirtualDirectory(dir, destinationParent, (File) null, SystemEncodingUtil.ENCODING_UTF_8, false); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File, java.lang.String, boolean) + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, String sourceEncoding, boolean isText) + { + return extractVirtualDirectory(dir, destinationParent, (File) null, sourceEncoding, isText); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#extractVirtualDirectory(java.lang.String, java.io.File, java.io.File) + */ + public boolean extractVirtualDirectory(String dir, File destinationParent, File destination) + { + return extractVirtualDirectory(dir, destinationParent, destination, SystemEncodingUtil.ENCODING_UTF_8, false); + } + + public boolean extractVirtualDirectory(String dir, File destinationParent, File destination, String sourceEncoding, boolean isText) + { + if (!_exists) return false; + + if (!destinationParent.isDirectory()) return false; + dir = ArchiveHandlerManager.cleanUpVirtualPath(dir); + if (!_virtualFS.containsKey(dir)) return false; + + String name; + int charsToTrim; + int j = dir.lastIndexOf("/"); + if (j == -1) + { + charsToTrim = 0; + name = dir; + } + else + { + charsToTrim = dir.substring(0,j).length() + 1; + name = dir.substring(j+1); + } + + if (destination == null) + { + if (dir.equals("")) + { + destination = destinationParent; + } + else + { + destination = new File(destinationParent, name); + } + } + + if (!(destination == destinationParent)) + { + if (destination.isFile() && destination.exists()) + { + if (!SystemArchiveUtil.delete(destination)) + { + System.out.println("Could not overwrite directory " + destination); + System.out.println("(Could not delete old directory)"); + return false; + } + } + + if (!destination.exists()) + { + if (!destination.mkdirs()) + { + System.out.println("Could not overwrite directory " + destination); + System.out.println("(Could not create new directory)"); + return false; + } + } + } + + File topFile = destination; + String topFilePath = topFile.getAbsolutePath().replace('\\', '/'); + //if (!dir.equals(topFile.getName())) + if (!topFilePath.endsWith(dir)) + { + rename(dir, topFile.getName()); + dir = topFile.getName(); + } + VirtualChild[] newChildren = getVirtualChildrenList(dir); + + + extractVirtualFile(dir + '/', topFile, sourceEncoding, isText); + + for (int i = 0; i < newChildren.length; i++) + { + String newName = newChildren[i].fullName.substring(charsToTrim); + char separator = File.separatorChar; + newName = newName.replace('/', separator); + + File nextFile = new File(destinationParent, newName); + /* + // DKM: case where a rename has taken place + // don't want to extract root folder as it appears in zip + if (!nextFile.getParent().equals(destination.getPath()) && + nextFile.getParentFile().getParent().equals(destination.getParent())) + { + nextFile = new File(destination, nextFile.getName()); + } + */ + if (!nextFile.exists()) + { + if (newChildren[i].isDirectory) + { + if (!nextFile.mkdirs()) + { + System.out.println("Could not create folder " + nextFile.toString()); + return false; + } + } + else + { + createFile(nextFile); + } + boolean success = false; + if (newChildren[i].isDirectory) + { + success = extractVirtualFile(newChildren[i].fullName + '/', nextFile, sourceEncoding, isText); + } + else + { + success = extractVirtualFile(newChildren[i].fullName, nextFile, sourceEncoding, isText); + } + if (!success) return false; + } + } + return true; + } + + protected boolean createFile(File file) + { + try + { + if (!file.createNewFile()) + { + System.out.println("File already exists: " + file.toString()); + return false; + } + else + { + return true; + } + } + catch (IOException e) + { + if (!file.getParentFile().exists() && file.getParentFile().mkdirs()) + { + return createFile(file); + } + else + { + System.out.println("Could not create " + file.toString()); + System.out.println(e.getMessage()); + return false; + } + } + } + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File, java.lang.String, java.lang.String) + */ + public boolean add(File file, String virtualPath, String name) + { + return add(file, virtualPath, name, SystemEncodingUtil.ENCODING_UTF_8, SystemEncodingUtil.ENCODING_UTF_8, false); + } + + public boolean add(InputStream stream, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText) + { + if (!_exists) return false; + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + + if (exists(virtualPath + "/" + name)) + { + // wrong method + return replace(virtualPath + "/" + name, stream, name, sourceEncoding, targetEncoding, isText); + } + else + { + if (openZipFile()) + { + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + File outputTempFile; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + + // if it is an empty zip file, no need to recreate it + if (!(vcList.length == 1) || !vcList[0].fullName.equals("")) + { + recreateZipDeleteEntries(vcList, dest, null); + } + + // append the additional entry to the zip file. + ZipEntry newEntry = appendBytes(stream, dest, virtualPath, name, sourceEncoding, targetEncoding, isText); + // Add the new entry to the virtual file system in memory + fillBranch(newEntry); + + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + } + catch (IOException e) + { + System.out.println("Could not add a file."); + System.out.println(e.getMessage()); + closeZipFile(); + return false; + } + closeZipFile(); + return true; + } + else return false; + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#add(java.io.File[], java.lang.String, java.lang.String[]) + */ + public boolean add(File[] files, String virtualPath, String[] names) + { + String[] encodings = new String[files.length]; + boolean[] isTexts = new boolean[files.length]; + for (int i = 0; i < files.length; i++) + { + encodings[i] = SystemEncodingUtil.ENCODING_UTF_8; + isTexts[i] = false; + } + return add(files, virtualPath, names, encodings, encodings, isTexts, true); + } + + public boolean add(File[] files, String virtualPath, String[] names, String[] sourceEncodings, String[] targetEncodings, boolean[] isText) + { + return add(files, virtualPath, names, sourceEncodings, targetEncodings, isText, true); + } + + + /** + * Same as add(File[] files, String virtualPath, String[] names, String[] encodings) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public boolean add(File[] files, String virtualPath, String[] names, String[] sourceEncodings, String[] targetEncodings, boolean[] isText, boolean closeZipFile) + { + if (!_exists) return false; + if (openZipFile()) + { + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + int numFiles = files.length; + for (int i = 0; i < numFiles; i++) + { + if (!files[i].exists() || !files[i].canRead()) return false; + if (exists(virtualPath + "/" + names[i])) + { + // sorry, wrong method buddy + return replace(virtualPath + "/" + names[i], files[i], names[i]); + } + } + File outputTempFile; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + + // if it is an empty zip file, no need to recreate it + if (!(vcList.length == 1) || !vcList[0].fullName.equals("")) + { + recreateZipDeleteEntries(vcList, dest, null); + } + + // Now for each new file to add + for (int i = 0; i < numFiles; i++) + { + // append the additional entry to the zip file. + ZipEntry newEntry = appendFile(files[i], dest, virtualPath, names[i], sourceEncodings[i], targetEncodings[i], isText[i]); + // Add the new entry to the virtual file system in memory + fillBranch(newEntry); + } + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + } + catch (IOException e) + { + System.out.println("Could not add a file."); + System.out.println(e.getMessage()); + if (closeZipFile) closeZipFile(); + return false; + } + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + /** + * Helper method. . . populates found with a + * collapsed list of all nodes in the subtree + * of the file system rooted at parent. + */ + public static void listAllFiles(File parent, HashSet found) + { + File[] children = parent.listFiles(); + if (children == null) // DKM - 56031, no authority on parent yields null + { + found.remove(parent); + return; + } + for (int i = 0; i < children.length; i++) + { + if (!found.contains(children[i])) // prevent infinite loops due to symlinks + { + if (children[i].canRead()) + { + found.add(children[i]); + if (children[i].isDirectory()) + { + listAllFiles(children[i], found); + } + } + } + } + } + + /** + * Recreates a zip file from a list of virtual children, optionally + * omitting a group of children whose names are in the Set omitChildren + * @param vcList The list of virtual children to create the zip from + * @param dest The ZipOutputStream representing the zip file where the + * children are to be recreated + * @param omitChildren The set of names of children to omit when creating + * the zipfile. Null or empty set if there are no ommisions. + * @throws IOException + */ + protected void recreateZipDeleteEntries(VirtualChild[] vcList, ZipOutputStream dest, HashSet omitChildren) throws IOException + { + if (!(omitChildren == null) && vcList.length == omitChildren.size()) + { + // the zip file will be empty, but it must have at least one entry, + // so we will put in a dummy entry. + ZipEntry entry = new ZipEntry("/"); + dest.putNextEntry(entry); + dest.closeEntry(); + return; + } + //else + for (int i = 0; i < vcList.length; i++) + { + // for each entry, append it to the new temp zip + // unless it is in the set of omissions + if (omitChildren != null && omitChildren.contains(vcList[i].fullName)) continue; + if (vcList[i].isDirectory) + { + ZipEntry nextEntry = safeGetEntry(vcList[i].fullName + "/"); + dest.putNextEntry(nextEntry); + dest.closeEntry(); + continue; + } + ZipEntry nextEntry = safeGetEntry(vcList[i].fullName); + BufferedInputStream source = new BufferedInputStream( + _zipfile.getInputStream(nextEntry)); + nextEntry.setCompressedSize(-1); + dest.putNextEntry(nextEntry); + byte[] buf = new byte[1024]; + int numRead = source.read(buf); + + while (numRead > 0) + { + dest.write(buf, 0, numRead); + numRead = source.read(buf); + } + dest.closeEntry(); + source.close(); + } + } + + /** + * Recreates a zip file from a list of virtual children, but renaming the + * one of the VirtualChildren. + * @param vcList The list of virtual children to create the zip from + * @param dest The ZipOutputStream representing the zip file where the + * children are to be recreated + * @param oldName The name of the virtual child to rename + * @param newName The new name for the renamed virtual child. + * @throws IOException + */ + protected void recreateZipRenameEntries(VirtualChild[] vcList, ZipOutputStream dest, HashMap names) throws IOException + { + for (int i = 0; i < vcList.length; i++) + { + // for each entry, append it to the new temp zip + ZipEntry nextEntry; + ZipEntry newEntry; + if (names.containsKey(vcList[i].getArchiveStandardName())) + { + // rename the entry + String oldName = vcList[i].getArchiveStandardName(); + String newName = (String) names.get(oldName); + vcList[i].renameTo(newName); + nextEntry = safeGetEntry(oldName); + newEntry = createSafeZipEntry(newName); + newEntry.setComment(nextEntry.getComment()); + newEntry.setExtra(nextEntry.getExtra()); + newEntry.setTime(nextEntry.getTime()); + } + else + { + nextEntry = safeGetEntry(vcList[i].getArchiveStandardName()); + newEntry = nextEntry; + } + if (nextEntry.isDirectory()) + { + dest.putNextEntry(newEntry); + dest.closeEntry(); + continue; + } + BufferedInputStream source = new BufferedInputStream( + _zipfile.getInputStream(nextEntry)); + newEntry.setCompressedSize(-1); + dest.putNextEntry(newEntry); + byte[] buf = new byte[1024]; + int numRead = source.read(buf); + + while (numRead > 0) + { + dest.write(buf, 0, numRead); + numRead = source.read(buf); + } + dest.closeEntry(); + source.close(); + } + } + + /** + * Compresses the contents of file, adding them to the + * ZipFile managed by dest. The file is encoded in the encoding + * specified by encoding. A new entry is created in the + * ZipFile with virtual path and name of virtualPath and name + * respectively. + * @return The ZipEntry that was added to the destination zip file. + * @throws IOException + */ + protected ZipEntry appendFile(File file, ZipOutputStream dest, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText) throws IOException + { + ZipEntry newEntry; + if (file.isDirectory()) + { + String fullName = virtualPath + "/" + name; + if (!fullName.endsWith("/")) fullName = fullName + "/"; + newEntry = createSafeZipEntry(fullName); + } + else + { + newEntry = createSafeZipEntry(virtualPath + "/" + name); + } + newEntry.setTime(file.lastModified()); + dest.putNextEntry(newEntry); + if (!file.isDirectory()) + { + BufferedInputStream source = new BufferedInputStream( + new FileInputStream(file)); + + byte[] buf = new byte[1024]; + int numRead = source.read(buf); + long fileSize = file.length(); + long totalRead = 0; + while (numRead > 0 && totalRead < fileSize) + { + totalRead += numRead; + if (isText) + { + // DKM - if you don't specify numRead here, then buf will get picked up wiht extra bytes from b4!!!! + String bufString = new String(buf, 0, numRead, sourceEncoding); + byte[] convertedBuf = bufString.getBytes(targetEncoding); + int newSize = convertedBuf.length; + dest.write(convertedBuf, 0, newSize); + } + else + { + dest.write(buf, 0, numRead); + } + // specify max size here + long maxRead = 1024; + long deltaLeft = fileSize - totalRead; + if (deltaLeft > 1024) + { + numRead = source.read(buf, 0, (int)maxRead); + } + else + { + numRead = source.read(buf, 0, (int)deltaLeft); + } + + } + dest.closeEntry(); + source.close(); + } + return newEntry; + } + + /** + * Compresses the contents of stream, adding them to the + * ZipFile managed by dest. The stream is encoded in the encoding + * specified by encoding. A new entry is created in the + * ZipFile with virtual path and name of virtualPath and name + * respectively. + * @return The ZipEntry that was added to the destination zip file. + * @throws IOException + */ + protected ZipEntry appendBytes(InputStream stream, ZipOutputStream dest, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText) throws IOException + { + ZipEntry newEntry; + newEntry = createSafeZipEntry(virtualPath + "/" + name); + dest.putNextEntry(newEntry); + BufferedInputStream source = new BufferedInputStream(stream); + + byte[] buf = new byte[1024]; + int numRead = source.read(buf); + long totalRead = 0; + while (numRead > 0 && source.available() > 0) + { + totalRead += numRead; + if (isText) + { + // DKM - if you don't specify numRead here, then buf will get picked up wiht extra bytes from b4!!!! + String bufString = new String(buf, 0, numRead, sourceEncoding); + byte[] convertedBuf = bufString.getBytes(targetEncoding); + int newSize = convertedBuf.length; + dest.write(convertedBuf, 0, newSize); + } + else + { + dest.write(buf, 0, numRead); + } + // specify max size here + long maxRead = 1024; + long deltaLeft = source.available(); + if (deltaLeft > 1024) + { + numRead = source.read(buf, 0, (int)maxRead); + } + else + { + numRead = source.read(buf, 0, (int)deltaLeft); + } + + } + dest.closeEntry(); + source.close(); + return newEntry; + } + + /** + * Replaces the old zip file managed by this SystemZipHandler, with + * the zip file referred to by outputTempFile. + * @throws IOException if outputTempFile cannot be used as a ZipFile. + */ + protected void replaceOldZip(File outputTempFile) throws IOException + { + String oldName = _file.getAbsolutePath(); + _zipfile.close(); + File oldFile = new File(oldName + "old"); + System.out.println(_file.renameTo(oldFile)); + System.out.println(outputTempFile.renameTo(_file)); + _vfsLastModified = _file.lastModified(); + _zipfile = new ZipFile(_file); + oldFile.delete(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#delete(java.lang.String) + */ + public boolean delete(String fullVirtualName) + { + return delete(fullVirtualName, true); + } + + /** + * Same as delete(String fullVirtualName) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public boolean delete(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return false; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + VirtualChild vc = getVirtualFile(fullVirtualName); + VirtualChild[] vcList; + VirtualChild[] vcOmmit = new VirtualChild[1]; + if (!vc.exists()) + { + if (closeZipFile) closeZipFile(); + return false; + } // file doesn't exist + + if (vc.isDirectory) // file is a directory, we must delete the contents + { + vcOmmit = getVirtualChildrenList(fullVirtualName, false); + } + + File outputTempFile = null; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + dest.setMethod(ZipOutputStream.DEFLATED); + + // get all the entries in the old zip + vcList = getVirtualChildrenList(false); + + HashSet omissions = new HashSet(); + + if (vc.isDirectory) + { + for (int i = 0; i < vcOmmit.length; i++) + { + omissions.add(vcOmmit[i].fullName); + } + try + { + safeGetEntry(vc.fullName); + omissions.add(vc.fullName); + } + catch (IOException e) {} + } + else + { + omissions.add(fullVirtualName); + } + + // recreate the zip file without the omissions + recreateZipDeleteEntries(vcList, dest, omissions); + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + // Now update the tree + HashMap hm = (HashMap) _virtualFS.get(vc.path); + hm.remove(vc.name); + if (vc.isDirectory) + { + delTree(vc); + } + } + catch (IOException e) + { + System.out.println(e.getMessage()); + System.out.println("Could not delete " + fullVirtualName); + if (!(outputTempFile == null)) outputTempFile.delete(); + if (closeZipFile) closeZipFile(); + return false; + } + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + /** + * Deletes all the children of the directory VirtualChild vc + * recursively down to the leaves. + * Pre: vc.isDirectory is true + * @param vc The child whose children we are deleting. + */ + protected void delTree(VirtualChild vc) + { + HashMap hm = (HashMap) _virtualFS.get(vc.fullName); + Object[] children = hm.values().toArray(); + for (int i = 0; i < children.length; i++) + { + VirtualChild next = (VirtualChild) children[i]; + hm.remove(next.name); + if (next.isDirectory) delTree(next); + } + return; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#replace(java.lang.String, java.io.File, java.lang.String) + */ + public boolean replace(String fullVirtualName, File file, String name) + { + return replace(fullVirtualName, file, name, true); + } + + /** + * Same as replace(String fullVirtualName, File file, String name) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public boolean replace(String fullVirtualName, File file, String name, boolean closeZipFile) + { + if (!_exists) return false; + + if (!file.exists() || !file.canRead()) return false; + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + if (!exists(fullVirtualName)) + { + // sorry, wrong method buddy + return add(file, fullVirtualName, name); + } + if (openZipFile()) + { + File outputTempFile = null; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + HashSet omissions = new HashSet(); + omissions.add(fullVirtualName); + recreateZipDeleteEntries(vcList, dest, omissions); + + // Now append the additional entry to the zip file. + int i = fullVirtualName.lastIndexOf("/"); + String virtualPath; + if (i == -1) + { + virtualPath = ""; + } + else + { + virtualPath = fullVirtualName.substring(0,i); + } + ZipEntry newEntry = appendFile(file, dest, virtualPath, name, SystemEncodingUtil.ENCODING_UTF_8, SystemEncodingUtil.ENCODING_UTF_8, false); + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + } + catch (IOException e) + { + System.out.println("Could not replace " + file.getName()); + if (!(outputTempFile == null)) outputTempFile.delete(); + if (closeZipFile) closeZipFile(); + return false; + } + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + public boolean replace(String fullVirtualName, InputStream stream, String name, String sourceEncoding, String targetEncoding, boolean isText) + { + if (!_exists) return false; + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + if (!exists(fullVirtualName)) + { + // wrong method + return add(stream, fullVirtualName, name, sourceEncoding, targetEncoding, isText); + } + if (openZipFile()) + { + File outputTempFile = null; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + HashSet omissions = new HashSet(); + omissions.add(fullVirtualName); + recreateZipDeleteEntries(vcList, dest, omissions); + + // Now append the additional entry to the zip file. + int i = fullVirtualName.lastIndexOf("/"); + String virtualPath; + if (i == -1) + { + virtualPath = ""; + } + else + { + virtualPath = fullVirtualName.substring(0,i); + } + ZipEntry newEntry = appendBytes(stream, dest, virtualPath, name, sourceEncoding, targetEncoding, isText); + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + } + catch (IOException e) + { + System.out.println("Could not replace " + fullVirtualName); + if (!(outputTempFile == null)) outputTempFile.delete(); + closeZipFile(); + return false; + } + closeZipFile(); + return true; + } + else return false; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#fullRename(java.lang.String, java.lang.String) + */ + public boolean fullRename(String fullVirtualName, String newFullVirtualName) + { + return fullRename(fullVirtualName, newFullVirtualName, true); + } + + /** + * Same as fullRename(String fullVirtualName, String newFullVirtualName) but you can choose whether + * or not you want to leave the zipfile open after return. + */ + public boolean fullRename(String fullVirtualName, String newFullVirtualName, boolean closeZipFile) + { + if (!_exists) return false; + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + newFullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(newFullVirtualName); + VirtualChild vc = getVirtualFile(fullVirtualName); + if (!vc.exists()) + { + System.out.println("The virtual file " + fullVirtualName + " does not exist."); + return false; + } + if (openZipFile()) + { + File outputTempFile = null; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + VirtualChild[] renameList; + HashMap names = new HashMap(); + // if the entry to rename is a directory, we must then rename + // all files and directories below it en masse. + if (vc.isDirectory) + { + renameList = getVirtualChildrenList(fullVirtualName, false); + for (int i = 0; i < renameList.length; i++) + { + int j = fullVirtualName.length(); + String suffix = renameList[i].fullName.substring(j); + String newName = newFullVirtualName + suffix; + if (renameList[i].isDirectory) + { + newName = newName + "/"; + names.put(renameList[i].fullName + "/", newName); + } + else + { + names.put(renameList[i].fullName, newName); + } + } + try + { + safeGetEntry(fullVirtualName); + names.put(fullVirtualName + "/", newFullVirtualName + "/"); + } + catch (IOException e) {} + } + else + { + names.put(fullVirtualName, newFullVirtualName); + } + // find the entry to rename and rename it + recreateZipRenameEntries(vcList, dest, names); + + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + // Now rebuild the tree + buildTree(); + } + catch (IOException e) + { + System.out.println("Could not rename " + fullVirtualName); + if (!(outputTempFile == null)) outputTempFile.delete(); + if (closeZipFile) closeZipFile(); + return false; + } + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#move(java.lang.String, java.lang.String) + */ + public boolean move(String fullVirtualName, String destinationVirtualPath) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + destinationVirtualPath = ArchiveHandlerManager.cleanUpVirtualPath(destinationVirtualPath); + int i = fullVirtualName.lastIndexOf("/"); + if (i == -1) + { + return fullRename(fullVirtualName, destinationVirtualPath + "/" + fullVirtualName); + } + String name = fullVirtualName.substring(i); + return fullRename(fullVirtualName, destinationVirtualPath + name); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#rename(java.lang.String, java.lang.String) + */ + public boolean rename(String fullVirtualName, String newName) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + int i = fullVirtualName.lastIndexOf("/"); + if (i == -1) + { + return fullRename(fullVirtualName, newName); + } + String fullNewName = fullVirtualName.substring(0, i+1) + newName; + return fullRename(fullVirtualName, fullNewName); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getFiles(java.lang.String[]) + */ + public File[] getFiles(String[] fullNames) + { + if (!_exists) return new File[0]; + + File[] files = new File[fullNames.length]; + for (int i = 0; i < fullNames.length; i++) + { + String name; + String fullName = fullNames[i]; + fullName = ArchiveHandlerManager.cleanUpVirtualPath(fullName); + int j = fullName.lastIndexOf("/"); + if (j == -1) + { + name = fullName; + } + else + { + name = fullName.substring(j+1); + } + try + { + files[i] = File.createTempFile(name, "virtual"); + files[i].deleteOnExit(); + extractVirtualFile(fullNames[i], files[i]); + } + catch (IOException e) + { + System.out.println(e.getMessage()); + System.out.println("Could not extract virtual file: " + fullNames[i]); + return null; + } + } + return files; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#createFolder(java.lang.String) + */ + public boolean createFolder(String name) + { + name = ArchiveHandlerManager.cleanUpVirtualPath(name); + name = name + "/"; + return createVirtualObject(name, true); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#createFile(java.lang.String) + */ + public boolean createFile(String name) + { + name = ArchiveHandlerManager.cleanUpVirtualPath(name); + return createVirtualObject(name, true); + } + + /** + * Creates a new, empty object in the virtual File system, and + * creates an empty file or folder in the physical zip file. + * @param name The name of the file or folder to create. The object + * created will be a folder if and only if + * name ends in a "/". + * @return Whether the creation was successful or not. + */ + protected boolean createVirtualObject(String name, boolean closeZipFile) + { + if (!_exists) return false; + if (exists(name)) + { + // The object already exists. + return false; + } + + if (openZipFile()) + { + File outputTempFile; + try + { + // Open a new tempfile which will be our destination for the new zip + outputTempFile = new File(_file.getAbsolutePath() + "temp"); + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(outputTempFile)); + dest.setMethod(ZipOutputStream.DEFLATED); + // get all the entries in the old zip + VirtualChild[] vcList = getVirtualChildrenList(false); + + // if it is an empty zip file, no need to recreate it + if (!(vcList.length == 1) || !vcList[0].fullName.equals("")) + { + recreateZipDeleteEntries(vcList, dest, null); + } + + // append the additional entry to the zip file. + ZipEntry newEntry = appendEmptyFile(dest, name); + // Add the new entry to the virtual file system in memory + fillBranch(newEntry); + + dest.close(); + + // Now replace the old zip file with the new one + replaceOldZip(outputTempFile); + + } + catch (IOException e) + { + System.out.println("Could not add a file."); + System.out.println(e.getMessage()); + if (closeZipFile) closeZipFile(); + return false; + } + if (closeZipFile) closeZipFile(); + return true; + } + else return false; + } + + /** + * Works similarly to appendFile, except no actual data is appended + * to the zipfile, only an entry is created. Thus, if the file were + * to be extracted, it would be of length 0. + * @param dest The destination zip stream to append the entry. + * @param name The new, virtual fullname to give the entry. + * @return The ZipEntry that was created. + * @throws IOException If there was an error appending the entry to the stream. + */ + protected ZipEntry appendEmptyFile(ZipOutputStream dest, String name) throws IOException + { + boolean isDirectory = name.endsWith("/"); + ZipEntry newEntry; + newEntry = createSafeZipEntry(name); + dest.putNextEntry(newEntry); + if (!isDirectory) + { + dest.write(new byte[0], 0, 0); + dest.closeEntry(); + } + return newEntry; + } + + /** + * A "safe" ZipEntry is one whose virtual path does not begin with a + * "/". This seems to cause the least problems for archive utilities, + * including this one. + * @param name The virtual name for the new, safe ZipEntry. + * @return The ZipEntry that is created. + */ + protected ZipEntry createSafeZipEntry(String name) + { + if (name.startsWith("/")) name = name.substring(1); + return new ZipEntry(name); + } + + public String getStandardName(VirtualChild vc) + { + if (vc.isDirectory) return vc.fullName + "/"; + return vc.fullName; + } + + /** + * Opens the zipfile that this handler manages. + * @return Whether the zipfile was successfully opened. + */ + protected boolean openZipFile() + { + if (!(_zipfile == null)) closeZipFile(); + try + { + _zipfile = new ZipFile(_file); + } + catch (IOException e) + { + System.out.println("Could not open zipfile: " + _file); + System.out.println(e.getMessage()); + return false; + } + return true; + } + + protected boolean closeZipFile() + { + try + { + _zipfile.close(); + } + catch (IOException e) + { + System.out.println("Could not close zipfile: " + _file); + System.out.println(e.getMessage()); + return false; + } + return true; + } + + /** + * If the mod-times of the underlying zip file and the file used to + * create the virtualFS are different, update the virtualFS. + * @return whether or not the op was successful. + */ + protected boolean updateVirtualFSIfNecessary() + { + if (_vfsLastModified != _file.lastModified()) + { + if (openZipFile()) + { + buildTree(); + _vfsLastModified = _file.lastModified(); + closeZipFile(); + return true; + } + else return false; + } + else return true; + } + + /** + * Returns the entry corresponding to name from _zipfile. Never returns + * null, but rather, throws an IOException if it cannot find the entry. Tries to retrieve + * both name and "/" + name, to accomodate for zipfiles created + * in a unix environment. ASSUMES THAT _zipfile IS ALREADY OPEN! + */ + protected ZipEntry safeGetEntry(String name) throws IOException + { + ZipEntry entry = _zipfile.getEntry(name); + if (entry == null) entry = _zipfile.getEntry("/" + name); + if (entry == null) throw new IOException("SystemZipHandler.safeGetEntry(): The ZipEntry " + name + " cannot be found in " + _file.toString()); + return entry; + } + + public boolean create() + { + try + { + // The zipfile is our destination + ZipOutputStream dest = new ZipOutputStream( + new FileOutputStream(_file)); + dest.setMethod(ZipOutputStream.DEFLATED); + + VirtualChild[] vcList = new VirtualChild[0]; + + HashSet omissions = new HashSet(); + // the above two statements force recreateZipDeleteEntries to create a dummy entry + recreateZipDeleteEntries(vcList, dest, omissions); + dest.close(); + + if (openZipFile()) + { + buildTree(); + closeZipFile(); + } + else + { + return false; + } + } + catch (IOException e) + { + System.out.println(e.getMessage()); + return false; + } + _exists = true; + return true; + } + + public SystemSearchLineMatch[] search(String fullVirtualName, SystemSearchStringMatcher matcher) + { + + // if the search string is empty or if it is "*", then return no matches + // since it is a file search + if (matcher.isSearchStringEmpty() || matcher.isSearchStringAsterisk()) { + return new SystemSearchLineMatch[0]; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + VirtualChild vc = getVirtualFile(fullVirtualName); + + if (!vc.exists() || vc.isDirectory) { + return new SystemSearchLineMatch[0]; + } + + if (openZipFile()) { + + ZipEntry entry = null; + + SystemSearchLineMatch[] matches = null; + + try + { + entry = safeGetEntry(fullVirtualName); + InputStream is = _zipfile.getInputStream(entry); + + if (is == null) + { + return new SystemSearchLineMatch[0]; + } + + InputStreamReader isr = new InputStreamReader(is); + BufferedReader bufReader = new BufferedReader(isr); + + SystemSearchStringMatchLocator locator = new SystemSearchStringMatchLocator(bufReader, matcher); + matches = locator.locateMatches(); + } + catch (IOException e) + { + System.out.println(e.getMessage()); + } + + closeZipFile(); + + if (matches == null) { + return new SystemSearchLineMatch[0]; + } + else { + return matches; + } + } + else { + return new SystemSearchLineMatch[0]; + } + } + + public boolean exists() + { + return _exists; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#getCommentFor(java.lang.String) + */ + public String getCommentFor(String fullVirtualName) + { + return getCommentFor(fullVirtualName, true); + } + + /** + * same as getCommentFor(String) but you can choose whether or not to leave + * the zipfile open after the method is closed + */ + public String getCommentFor(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return ""; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + } + catch (IOException e) + { + if (closeZipFile) closeZipFile(); + return ""; + } + if (closeZipFile) closeZipFile(); + String comment = entry.getComment(); + if (comment == null) return ""; + else return comment; + } + else return ""; + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.core.archiveutils.ISystemArchiveHandler#getCompressedSizeFor(java.lang.String) + */ + public long getCompressedSizeFor(String fullVirtualName) + { + return getCompressedSizeFor(fullVirtualName, true); + } + + /** + * same as getCompressedSizeFor(String) but you can choose whether or not to leave + * the zipfile open after the method is closed + */ + public long getCompressedSizeFor(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return 0; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + } + catch (IOException e) + { + if (closeZipFile) closeZipFile(); + return 0; + } + if (closeZipFile) closeZipFile(); + return entry.getCompressedSize(); + } + else return 0; + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.core.archiveutils.ISystemArchiveHandler#getCompressionMethodFor(java.lang.String) + */ + public String getCompressionMethodFor(String fullVirtualName) + { + return getCompressionMethodFor(fullVirtualName, true); + } + + /** + * same as getCompressionMethodFor(String) but you can choose whether or not to leave + * the zipfile open after the method is closed + */ + public String getCompressionMethodFor(String fullVirtualName, boolean closeZipFile) + { + if (!_exists) return ""; + + if (openZipFile()) + { + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + ZipEntry entry = null; + try + { + entry = safeGetEntry(fullVirtualName); + } + catch (IOException e) + { + if (closeZipFile) closeZipFile(); + return ""; + } + if (closeZipFile) closeZipFile(); + return (new Integer(entry.getMethod())).toString(); + } + else return ""; + } + /* (non-Javadoc) + * @see com.ibm.etools.systems.core.archiveutils.ISystemArchiveHandler#getArchiveComment() + */ + public String getArchiveComment() + { + return ""; + } + + /** + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#isExecutable(java.lang.String) + */ + public String getClassification(String fullVirtualName) { + return getClassification(fullVirtualName, true); + } + + /** + * Same as getClassification(String), but you can choose whether to leave the zip file + * open after the method is closed. + * @see org.eclipse.rse.services.clientserver.archiveutils.ISystemArchiveHandler#isExecutable(java.lang.String) + */ + public String getClassification(String fullVirtualName, boolean closeZipFile) { + + // default type + String type = "file"; + + if (!_exists) { + return type; + } + + fullVirtualName = ArchiveHandlerManager.cleanUpVirtualPath(fullVirtualName); + + // if it's not a class file, we do not classify it + if (!fullVirtualName.endsWith(".class")) { + return type; + } + + // class file parser + BasicClassFileParser parser = null; + + boolean isExecutable = false; + + if (openZipFile()) { + + // get the input stream for the entry + InputStream stream = null; + + try { + ZipEntry entry = safeGetEntry(fullVirtualName); + stream = _zipfile.getInputStream(entry); + + // use class file parser to parse the class file + parser = new BasicClassFileParser(stream); + parser.parse(); + + // query if it is executable, i.e. whether it has main method + isExecutable = parser.isExecutable(); + + if (closeZipFile) { + closeZipFile(); + } + } + catch (IOException e) { + + if (closeZipFile) { + closeZipFile(); + } + + return type; + } + } + + // if it is executable, then also get qualified class name + if (isExecutable) { + type = "executable(java"; + + String qualifiedClassName = parser.getQualifiedClassName(); + + if (qualifiedClassName != null) { + type = type + ":" + qualifiedClassName; + } + + type = type + ")"; + } + + return type; + } + + public boolean add(File file, String virtualPath, String name, String sourceEncoding, String targetEncoding, ISystemFileTypes registry) + { + if (!_exists) return false; + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + if (!file.isDirectory()) + { + if (exists(virtualPath + "/" + name)) + { + // wrong method + return replace(virtualPath + "/" + name, file, name); + } + else + { + File[] files = new File[1]; + files[0] = file; + String[] names = new String[1]; + names[0] = name; + String[] sourceEncodings = new String[1]; + sourceEncodings[0] = sourceEncoding; + String[] targetEncodings = new String[1]; + targetEncodings[0] = targetEncoding; + boolean[] isTexts = new boolean[1]; + isTexts[0] = registry.isText(file); + return add(files, virtualPath, names, sourceEncodings, targetEncodings, isTexts); + } + } + else + { + String sourceName = name; + HashSet children = new HashSet(); + listAllFiles(file, children); + File[] sources = new File[children.size() + 1]; + String[] newNames = new String[children.size() + 1]; + Object[] kids = children.toArray(); + String[] sourceEncodings = new String[children.size() + 1]; + String[] targetEncodings = new String[children.size() + 1]; + boolean[] isTexts = new boolean[children.size() + 1]; + int charsToTrim = file.getParentFile().getAbsolutePath().length() + 1; + if (file.getParentFile().getAbsolutePath().endsWith(File.separator)) charsToTrim--; // accounts for root + for (int i = 0; i < children.size(); i++) + { + sources[i] = (File) kids[i]; + newNames[i] = sources[i].getAbsolutePath().substring(charsToTrim); + newNames[i] = newNames[i].replace('\\','/'); + if (sources[i].isDirectory() && !newNames[i].endsWith("/")) newNames[i] = newNames[i] + "/"; + + // this part can be changed to allow different encodings for different files + sourceEncodings[i] = sourceEncoding; + targetEncodings[i] = targetEncoding; + isTexts[i] = registry.isText(sources[i]); + } + sources[children.size()] = file; + newNames[children.size()] = name; + sourceEncodings[children.size()] = sourceEncoding; + targetEncodings[children.size()] = targetEncoding; + + isTexts[children.size()] = registry.isText(file); + if (!newNames[children.size()].endsWith("/")) newNames[children.size()] = newNames[children.size()] + "/"; + return add(sources, virtualPath, newNames, sourceEncodings, targetEncodings, isTexts); + } + } + + public boolean add(File file, String virtualPath, String name, String sourceEncoding, String targetEncoding, boolean isText) + { + if (!_exists) return false; + virtualPath = ArchiveHandlerManager.cleanUpVirtualPath(virtualPath); + if (!file.isDirectory()) + { + if (exists(virtualPath + "/" + name)) + { + // wrong method + return replace(virtualPath + "/" + name, file, name); + } + else + { + File[] files = new File[1]; + files[0] = file; + String[] names = new String[1]; + names[0] = name; + String[] sourceEncodings = new String[1]; + sourceEncodings[0] = sourceEncoding; + String[] targetEncodings = new String[1]; + targetEncodings[0] = targetEncoding; + boolean[] isTexts = new boolean[1]; + isTexts[0] = isText; + return add(files, virtualPath, names, sourceEncodings, targetEncodings, isTexts); + } + } + else + { + String sourceName = name; + HashSet children = new HashSet(); + listAllFiles(file, children); + File[] sources = new File[children.size() + 1]; + String[] newNames = new String[children.size() + 1]; + Object[] kids = children.toArray(); + String[] sourceEncodings = new String[children.size() + 1]; + String[] targetEncodings = new String[children.size() + 1]; + boolean[] isTexts = new boolean[children.size() + 1]; + int charsToTrim = file.getParentFile().getAbsolutePath().length() + 1; + if (file.getParentFile().getAbsolutePath().endsWith(File.separator)) charsToTrim--; // accounts for root + for (int i = 0; i < children.size(); i++) + { + sources[i] = (File) kids[i]; + newNames[i] = sources[i].getAbsolutePath().substring(charsToTrim); + newNames[i] = newNames[i].replace('\\','/'); + if (sources[i].isDirectory() && !newNames[i].endsWith("/")) newNames[i] = newNames[i] + "/"; + + // this part can be changed to allow different encodings for different files + sourceEncodings[i] = sourceEncoding; + targetEncodings[i] = targetEncoding; + isTexts[i] = isText; + } + sources[children.size()] = file; + newNames[children.size()] = name; + sourceEncodings[children.size()] = sourceEncoding; + targetEncodings[children.size()] = targetEncoding; + isTexts[children.size()] = isText; + if (!newNames[children.size()].endsWith("/")) newNames[children.size()] = newNames[children.size()] + "/"; + return add(sources, virtualPath, newNames, sourceEncodings, targetEncodings, isTexts); + } + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/VirtualChild.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/VirtualChild.java new file mode 100644 index 00000000000..0d2eebf9365 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/archiveutils/VirtualChild.java @@ -0,0 +1,321 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.archiveutils; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.rse.services.clientserver.SystemEncodingUtil; + + +/** + * @author mjberger + * A simple structure for passing information about virtual files and folders. + */ +public final class VirtualChild { + + public String fullName; + public String name; + public String path; + public boolean isDirectory; + protected ISystemArchiveHandler _handler; + protected File _extractedFile; + protected File _containingArchive; + + /** + * Constructs a new VirtualChild given a reference to its parent archive's + * handler, but does not populate any fields in the child. Clients must + * populate the fullName, name, path, and isDirectory fields. + */ + public VirtualChild(ISystemArchiveHandler handler) + { + fullName = ""; + name = ""; + path = ""; + isDirectory = false; + _handler = handler; + _extractedFile = null; + _containingArchive = null; + } + + /** + * Constructs a new VirtualChild given a reference to its parent archive's + * handler (handler), and immediately populates the name and path info + * for the VirtualChild given its fullVirtualName. Clients + * must still populate the isDirectory field. + */ + public VirtualChild(ISystemArchiveHandler handler, String fullVirtualName) + { + this(handler); + renameTo(fullVirtualName); + } + + /** + * Constructs a new VirtualChild given the name of its parent archive, + * and immediately populates the name and path info + * for the VirtualChild given its fullVirtualName. Clients + * must still populate the isDirectory field. + * NOTE: This constructor is intended only to be used for creating NON-EXISTENT + * virtual children. + */ + public VirtualChild(String fullVirtualName, File containingArchive) + { + this(null); + renameTo(fullVirtualName); + _containingArchive = containingArchive; + } + + /** + * @return This VirtualChild's parent archive's Handler. + */ + public ISystemArchiveHandler getHandler() + { + return _handler; + } + + /** + * @return This VirtualChild's time stamp (retrieves the latest one + * from the archive). + */ + public long getTimeStamp() + { + if (_handler == null) return 0; + return _handler.getTimeStampFor(fullName); + } + + /** + * @return This VirtualChild's uncompressed size (retrieves the latest one + * from the archive). + */ + public long getSize() + { + if (_handler == null) return 0; + return _handler.getSizeFor(fullName); + } + + /** + * @return The comment associated with this VirtualChild. + */ + public String getComment() + { + if (_handler == null) return ""; + return _handler.getCommentFor(fullName); + } + + /** + * @return The amount of space this VirtualChild takes up in the archive + * in compressed form. + */ + public long getCompressedSize() + { + if (_handler == null) return 0; + return _handler.getCompressedSizeFor(fullName); + } + + /** + * @return The method used to compress this VirtualChild. + */ + public String getCompressionMethod() + { + if (_handler == null) return ""; + return _handler.getCompressionMethodFor(fullName); + } + + /** + * @return The actual minus compressed size of this VirtualChild, divided + * by the actual size. + */ + public double getCompressionRatio() + { + if (getSize() == 0) + { + return 1; + } + else return ((double)getSize() - (double)getCompressedSize()) / getSize(); + } + + /** + * @return The extracted file or directory represented by this VirtualChild from the archive. + * Note that the extracted file is cached after it is extracted once, but if the + * timestamps on the cached and archived files do not match, the cached file is erased, + * and reextracted from the archive. + */ + public File getExtractedFile() + { + return getExtractedFile(SystemEncodingUtil.ENCODING_UTF_8, false); + } + + /** + * @return The extracted file or directory represented by this VirtualChild from the archive. + * Assumes that the file has been encoded in the encoding specified. + * Note that the extracted file is cached after it is extracted once, but if the + * timestamps on the cached and archived files do not match, the cached file is erased, + * and reextracted from the archive. + */ + public File getExtractedFile(String sourceEncoding, boolean isText) + { + if (_extractedFile == null || _extractedFile.lastModified() != getTimeStamp()) + { + try + { + int i = name.lastIndexOf("."); + String ext = ""; + if (i != -1) ext = name.substring(i+1); + if (i < 3) + { + _extractedFile = File.createTempFile(name + "123", "virtual." + ext); + } + else + { + _extractedFile = File.createTempFile(name, "virtual." + ext); + } + _extractedFile.deleteOnExit(); + if (_handler == null) return _extractedFile; + if (isDirectory) + { + if (!_extractedFile.isDirectory()) + { + if (!(_extractedFile.delete() && _extractedFile.mkdirs())) + { + System.out.println("VirtualChild.getExtractedFile(): Could not create temp dir."); + return null; + } + } + _handler.extractVirtualDirectory(fullName, _extractedFile, sourceEncoding, isText); + } + else + { + _handler.extractVirtualFile(fullName, _extractedFile, sourceEncoding, isText); + } + } + catch (IOException e) + { + System.out.println("VirtualChild.getExtractedFile(): "); + System.out.println(e.getMessage()); + } + } + + if (isDirectory) + { + return new File(_extractedFile, name); + } + else + { + return _extractedFile; + } + } + + /** + * Gets the extracted file or directory represented by this VirtualChild from the archive, + * and replaces the object referred to by destination with that extracted file or directory. + * Note that the extracted file is cached after it is extracted once, but if the + * timestamps on the cached and archived files do not match, the cached file is erased, + * and reextracted from the archive. + * destination is always overwritten with either what is cached, or + * what is in the archive. + * @return true if and only if the extraction succeeded. + */ + public boolean getExtractedFile(File destination) + { + return getExtractedFile(destination, SystemEncodingUtil.ENCODING_UTF_8, false); + } + + /** + * Gets the extracted file or directory represented by this VirtualChild from the archive, + * and replaces the object referred to by destination with that extracted file or directory. + * Note that the extracted file is cached after it is extracted once, but if the + * timestamps on the cached and archived files do not match, the cached file is erased, + * and reextracted from the archive. + * destination is always overwritten with either what is cached, or + * what is in the archive. + * @return true if and only if the extraction succeeded. + */ + public boolean getExtractedFile(File destination, String sourceEncoding, boolean isText) + { + boolean success = true; + if (_handler == null) return false; + if (_extractedFile == null || + _extractedFile.lastModified() != getTimeStamp() || + !destination.getAbsolutePath().equals(_extractedFile.getAbsolutePath()) + ) + { + if (isDirectory) + { + success = _handler.extractVirtualDirectory(fullName, destination.getParentFile(), destination, sourceEncoding, isText); + } + else + { + success = _handler.extractVirtualFile(fullName, destination, sourceEncoding, isText); + } + _extractedFile = destination; + } + return success; + } + + /** + * @return Whether or not this VirtualChild exists in the archive. + */ + public boolean exists() + { + if (_handler == null) return false; + return _handler.exists(fullName); + } + + /** + * Renames this virtual child to newName. WARNING!! + * This method does not change the underlying zip file, + * you must rename the entry in the zip file for subsequent + * calls to any of the getters to work. + */ + public void renameTo(String newName) + { + newName = ArchiveHandlerManager.cleanUpVirtualPath(newName); + fullName = newName; + int i = newName.lastIndexOf("/"); + if (i == -1) + { + name = newName; + path = ""; + } + else + { + name = newName.substring(i+1); + path = newName.substring(0, i); + } + // force reextraction of temp file + _extractedFile = null; + + } + + /** + * @return The "standard" name for this VirtualChild, based on + * the handler type. + */ + public String getArchiveStandardName() + { + if (_handler == null) return fullName; + return _handler.getStandardName(this); + } + + public File getContainingArchive() + { + if (_handler == null) return _containingArchive; + return _handler.getArchive(); + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract4ByteNumericInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract4ByteNumericInfo.java new file mode 100644 index 00000000000..b7bde700fa5 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract4ByteNumericInfo.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents 4 byte numeric information. + */ +public abstract class Abstract4ByteNumericInfo extends AbstractCPInfo { + + protected long bytes; + + /** + * Constructor. + * @param tag the tag. + * @param bytes the bytes. + */ + public Abstract4ByteNumericInfo(short tag, long bytes) { + super(tag); + setBytes(bytes); + } + + /** + * Returns the bytes. + * @return the bytes. + */ + public long getBytes() { + return bytes; + } + + /** + * Sets the bytes. + * @param bytes the bytes. + */ + private void setBytes(long bytes) { + this.bytes = bytes; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract8ByteNumericInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract8ByteNumericInfo.java new file mode 100644 index 00000000000..f019e5f5a2d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/Abstract8ByteNumericInfo.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents 8 byte numeric information. + */ +public abstract class Abstract8ByteNumericInfo extends AbstractCPInfo { + + protected long highBytes; + protected long lowBytes; + + /** + * Constructor. + * @param tag the tag. + * @param highBytes high bytes. + * @param lowBytes low bytes. + */ + public Abstract8ByteNumericInfo(short tag, long highBytes, long lowBytes) { + super(tag); + setHighBytes(highBytes); + setLowBytes(lowBytes); + } + + /** + * Returns the high bytes. + * @return the high bytes. + */ + public long getHighBytes() { + return highBytes; + } + + /** + * Sets the high bytes. + * @param highBytes the high bytes. + */ + private void setHighBytes(long highBytes) { + this.highBytes = highBytes; + } + + /** + * Returns the low bytes. + * @return the low bytes. + */ + public long getLowBytes() { + return lowBytes; + } + + /** + * Sets the low bytes. + * @param lowBytes the low bytes. + */ + private void setLowBytes(long lowBytes) { + this.lowBytes = lowBytes; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractAttributeInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractAttributeInfo.java new file mode 100644 index 00000000000..4e11cd3aff9 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractAttributeInfo.java @@ -0,0 +1,69 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents a attribute. + */ +public class AbstractAttributeInfo { + + protected int attributeNameIndex; + protected long attributeLength; + + /** + * Constructor. + * @param attributeNameIndex the attribute name index. + * @param attributeLength the attribute length. + */ + public AbstractAttributeInfo(int attributeNameIndex, long attributeLength) { + super(); + setAttributeNameIndex(attributeNameIndex); + setAttributeLength(attributeLength); + } + + /** + * Returns the attribute length. + * @return the attribute length. + */ + public long getAttributeLength() { + return attributeLength; + } + + /** + * Sets the attribute length. + * @param attributeLength the attribute length. + */ + public void setAttributeLength(long attributeLength) { + this.attributeLength = attributeLength; + } + + /** + * Returns the attribute name index. + * @return the attribute name index. + */ + public int getAttributeNameIndex() { + return attributeNameIndex; + } + + /** + * Sets the attribute name index. + * @param attributeNameIndex the attribute name index. + */ + public void setAttributeNameIndex(int attributeNameIndex) { + this.attributeNameIndex = attributeNameIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCPInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCPInfo.java new file mode 100644 index 00000000000..559fae7b87e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCPInfo.java @@ -0,0 +1,53 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents various string constants, class and interface names, field names, and other constants + * that are referred to within the BasicClassFileParser structure. + * + * @see BasicClassFileParser + */ +public abstract class AbstractCPInfo { + + protected short tag; + + /** + * Constructor. + * @param tag the tag. + */ + public AbstractCPInfo(short tag) { + super(); + setTag(tag); + } + + /** + * Returns the tag. + * @return the tag. + */ + public int getTag() { + return tag; + } + + /** + * Sets the tag. + * @param tag the tag. + */ + private void setTag(short tag) { + this.tag = tag; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCommonInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCommonInfo.java new file mode 100644 index 00000000000..ab9df6a01bc --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractCommonInfo.java @@ -0,0 +1,125 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents information about a field or method. + */ +public abstract class AbstractCommonInfo { + + protected int accessFlags; + protected int nameIndex; + protected int descriptorIndex; + protected int attributesCount; + protected AbstractAttributeInfo[] attributes; + + /** + * Constructor. + * @param accessFlags the access flags. + * @param nameIndex the name index. + * @param descriptorIndex the descriptor index. + * @param attributesCount the number of attributes. + * @param attributes the attributes. + */ + public AbstractCommonInfo(int accessFlags, int nameIndex, int descriptorIndex, int attributesCount, AbstractAttributeInfo[] attributes) { + super(); + setAccessFlags(accessFlags); + setNameIndex(nameIndex); + setDescriptorIndex(descriptorIndex); + setAttributesCount(attributesCount); + setAttributes(attributes); + } + + /** + * Returns the access flags. + * @return the access flags. + */ + public int getAccessFlags() { + return accessFlags; + } + + /** + * Sets the access flags. + * @param accessFlags the access flags. + */ + public void setAccessFlags(int accessFlags) { + this.accessFlags = accessFlags; + } + + /** + * Returns the attributes. + * @return the array of attributes. + */ + public AbstractAttributeInfo[] getAttributes() { + return attributes; + } + /** + * Sets the attributes. + * @param attributes the attributes. + */ + public void setAttributes(AbstractAttributeInfo[] attributes) { + this.attributes = attributes; + } + + /** + * Returns the number of attributes. + * @return the number of attributes. + */ + public int getAttributesCount() { + return attributesCount; + } + + /** + * Sets the number of attributes. + * @param attributesCount the number of attributes. + */ + public void setAttributesCount(int attributesCount) { + this.attributesCount = attributesCount; + } + + /** + * Returns the descriptor index. + * @return the descriptor index. + */ + public int getDescriptorIndex() { + return descriptorIndex; + } + + /** + * Sets the descriptor index. + * @param descriptorIndex the descriptor index. + */ + public void setDescriptorIndex(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } + + /** + * Returns the name index. + * @return the name index. + */ + public int getNameIndex() { + return nameIndex; + } + + /** + * Sets the name index. + * @param nameIndex the name index. + */ + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractRefInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractRefInfo.java new file mode 100644 index 00000000000..684b85e24ca --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/AbstractRefInfo.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents reference information. + */ +public abstract class AbstractRefInfo extends AbstractCPInfo { + + protected int classIndex; + protected int nameAndTypeIndex; + + /** + * Constructor. + * @param tag the tag. + * @param classIndex the class index. + * @param nameAndTypeIndex + */ + public AbstractRefInfo(short tag, int classIndex, int nameAndTypeIndex) { + super(tag); + setClassIndex(classIndex); + setNameAndTypeIndex(nameAndTypeIndex); + } + + /** + * Returns the class index. + * @return the class index. + */ + public int getClassIndex() { + return classIndex; + } + + /** + * Sets the class index. + * @param classIndex the class index. + */ + private void setClassIndex(int classIndex) { + this.classIndex = classIndex; + } + + /** + * Returns the name and type index. + * @return the name and type index. + */ + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + /** + * Sets the name and type index. + * @param nameAndTypeIndex the name and type index. + */ + private void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/BasicClassFileParser.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/BasicClassFileParser.java new file mode 100644 index 00000000000..2b0ff5a89f2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/BasicClassFileParser.java @@ -0,0 +1,342 @@ +/******************************************************************************** + * Copyright (c) 2004, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * This is a basic class file parser that returns a package name from a class file. + */ +public class BasicClassFileParser implements IClassFileConstants { + + private long magic; + private int minor_version; + private int major_version; + private int constant_pool_count; + private List constant_pool; + private int access_flags; + private int this_class; + private int super_class; + private int interfaces_count; + private int[] interfaces; + private int fields_count; + private int methods_count; + private MethodInfo[] methods; + private int attributes_count; + private InputStream stream; + + /** + * Constuctor. + * @param the input stream to parse. + */ + public BasicClassFileParser(InputStream stream) { + this.stream = stream; + } + + /** + * Returns the package. + * @return the package. + */ + public String getQualifiedClassName() { + + ClassInfo info = (ClassInfo)(getCPInfo(this_class)); + + int nameIndex = info.getNameIndex(); + String name = getString(nameIndex); + + return name.replace('/', '.'); + } + + /** + * Returns whether there is a public static void main(String[]) method. + * @return true if there is, otherwise false. + */ + public boolean isExecutable() { + + for (int i = 0; i < methods_count; i++) { + MethodInfo info = methods[i]; + + // first ensure method name is "main" + int nameIndex = info.getNameIndex(); + String name = getString(nameIndex); + + if (name.equals("main")) { + + // check access flags for public and static + int accessFlags = info.getAccessFlags(); + + if ((accessFlags & 0x000F) == 0x0009) { + + // now check descriptor for parameter and return value + int descriptorIndex = info.getDescriptorIndex(); + String descriptor = getString(descriptorIndex); + + if (descriptor.equals("([Ljava/lang/String;)V")) { + return true; + } + } + } + } + + return false; + } + + /** + * Parses a class file. + * @throws IOException if an I/O error occurs. + */ + public void parse() throws IOException { + + EnhancedDataInputStream dataStream = new EnhancedDataInputStream(stream); + + magic = dataStream.readUnsignedInt(); + minor_version = dataStream.readUnsignedShort(); + major_version = dataStream.readUnsignedShort(); + constant_pool_count = dataStream.readUnsignedShort(); + + readConstantPool(dataStream); + + access_flags = dataStream.readUnsignedShort(); + + this_class = dataStream.readUnsignedShort(); + + super_class = dataStream.readUnsignedShort(); + + interfaces_count = dataStream.readUnsignedShort(); + + readInterfaces(dataStream); + + fields_count = dataStream.readUnsignedShort(); + + readFields(dataStream); + + methods_count = dataStream.readUnsignedShort(); + + readMethods(dataStream); + + dataStream.close(); + } + + /** + * Reads the constant pool. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected void readConstantPool(EnhancedDataInputStream dataStream) throws IOException { + + constant_pool = new ArrayList(); + + for (int i = 0; i < constant_pool_count-1; i++) { + AbstractCPInfo info = readConstantInfo(dataStream); + constant_pool.add(i, info); + + // each long or double info takes two spaces, so fill in the next entry with an empty object + // this entry is not usable according to the VM Specification + if (info instanceof LongInfo || info instanceof DoubleInfo) { + i++; + constant_pool.add(i, new Object()); + } + } + } + + /** + * Gets the constant info. + * @param dataStream the data stream. + * @return the constant info. + * @throws IOException if an I/O error occurs. + */ + protected AbstractCPInfo readConstantInfo(EnhancedDataInputStream dataStream) throws IOException { + short tag = (short)(dataStream.readUnsignedByte()); + + switch (tag) { + + case CONSTANT_CLASS: { + int nameIndex = dataStream.readUnsignedShort(); + return new ClassInfo(tag, nameIndex); + } + case CONSTANT_FIELD_REF: { + int classIndex = dataStream.readUnsignedShort(); + int nameAndTypeIndex = dataStream.readUnsignedShort(); + return new FieldRefInfo(tag, classIndex, nameAndTypeIndex); + } + case CONSTANT_METHOD_REF: { + int classIndex = dataStream.readUnsignedShort(); + int nameAndTypeIndex = dataStream.readUnsignedShort(); + return new MethodRefInfo(tag, classIndex, nameAndTypeIndex); + } + case CONSTANT_INTERFACE_METHOD_REF: { + int classIndex = dataStream.readUnsignedShort(); + int nameAndTypeIndex = dataStream.readUnsignedShort(); + return new InterfaceMethodRefInfo(tag, classIndex, nameAndTypeIndex); + } + case CONSTANT_STRING: { + int stringIndex = dataStream.readUnsignedShort(); + return new StringInfo(tag, stringIndex); + } + case CONSTANT_INTEGER: { + long bytes = dataStream.readUnsignedInt(); + return new IntegerInfo(tag, bytes); + } + case CONSTANT_FLOAT: { + long bytes = dataStream.readUnsignedInt(); + return new FloatInfo(tag, bytes); + } + case CONSTANT_LONG: { + long highBytes = dataStream.readUnsignedInt(); + long lowBytes = dataStream.readUnsignedInt(); + return new LongInfo(tag, highBytes, lowBytes); + } + case CONSTANT_DOUBLE: { + long highBytes = dataStream.readUnsignedInt(); + long lowBytes = dataStream.readUnsignedInt(); + return new DoubleInfo(tag, highBytes, lowBytes); + } + case CONSTANT_NAME_AND_TYPE: { + int nameIndex = dataStream.readUnsignedShort(); + int descriptorIndex = dataStream.readUnsignedShort(); + return new NameAndTypeInfo(tag, nameIndex, descriptorIndex); + } + case CONSTANT_UTF8: { + int length = dataStream.readUnsignedShort(); + short[] bytes = new short[length]; + + for (int i = 0; i < length; i++) { + bytes[i] = (short)(dataStream.readUnsignedByte()); + } + + return new UTF8Info(tag, length, bytes); + } + default: { + return null; + } + } + } + + /** + * Reads the interfaces. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected void readInterfaces(EnhancedDataInputStream dataStream) throws IOException { + interfaces = new int[interfaces_count]; + + for (int i = 0; i < interfaces_count; i++) { + interfaces[i] = dataStream.readUnsignedShort(); + } + } + + /** + * Reads the fields. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected void readFields(EnhancedDataInputStream dataStream) throws IOException { + + for (int i = 0; i < fields_count; i++) { + readField(dataStream); + } + } + + /** + * Reads a field. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected FieldInfo readField(EnhancedDataInputStream dataStream) throws IOException { + int accessFlags = dataStream.readUnsignedShort(); + int nameIndex = dataStream.readUnsignedShort(); + int descriptorIndex = dataStream.readUnsignedShort(); + int attributesCount = dataStream.readUnsignedShort(); + + for (int i = 0; i < attributesCount; i++) { + readAttribute(dataStream); + } + + return null; + } + + /** + * Reads the methods. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected void readMethods(EnhancedDataInputStream dataStream) throws IOException { + + methods = new MethodInfo[methods_count]; + + for (int i = 0; i < methods_count; i++) { + methods[i] = readMethod(dataStream); + } + } + + /** + * Reads a method. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected MethodInfo readMethod(EnhancedDataInputStream dataStream) throws IOException { + + int accessFlags = dataStream.readUnsignedShort(); + int nameIndex = dataStream.readUnsignedShort(); + int descriptorIndex = dataStream.readUnsignedShort(); + int attributesCount = dataStream.readUnsignedShort(); + + for (int i = 0; i < attributesCount; i++) { + readAttribute(dataStream); + } + + return new MethodInfo(accessFlags, nameIndex, descriptorIndex, attributes_count, null); + } + + /** + * Reads an attribute. + * @param dataStream the data stream. + * @throws IOException if an I/O error occurs. + */ + protected AbstractAttributeInfo readAttribute(EnhancedDataInputStream dataStream) throws IOException { + dataStream.skip(2); + long length = dataStream.readUnsignedInt(); + + if (length > 0) { + dataStream.skip(length); + } + + return null; + } + + /** + * Returns the entry at the constant pool index. + * @param index the index. + * @return the constant pool table entry. + */ + protected AbstractCPInfo getCPInfo(int index) { + return (AbstractCPInfo)(constant_pool.get(index-1)); + } + + /** + * Returns the name given an index to the constant pool table. + * The entry at the index must be a UTF8 string entry + */ + protected String getString(int index) { + UTF8Info nameInfo = (UTF8Info)(getCPInfo(index)); + String name = ClassFileUTF8Reader.getInstance().getString(nameInfo.getBytes()); + return name; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUTF8Reader.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUTF8Reader.java new file mode 100644 index 00000000000..5ce413c720c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUTF8Reader.java @@ -0,0 +1,104 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This singleton class converts an array of unsigned bytes (represented by shorts) to UTF-8 + * strings as per the UTF-8 format that the JVM uses. Note that the JVM's version + * of UTF8 is different to the standard UTF-8 format. + */ +public class ClassFileUTF8Reader { + + private static ClassFileUTF8Reader instance; + + /** + * Constructor. + */ + private ClassFileUTF8Reader() { + super(); + } + + /** + * Returns the singleton instance of the reader. + * @return the singleton instance. + */ + public static final ClassFileUTF8Reader getInstance() { + + if (instance == null) { + instance = new ClassFileUTF8Reader(); + } + + return instance; + } + + /** + * Returns a string given an unsigned array of bytes (represented as an array of shorts). Converts to + * a string assuming the bytes represent the UTF8 format used by JVM. + * @param bytes the bytes. + * @return the string. + */ + public String getString(short[] bytes) { + StringBuffer buf = new StringBuffer(); + + char c; + + int i = 0; + + while (i < bytes.length) { + + // first bit is 0 + // char is represented by one byte + // char is in the range '\u0001' to '\u007F' + // format: x byte + // x: 0xxxxxxx + if ((bytes[i] & 0x80) == 0) { + c = (char)(bytes[i]); + i = i + 1; + } + // first three bits are 110 and first two bits of next byte are 10 + // char is represented by two bytes + // char is either null character ('\u0000') or in the range '\u0080' to '\u07FF' + // format: x byte followed by y byte + // x: 110xxxxx + // y: 10xxxxxx + else if (((bytes[i] & 0xE0) == 0xC0) && ((bytes[i+1] & 0xC0) == 0x80)) { + c = (char)(((bytes[i] & 0x1F) << 6) + (bytes[i+1] & 0x3F)); + i = i + 2; + } + // first three bits are 1110 and first two bits of next bytes are 10 + // char is represented by three bytes + // char is in the range '\u0800' to '\uFFFF' + // format: x byte, y byte and z byte + // x: 1110xxxx + // y: 10xxxxxx + // z: 10xxxxxx + else if (((bytes[i] & 0xF0) == 0xE0) && ((bytes[i+1] & 0xC0) == 0x80) && ((bytes[i+2] & 0xC0) == 0x80)) { + c = (char)(((bytes[i] & 0x0F) << 12) + ((bytes[i+1] & 0x3F) << 6) + (bytes[i+2] & 0x3F)); + i = i + 3; + } + // we should not never be here + else { + continue; + } + + // append character + buf.append(c); + } + + return buf.toString(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUtil.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUtil.java new file mode 100644 index 00000000000..6720ccd22df --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassFileUtil.java @@ -0,0 +1,118 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Singleton class for obtaining various information about class files. + */ +public class ClassFileUtil { + + private static ClassFileUtil instance; + + /** + * Constructor. + */ + private ClassFileUtil() { + super(); + } + + /** + * Returns the singleton instance. + * @return the singleton instance. + */ + public static final ClassFileUtil getInstance() { + + if (instance == null) { + instance = new ClassFileUtil(); + } + + return instance; + } + + /** + * Returns whether the class with the given path is runnable, i.e. whether it contains public + * static void main (String[]) method. + * @param classFilePath the class file path. + * @return true if the class file is runnable, false otherwise. + * @throws IOException if an I/O error occurs. + */ + public boolean isRunnable(String classFilePath) throws IOException { + File classFile = new File(classFilePath); + return isRunnable(classFile); + } + + /** + * Returns whether the class is runnable, i.e. whether it contains public + * static void main (String[]) method. + * @param classFile the class file. + * @return true if the class file is runnable, false otherwise. + * @throws IOException if an I/O error occurs. + */ + public boolean isRunnable(File classFile) throws IOException { + FileInputStream stream = new FileInputStream(classFile); + return isRunnable(stream); + } + + /** + * Returns whether the class represented by the given input stream is runnable, + * i.e. whether it contains public static void main (String[]) method. + * @param stream the input stream. + * @return true if the class file is runnable, false otherwise. + * @throws IOException if an I/O error occurs. + */ + public boolean isRunnable(InputStream stream) throws IOException { + BasicClassFileParser parser = new BasicClassFileParser(stream); + parser.parse(); + return parser.isExecutable(); + } + + /** + * Gets the qualified class name for the file with the given path. + * @param classFilePath the class file path. + * @throws IOException if an I/O error occurs. + */ + public String getQualifiedClassName(String classFilePath) throws IOException { + File classFile = new File(classFilePath); + return getQualifiedClassName(classFile); + } + + /** + * Gets the qualified class name. + * @param classFile the class file. + * @throws IOException if an I/O error occurs. + */ + public String getQualifiedClassName(File classFile) throws IOException { + FileInputStream stream = new FileInputStream(classFile); + return getQualifiedClassName(stream); + } + + /** + * Gets the qualified class name for the class represented by the given input stream. + * @param classFilePath the class file path. + * @throws IOException if an I/O error occurs. + */ + public String getQualifiedClassName(InputStream stream) throws IOException { + BasicClassFileParser parser = new BasicClassFileParser(stream); + parser.parse(); + return parser.getQualifiedClassName(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassInfo.java new file mode 100644 index 00000000000..06fb88de2ab --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/ClassInfo.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents class information. + */ +public class ClassInfo extends AbstractCPInfo { + + protected int nameIndex; + + /** + * Constructor. + * @param tag the tag. + * @param nameIndex the name index. + */ + public ClassInfo(short tag, int nameIndex) { + super(tag); + setNameIndex(nameIndex); + } + + /** + * Returns the name index. + * @return the name index. + */ + public int getNameIndex() { + return nameIndex; + } + + /** + * Sets the name index. + * @param nameIndex the name index. + */ + private void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/DoubleInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/DoubleInfo.java new file mode 100644 index 00000000000..6bbea494983 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/DoubleInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents double information. + */ +public class DoubleInfo extends Abstract8ByteNumericInfo { + + /** + * Constructor. + * @param tag the tag. + * @param highBytes the high bytes. + * @param lowBytes the low bytes. + */ + public DoubleInfo(short tag, long highBytes, long lowBytes) { + super(tag, highBytes, lowBytes); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedClassLoader.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedClassLoader.java new file mode 100644 index 00000000000..60f2ea7e7c6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedClassLoader.java @@ -0,0 +1,131 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +/** + * This class loader is used to load classes given a root path. + */ +public class EnhancedClassLoader extends ClassLoader { + + private String rootPath; + + /** + * Constructor. + * @param rootPath the root path. + */ + public EnhancedClassLoader(String rootPath) { + super(); + setRootPath(rootPath); + } + + /** + * Returns the root path. + * @return the root path. + */ + public String getRootPath() { + return rootPath; + } + + /** + * Sets the root path. + * @param rootPath the root path. + */ + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } + + /** + * Finds the class with the given name. + * @see java.lang.ClassLoader#findClass(java.lang.String) + */ + protected Class findClass(String name) throws ClassNotFoundException { + + try { + byte[] b = loadClassData(name); + return defineClass(name, b, 0, b.length); + } + catch (IOException e) { + throw new ClassNotFoundException(); + } + } + + /** + * Returns the class data. + * @param name the name of the class. + * @return the contents of the class. + */ + private byte[] loadClassData(String name) throws IOException { + + // parent path + String parentPath = rootPath; + + // system file separator + String fileSep = System.getProperty("file.separator"); + + // add file separator to the parent path if it does not end with it + if (!parentPath.endsWith(fileSep)) { + parentPath = parentPath + fileSep; + } + + StringBuffer buf = new StringBuffer(parentPath); + + // replace '.' in class name with file separator + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + + if (c == '.') { + buf.append(fileSep); + } + else { + buf.append(c); + } + } + + String filePath = buf.append(".class").toString(); + + File file = new File(filePath); + + FileInputStream fileStream = new FileInputStream(file); + + int length = (int)(file.length()); + byte[] classData = new byte[length]; + + int bytesRead = 0; + int offset = 0; + + int available = fileStream.available(); + + while (available > 0) { + int bytesToRead = Math.min(available, 256000); + bytesRead = fileStream.read(classData, offset, bytesToRead); + + if (bytesRead == -1) { + break; + } + + offset += bytesRead; + + available = fileStream.available(); + } + + return classData; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedDataInputStream.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedDataInputStream.java new file mode 100644 index 00000000000..b6d10724965 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/EnhancedDataInputStream.java @@ -0,0 +1,63 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * A data input stream that adds a method for reading an unsigned integer. + */ +public class EnhancedDataInputStream extends DataInputStream { + + /** + * Creates a data input stream that uses the specified underlying input stream. + * @param in the specified input stream. + */ + public EnhancedDataInputStream(InputStream in) { + super(in); + } + + /** + * Reads the next four bytes of this input stream as an unsigned 32-bit long. + *

    + * Bytes + * for this operation are read from the contained + * input stream. + * + * @return the next four bytes of this input stream, interpreted as an + * unsigned 32-bit long. + * @exception EOFException if this input stream reaches the end before + * reading four bytes. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + public final long readUnsignedInt() throws IOException { + long ch1 = in.read(); + long ch2 = in.read(); + long ch3 = in.read(); + long ch4 = in.read(); + + if ((ch1 | ch2 | ch3 | ch4) < 0) { + throw new EOFException(); + } + + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldInfo.java new file mode 100644 index 00000000000..2521b1da632 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldInfo.java @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents a field. + */ +public class FieldInfo extends AbstractCommonInfo { + + /** + * Constructor. + * @param accessFlags the access flags. + * @param nameIndex the name index. + * @param descriptorIndex the descriptor index. + * @param attributesCount the number of attributes. + * @param attributes the attributes. + */ + public FieldInfo(int accessFlags, int nameIndex, int descriptorIndex, int attributesCount, AbstractAttributeInfo[] attributes) { + super(accessFlags, nameIndex, descriptorIndex, attributesCount, attributes); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldRefInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldRefInfo.java new file mode 100644 index 00000000000..7611494b888 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FieldRefInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents field reference inforamtion. + */ +public class FieldRefInfo extends AbstractRefInfo { + + /** + * Constructor. + * @param tag the tag. + * @param classIndex the class index. + * @param nameAndTypeIndex the name and type index. + */ + public FieldRefInfo(short tag, int classIndex, int nameAndTypeIndex) { + super(tag, classIndex, nameAndTypeIndex); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FloatInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FloatInfo.java new file mode 100644 index 00000000000..36d7be8b04a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/FloatInfo.java @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents float information. + */ +public class FloatInfo extends Abstract4ByteNumericInfo { + + /** + * Constructor. + * @param tag the tag. + * @param bytes the bytes. + */ + public FloatInfo(short tag, long bytes) { + super(tag, bytes); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IClassFileConstants.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IClassFileConstants.java new file mode 100644 index 00000000000..73876f080a4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IClassFileConstants.java @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +public interface IClassFileConstants { + + public static final int CONSTANT_CLASS = 7; + public static final int CONSTANT_FIELD_REF = 9; + public static final int CONSTANT_METHOD_REF = 10; + public static final int CONSTANT_INTERFACE_METHOD_REF = 11; + public static final int CONSTANT_STRING = 8; + public static final int CONSTANT_INTEGER = 3; + public static final int CONSTANT_FLOAT = 4; + public static final int CONSTANT_LONG = 5; + public static final int CONSTANT_DOUBLE = 6; + public static final int CONSTANT_NAME_AND_TYPE = 12; + public static final int CONSTANT_UTF8 = 1; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IntegerInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IntegerInfo.java new file mode 100644 index 00000000000..7f146db5a0c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/IntegerInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents integer information. + */ +public class IntegerInfo extends Abstract4ByteNumericInfo { + + /** + * Constructor. + * @param tag the tag. + * @param bytes the bytes. + */ + public IntegerInfo(short tag, long bytes) { + super(tag, bytes); + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/InterfaceMethodRefInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/InterfaceMethodRefInfo.java new file mode 100644 index 00000000000..c8e8eeb7e39 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/InterfaceMethodRefInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents + */ +public class InterfaceMethodRefInfo extends AbstractRefInfo { + + /** + * Constructor. + * @param tag the tag. + * @param classIndex the class index. + * @param nameAndTypeIndex the name and type index. + */ + public InterfaceMethodRefInfo(short tag, int classIndex, int nameAndTypeIndex) { + super(tag, classIndex, nameAndTypeIndex); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/LongInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/LongInfo.java new file mode 100644 index 00000000000..a2977a12e62 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/LongInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents long information. + */ +public class LongInfo extends Abstract8ByteNumericInfo { + + /** + * Constructor. + * @param tag the tag. + * @param highBytes the high bytes. + * @param lowBytes the low bytes. + */ + public LongInfo(short tag, long highBytes, long lowBytes) { + super(tag, highBytes, lowBytes); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodInfo.java new file mode 100644 index 00000000000..e0b355e18aa --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodInfo.java @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents a method. + */ +public class MethodInfo extends AbstractCommonInfo { + + /** + * Constructor. + * @param accessFlags the access flags. + * @param nameIndex the name index. + * @param descriptorIndex the descriptor index. + * @param attributesCount the number of attributes. + * @param attributes the attributes. + */ + public MethodInfo(int accessFlags, int nameIndex, int descriptorIndex, int attributesCount, AbstractAttributeInfo[] attributes) { + super(accessFlags, nameIndex, descriptorIndex, attributesCount, attributes); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodRefInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodRefInfo.java new file mode 100644 index 00000000000..9d59227b943 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/MethodRefInfo.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents method reference information. + */ +public class MethodRefInfo extends AbstractRefInfo { + + /** + * Constructor. + * @param tag the tag. + * @param classIndex the class index. + * @param nameAndTypeIndex the name and type index. + */ + public MethodRefInfo(short tag, int classIndex, int nameAndTypeIndex) { + super(tag, classIndex, nameAndTypeIndex); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/NameAndTypeInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/NameAndTypeInfo.java new file mode 100644 index 00000000000..2546458358c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/NameAndTypeInfo.java @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents name and type information. + */ +public class NameAndTypeInfo extends ClassInfo { + + protected int descriptorIndex; + + /** + * Constructor. + * @param tag the tag. + * @param nameIndex the name index. + * @param descriptorIndex the descriptor index. + */ + public NameAndTypeInfo(short tag, int nameIndex, int descriptorIndex) { + super(tag, nameIndex); + setDescriptorIndex(descriptorIndex); + } + + /** + * Returns the descriptor index. + * @return the descriptorIndex. + */ + public int getDescriptorIndex() { + return descriptorIndex; + } + + /** + * Sets the descriptor index. + * @param descriptorIndex the descriptor index. + */ + private void setDescriptorIndex(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/StringInfo.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/StringInfo.java new file mode 100644 index 00000000000..708d5e24d29 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/StringInfo.java @@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents a string information. + */ +public class StringInfo extends AbstractCPInfo { + + protected int stringIndex; + + /** + * Constructor. + * @param tag the tag. + * @param stringIndex the string index. + */ + public StringInfo(short tag, int stringIndex) { + super(tag); + setStringIndex(stringIndex); + } + + /** + * @return the stringIndex. + */ + public int getStringIndex() { + return stringIndex; + } + + /** + * Sets the stringIndex. + * @param stringIndex the stringIndex. + */ + private void setStringIndex(int stringIndex) { + this.stringIndex = stringIndex; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/UTF8Info.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/UTF8Info.java new file mode 100644 index 00000000000..56d799f45ac --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/java/UTF8Info.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.java; + +/** + * This class represents a UTF-8 string. + */ +public class UTF8Info extends AbstractCPInfo { + + protected int length; + protected short[] bytes; + + /** + * Constructor. + * @param tag the tag. + * @param length the length; + * @param bytes the array of bytes with the given length. + */ + public UTF8Info(short tag, int length, short[] bytes) { + super(tag); + setLength(length); + setBytes(bytes); + } + + /** + * Returns the bytes. + * @return the bytes. + */ + public short[] getBytes() { + return bytes; + } + + /** + * Sets the bytes. + * @param bytes the bytes. + */ + private void setBytes(short[] bytes) { + this.bytes = bytes; + } + + /** + * Returns the length. + * @return the length. + */ + public int getLength() { + return length; + } + + /** + * Sets the length. + * @param length the length. + */ + private void setLength(int length) { + this.length = length; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/IndicatorException.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/IndicatorException.java new file mode 100644 index 00000000000..73de67cc92e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/IndicatorException.java @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.messages; + +/** + * used to indicate that the indicator is not valid. + */ +public class IndicatorException extends Exception +{ + /** + * + */ + private static final long serialVersionUID = 3884986031505435750L; + + public IndicatorException(String text) + { + super(text); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessage.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessage.java new file mode 100644 index 00000000000..f77aa73d811 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessage.java @@ -0,0 +1,510 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.messages; + +// To dos: +// 1) can remove the following import when deprecated stuff is removed.... +// 2) remove deprecated classes.... +// ... done. Phil. + + +import java.io.PrintWriter; +import java.io.StringWriter; + + +/** + * Error message window class. + */ +public class SystemMessage + //implements ISystemMessages +{ + + // start of the new stuff!!! Violaine Batthish + // Indicators + /** + * Completion message indicator (added by DWD) + */ + public static final char COMPLETION='C'; + /** + * Inquiry message indicator + */ + public static final char INQUIRY='Q'; + /** + * Information message indicator + */ + public static final char INFORMATION='I'; + /** + * Error message indicator + */ + public static final char ERROR='E'; + /** + * Warning message indicator + */ + public static final char WARNING='W'; + /** + * Unexpected message indicator (same as warning but will log exception & stack in message log) + */ + public static final char UNEXPECTED='U'; + + // Private variables + private char subPrefix='%'; + private char indicator; + private String level1NS, level2NS; // level 1 & 2 with NO substitution made + private String level1WS, level2WS; // level 1 & 2 with substitutions made. + private String component, subComponent; + private String messageNumber; + private int numSubs=-1; + private Object[] subs=null; + + protected static final String NESTING_INDENT = " "; //$NON-NLS-1$ + + + /** SystemMesssage constructor + *

    Throws: + *

  • IndicatorException: the indicator specified is not a valid indicator + * @param comp: Component + * @param sub: Subcomponent + * @param ind: Indicator + * @param number: message number + * @param l1: Level 1 text + * @param l2: Level 2 text + */ + public SystemMessage(String comp, String sub, String number, char ind, String l1, String l2) throws IndicatorException { + component=comp.toUpperCase(); + subComponent=sub.toUpperCase(); + messageNumber=number.toUpperCase(); + setIndicator(ind); + level1NS=l1.trim(); + level2NS=l2.trim(); + level1WS=l1.trim(); + level2WS=l2.trim(); + + } + + /** + * Use this method to override the default severity of a message + * Throws SeverityException if the severity is not valid + */ + public void setIndicator(char ind) throws IndicatorException { + // check that a valid indicator was specified + if (ind != INQUIRY && + ind != INFORMATION && + ind != ERROR && + ind != WARNING && + ind != UNEXPECTED && + ind != COMPLETION) + throw(new IndicatorException("Indicator specified not valid. Unable to set Indicator.")); + + // to do: decide if there are other indicator change violations.... + + // set indicator + indicator=ind; + } + + /** + * Use this method to get the severity. Will be one of: + *
      + *
    • {@link #INQUIRY} for a question message. + *
    • {@link #COMPLETION} for a completion message. + *
    • {@link #INFORMATION} for an informational message. + *
    • {@link #ERROR} for an error message. + *
    • {@link #WARNING} for a warning message. + *
    • {@link #UNEXPECTED} for an unexpected-situation-encountered message. + *
    + **/ + public char getIndicator() { + return indicator; + } + + /** + * @return the message number of this message. + */ + public String getMessageNumber() { + return messageNumber; + } + + /** + * @return the component of this message. + */ + public String getComponent() { + return component; + } + + /** + * @return the subcomponent of this message. + */ + public String getSubComponent() { + return subComponent; + } + + /** + * Use this method to retrieve the unique number of substitution variables + * in this message (this would include level 1 and 2 text + * @return (int) number of unique substitution variables variables + **/ + public int getNumSubstitutionVariables() { + // see if we already have this information stored + if (numSubs>=0) + return numSubs; + // otherwise we need to count the substitution variables. + else { + numSubs=0; // initial value + String allText=level1NS+" "+level2NS; + String subVar=subPrefix+new Integer(numSubs+1).toString(); + int subLoc=allText.indexOf(subVar); + while (subLoc>=0) { + // in first position + if ((subLoc==0 && + !Character.isDigit(allText.substring(subVar.length()).toCharArray()[0])) || + // in last position + (subLoc==allText.length()-subVar.length() && + allText.substring(subLoc-1).toCharArray()[0]!=subPrefix) || + // somewhere in the middle + (!Character.isDigit(allText.substring(subLoc+subVar.length()).toCharArray()[0]) && + allText.substring(subLoc-1).toCharArray()[0]!=subPrefix)) + numSubs++; + subVar=subPrefix+new Integer(numSubs+1).toString(); + subLoc=allText.indexOf(subVar); + } + return numSubs; + } + } + + /** + * Use this method to retrieve level one text + * @return String - level one text with subsitutions made. + **/ + public String getLevelOneText() { + return level1WS; + } + + /** + * Use this method to retrieve level two text + * @return String - level two text with subsitutions made. + **/ + public String getLevelTwoText() { + return level2WS; + } + + /** + * Use this method to retrieve the full message ID: + * Component + SubComponent + Number + indicator + * @return String - the full message ID + **/ + public String getFullMessageID() { + return component+subComponent+messageNumber+indicator; + } + + + /** + * Use this method to retrieve 'long' message ID format: + * Component + SubComponent + Number. + * The long message ID is used for retrieving messages from a message file. + * @return String - the long message ID + **/ + public String getLongMessageID() { + return component + subComponent + messageNumber; + } + + /** + * Use this method to retrieve 'standard' message ID format: + * Component + Number + * @return String - the full message ID + **/ + public String getMessageID() { + return component + messageNumber; + } + + /** + * Tests if this message has a long id equal to the one supplied in the argument. + * @param messageId the long message id to compare against. + * @return a boolean indicating if the message ids are equal. + */ + public boolean hasLongID(String messageId) { + return getLongMessageID().equals(messageId); + } + + /** + * Use this method to set substitution value %1. + *
    Generally toString() is used on the substitution objects, but there is + * special case handling for exception objects and IStatus objects. + */ + public SystemMessage makeSubstitution(Object sub1) { + level1WS=level1NS; + level2WS=level2NS; + makeSub(1, sub1); + // save subs + subs=new Object[1]; + subs[0]=sub1; + return this; + } + /** + * Use this method to set substitution value %1 %2 + *
    Generally toString() is used on the substitution objects, but there is + * special case handling for exception objects and IStatus objects. + */ + public SystemMessage makeSubstitution(Object sub1, Object sub2) { + level1WS=level1NS; + level2WS=level2NS; + makeSub(1, sub1); + makeSub(2, sub2); + // save subs + subs=new Object[2]; + subs[0]=sub1; + subs[1]=sub2; + return this; + } + /** + * Use this method to set substitution value %1 %2 %3 + *
    Generally toString() is used on the substitution objects, but there is + * special case handling for exception objects and IStatus objects. + */ + public SystemMessage makeSubstitution(Object sub1, Object sub2, Object sub3) { + level1WS=level1NS; + level2WS=level2NS; + makeSub(1, sub1); + makeSub(2, sub2); + makeSub(3, sub3); + // save subs + subs=new Object[3]; + subs[0]=sub1; + subs[1]=sub2; + subs[2]=sub3; + return this; + } + /** + * Use this method to set substitution value %1 %2 %3 %4 + *
    Generally toString() is used on the substitution objects, but there is + * special case handling for exception objects and IStatus objects. + */ + public SystemMessage makeSubstitution(Object sub1, Object sub2, Object sub3, Object sub4) { + level1WS=level1NS; + level2WS=level2NS; + makeSub(1, sub1); + makeSub(2, sub2); + makeSub(3, sub3); + makeSub(4, sub4); + // save subs + subs=new Object[4]; + subs[0]=sub1; + subs[1]=sub2; + subs[2]=sub3; + subs[3]=sub4; + return this; + } + + /** + * Use this method to set substitution values + *
    Generally toString() is used on the substitution objects, but there is + * special case handling for exception objects and IStatus objects. + */ + public SystemMessage makeSubstitution(Object [] subsList) + { + level1WS=level1NS; + level2WS=level2NS; + + if ((subsList!=null) && (subsList.length>0)) + for (int i=0; igetNumSubstitutionVariables()) + return; + + String subVar=subPrefix+new Integer(subNumber).toString(); + int subLoc = -1; + + // set level 1 + // - quick test added by Phil + if (level1WS.equals(subVar)) + level1WS = subValue; + else + { + subLoc=level1WS.indexOf(subVar); + + // FIXES BY PHIL + // 1. + // in the following code we were doing toCharArray only to index and get the first char. + // this is not required! there is a charAt method in String for this. Phil. EG: + //!Character.isDigit(level1WS.substring(subVar.length()).toCharArray()[0])) || + + // 2. compared subLoc to gt zero, vs gte zero + // 3. fixing that exposed a bug for the case when level one or two is only '%1' + // + // This code is hard to read and maintain and should be fixed up someday. + // -- why do we check if the next or previous char is a digit? For double digit sub vars like %11? + + //while (subLoc>0) fixed. phil + while (subLoc>=0) + { + // in first position + if ((subLoc==0 && + !Character.isDigit(level1WS.substring(subVar.length()).charAt(0))) || + // in last position + (subLoc==level1WS.length()-subVar.length() && + level1WS.substring(subLoc-1).charAt(0)!=subPrefix) || + // somewhere in the middle + (!Character.isDigit(level1WS.substring(subLoc+subVar.length()).charAt(0)) && + level1WS.substring(subLoc-1).charAt(0)!=subPrefix)) + level1WS=level1WS.substring(0,subLoc)+subValue+level1WS.substring(subLoc+subVar.length()); + subLoc=level1WS.indexOf(subVar, subLoc + subValue.length() ); + } + } + // set level 2 + // - quick test added by Phil + if (level2WS.equals(subVar)) + level2WS = subValue; + else + { + subLoc=level2WS.indexOf(subVar); + //while (subLoc>0) fixed. phil + while (subLoc>=0) + { + // in first position + if ((subLoc==0 && + //!Character.isDigit(level2WS.substring(subVar.length()).charAt(0))) || + !Character.isDigit(level2WS.charAt(subVar.length()))) || + // in last position + (subLoc==level2WS.length()-subVar.length() && + level2WS.substring(subLoc-1).charAt(0)!=subPrefix) || + // somewhere in the middle + (!Character.isDigit(level2WS.substring(subLoc+subVar.length()).charAt(0)) && + level2WS.substring(subLoc-1).charAt(0)!=subPrefix)) + level2WS=level2WS.substring(0,subLoc)+subValue+level2WS.substring(subLoc+subVar.length()); + subLoc=level2WS.indexOf(subVar, subLoc + subValue.length() ); + } + } + } + + + + public void setPrefixChar(char prefixChar) { + subPrefix = prefixChar; + } + + /** + * Do message variable substitution. Using you are replacing &1 (say) with + * a string. + * Still need this for non-message substitution capability. Phil. + * @param string - string containing substring to be substituted. + * @param subOld - substitution variable. Eg "%1" + * @param subNew - substitution data. Eg "001" + * @return message with all occurrences of subOld substituted with subNew. + */ + public static String sub(String msg, String subOld, String subNew) + { + StringBuffer temp = new StringBuffer(); + int lastHit = 0; + int newHit = 0; + for (newHit = msg.indexOf(subOld,lastHit); newHit != -1; + lastHit = newHit, newHit = msg.indexOf(subOld,lastHit)) + { + if (newHit >= 0) + temp.append(msg.substring(lastHit,newHit)); + temp.append(subNew); + newHit += subOld.length(); + } + if (lastHit >= 0) + temp.append(msg.substring(lastHit)); + return temp.toString(); + } + + // Housekeeping... + /** + * Convert this message to a string. + * Returns string of the form: msgId + severity + ":" + first-level-text + */ + public String toString() + { + return getFullMessageID() + ": " + getLevelOneText(); + } + + + + /** + * used to determine the string value of the object + * it calls toString for all object types except for Exceptions + * where the stack is also rendered + * @param sub the substitution object + * @return the string value for the object + */ + public String getSubValue(Object sub) + { + + // the following code caused a crash so I changed it. Phil. + /* + Class subClass=sub.getClass(); + // loop through all the classes for the object + try { + while (subClass!=null) { + if (subClass.equals(Class.forName("Exception"))) { + Exception exc=(Exception)sub; + StringWriter excWriter = new StringWriter(); + exc.printStackTrace(new PrintWriter(excWriter)); + return exc.toString()+"\n"+ excWriter.toString(); + } + subClass=subClass.getSuperclass(); + } + } + catch(ClassNotFoundException e) { + // class was not found + SystemBasePlugin.logError("SystemMessge: getSubValue (Class not found) "+e.toString(), e); + } + */ + + if (sub == null) + return ""; + + if (sub instanceof Exception) + { + Exception exc=(Exception)sub; + StringWriter excWriter = new StringWriter(); + exc.printStackTrace(new PrintWriter(excWriter)); + String msg = exc.toString(); + //String msg = exc.getMessage(); + if ((msg == null) || (exc instanceof ClassCastException)) + msg = exc.getClass().getName(); + return msg+"\n"+ excWriter.toString(); + } + + + return sub.toString(); + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageException.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageException.java new file mode 100644 index 00000000000..1cc10928fef --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageException.java @@ -0,0 +1,74 @@ +/******************************************************************************** + * Copyright (c) 2000, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.messages; +/** + * Encapsulates a system message + */ +public class SystemMessageException extends Exception +{ + /** + * + */ + private static final long serialVersionUID = 6695260563678942200L; + private SystemMessage msg; + + /** + * Constructor + * @param msg - a message to wrap. + */ + protected SystemMessageException(String msg) + { + super(msg); + } + + /** + * Constructor + * @param msg - a system message to wrap. + */ + public SystemMessageException(SystemMessage msg) + { + super(msg.getLevelOneText()); + this.msg = msg; + } + + /** + * Return the SystemMessage we wrap + */ + public SystemMessage getSystemMessage() + { + return msg; + } + + /** + * Tests if the SystemMessage encapsulated by this exception has a long id equal to the + * argument. + * @param longMessageID the String containing the message id to test. + * @return true if the long message id of the message is equal to the supplied message id. + */ + public boolean hasLongID(String longMessageID) { + return getSystemMessage().hasLongID(longMessageID); + } + + /** + * Set the SystemMessage being wrapped + */ + public void setSystemMessage(SystemMessage msg) + { + this.msg = msg; + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageFile.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageFile.java new file mode 100644 index 00000000000..27f534b1049 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/messages/SystemMessageFile.java @@ -0,0 +1,794 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.messages; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + + +/** + * Use this class to open, and parse, a RSE-style message file. + */ +public class SystemMessageFile implements ErrorHandler +{ + + + private static final LinkedList msgfList=new LinkedList(); + private MessageFileInfo msgFile; + private String defaultMsgFileLocation; + private InputStream dtdInputStream; + // the following is an attempt to improve response time, and reduce memory requirements, by + // caching SystemMessage objects for previously issued messages. Phil + private Hashtable messages = new Hashtable(); + // XML TAG AND ELEMENT NAMES... + private static final String XML_TAG_COMPONENT = "Component"; + private static final String XML_TAG_SUBCOMPONENT = "Subcomponent"; + private static final String XML_TAG_MESSAGeList = "MessageList"; + private static final String XML_TAG_MESSAGE = "Message"; + private static final String XML_TAG_LEVELONE = "LevelOne"; + private static final String XML_TAG_LEVELTWO = "LevelTwo"; + private static final String XML_ATTR_ABBR = "Abbr"; + private static final String XML_ATTR_ID = "ID"; + private static final String XML_ATTR_INDICATOR = "Indicator"; + private static final String XML_ATTR_NAME = "Name"; + + + + /** + * Inner class + */ + private class MessageFileInfo + { + private String filename=null; + private String shortName=null; + private Document xmlDocument=null; + + public MessageFileInfo(String ucFileName, String lcFileName, Document doc) + { + filename=ucFileName; + int idx=lcFileName.lastIndexOf('\\'); + if (idx == -1) + idx = lcFileName.lastIndexOf('/'); + if (idx >= 0) + shortName = lcFileName.substring(idx+1); + else + shortName = lcFileName; + xmlDocument=doc; + } + + public String getMessageFullFileName() + { + return filename; + } + public String getMessageShortFileName() + { + return shortName; + } + + public Document getXMLDocument() + { + return xmlDocument; + } + } + /** + * Constructor + * @param messageFileName - name of xml file which will contain the messages + */ + public SystemMessageFile (String messageFileName, String defaultMessageFileLocation) + { + this.defaultMsgFileLocation = defaultMessageFileLocation; + // have we already loaded this message file? + msgFile = getFromCache(messageFileName); + + // now, we haven't. Load it now. + if (msgFile == null) + { + msgFile=new MessageFileInfo(messageFileName.toUpperCase(), messageFileName, loadAndParseXMLFile(messageFileName)); + msgfList.add(msgFile); + //scanForDuplicates(); // don't keep this for production. Too expensive + } + } + /** + * Constructor + * @param messageFileName - name of xml file which will contain the messages + */ + public SystemMessageFile (String messageFileName, InputStream messageFile, InputStream dtdStream) + { + // have we already loaded this message file? + msgFile = getFromCache(messageFileName); + + // now, we haven't. Load it now. + this.dtdInputStream = dtdStream; + if (msgFile == null) + { + msgFile=new MessageFileInfo(messageFileName.toUpperCase(), messageFileName, loadAndParseXMLFile(messageFile)); + msgfList.add(msgFile); + //scanForDuplicates(); // don't keep this for production. Too expensive + } + } + + /** + * If the named message file has already been loaded return its + * MessageFileInfo + * @param messageFileName + * @return + */ + protected MessageFileInfo getFromCache(String messageFileName) + { + for (int i=0; i0)) + messageListNode = (Element)msgListNodes.item(0); + else + { + issueWarningMessage("unable to find MessageList nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + + // search for the message node which has the right number + //for (Node node=messageListNode.getFirstChild(); + // node!=null; node=node.getNextSibling()) + NodeList msgNodes = messageListNode.getElementsByTagName(XML_TAG_MESSAGE); + if ((msgNodes==null) || (msgNodes.getLength()==0)) + { + issueWarningMessage("unable to find Message nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + boolean match = false; // I added this so we stop looping when we find what we are looking for!!! Phil. + for (int msgIdx = 0; !match && (msgIdx < msgNodes.getLength()); msgIdx++) + { + Element node = (Element)msgNodes.item(msgIdx); + // if the message number matches... + //if (node.getNodeName().equals("Message") && node.getAttributes().getNamedItem("ID").getFirstChild().getNodeValue().toUpperCase().equals(msgNumber)) + if (node.getAttribute(XML_ATTR_ID).equals(msgNumber)) + { + match = true; + // save the indicator value + //msgIndicator=(node.getAttributes().getNamedItem("Indicator").getFirstChild().getNodeValue().toUpperCase().toCharArray())[0]; + msgIndicator=node.getAttribute(XML_ATTR_INDICATOR).toUpperCase().charAt(0); + // search for the l1 & l2 text + for (Node msgNode=node.getFirstChild(); + msgNode!=null; msgNode=msgNode.getNextSibling()) + { + // get Level One text + if (msgNode.getNodeName().equals(XML_TAG_LEVELONE)) + msgL1 = getNodeText(msgNode); + // get Level Two text + else if (msgNode.getNodeName().equals(XML_TAG_LEVELTWO)) + msgL2 = getNodeText(msgNode); + } + break; + } + } + if (!match) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("Requested Message " + msgId + " not found in message file " + msgFile.getMessageShortFileName()); + */ + return null; + } + try + { + msg = loadSystemMessage(componentAbbr, subComponentAbbr, msgNumber, msgIndicator, msgL1, msgL2); + messages.put(msgFile.getMessageShortFileName()+":"+msgId, msg); // add to cache so we find it immediately next time!! + return msg; + } + catch (IndicatorException e) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("MessageFile:getMessage: "+e.toString(), e); + */ + } + break; + } + } + return null; + } + + /** + * Override this to provide different extended SystemMessage implementation + * @param componentAbbr + * @param subComponentAbbr + * @param msgNumber + * @param msgIndicator + * @param msgL1 + * @param msgL2 + * @return + * @throws IndicatorException + */ + protected SystemMessage loadSystemMessage(String componentAbbr, String subComponentAbbr, String msgNumber, char msgIndicator, + String msgL1, String msgL2) throws IndicatorException + { + return new SystemMessage(componentAbbr, subComponentAbbr, msgNumber, msgIndicator, msgL1, msgL2); + } + + /** + * Get the level one text + */ + private String getNodeText(Node msgNode) + { + String nodeText = ""; + for (Node textNode=msgNode.getFirstChild(); + textNode!=null; textNode=textNode.getNextSibling()) + { + if ((textNode.getNodeType()==Node.TEXT_NODE) && (textNode.getNodeValue().trim().length()>0)) + nodeText += textNode.getNodeValue(); + } + return nodeText.trim(); + } + + /** + * Use this method to scan message file for duplicate messages. You typically do this only during development!! + * If a duplicate is found, its message id is written to standard out, and to the systems.core + * log file. + * @return true if duplicates found. + */ + public boolean scanForDuplicates() + { + boolean echoErrorsToStandardOut = true; + if (msgFile.getXMLDocument() == null) + return issueErrorMessage("No XML document for message file", echoErrorsToStandardOut); + + // parse out the Abbr attr of the first Component element + NodeList componentElementList = msgFile.getXMLDocument().getElementsByTagName(XML_TAG_COMPONENT); + if ((componentElementList == null) || (componentElementList.getLength() == 0)) + return issueErrorMessage("Unable to find any Component elements",echoErrorsToStandardOut); + + Element componentElement = (Element)componentElementList.item(0); + String componentAbbr = componentElement.getAttribute(XML_ATTR_ABBR); + + // get list of all Subcomponent elements... + NodeList subComponentList=msgFile.getXMLDocument().getElementsByTagName(XML_TAG_SUBCOMPONENT); + + if ((subComponentList == null) || (subComponentList.getLength() == 0)) + return issueErrorMessage("Unable to find any Subcomponent elements",echoErrorsToStandardOut); + + // scan all subcomponents... + boolean anyDupes = false; + for (int subComponentIdx=0; subComponentIdx0)) + messageListNode = (Element)msgListNodes.item(0); + else + { + issueWarningMessage("unable to find MessageList nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + + NodeList msgNodes = messageListNode.getElementsByTagName(XML_TAG_MESSAGE); + if ((msgNodes==null) || (msgNodes.getLength()==0)) + { + issueWarningMessage("unable to find Message nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + for (int msgIdx = 0; (msgIdx < msgNodes.getLength()); msgIdx++) + { + Element node = (Element)msgNodes.item(msgIdx); + String msgId = msgPrefix + node.getAttribute(XML_ATTR_ID); + if (msgsById.contains(msgId)) + { + anyDupes = true; + issueWarningMessage("Warning: duplicate message " + msgId + " found", echoErrorsToStandardOut); + } + else + msgsById.addElement(msgId); + } + } + return anyDupes; + } + + /** + * Use this method to generate html documentation for the messages in the message file. + * This is useful for reference information, or to give to Level 2 for service support. + * @param htmlFile - the fully qualified name of the file to write to. Overwrites current contents. + * @return true if it went well, false if it failed for some reason, such as given a bad file name. Errors written to standard out. + */ + public boolean printHTML(String fullFileName) + { + boolean echoErrorsToStandardOut = true; + if (msgFile.getXMLDocument() == null) + return issueErrorMessage("No XML document for message file", echoErrorsToStandardOut); + + // parse out the Abbr attr of the first Component element + NodeList componentElementList = msgFile.getXMLDocument().getElementsByTagName(XML_TAG_COMPONENT); + if ((componentElementList == null) || (componentElementList.getLength() == 0)) + return issueErrorMessage("Unable to find any Component elements",echoErrorsToStandardOut); + + Element componentElement = (Element)componentElementList.item(0); + String componentAbbr = componentElement.getAttribute(XML_ATTR_ABBR); + + // get list of all Subcomponent elements... + NodeList subComponentList=msgFile.getXMLDocument().getElementsByTagName(XML_TAG_SUBCOMPONENT); + + if ((subComponentList == null) || (subComponentList.getLength() == 0)) + return issueErrorMessage("Unable to find any Subcomponent elements",echoErrorsToStandardOut); + + File outFile = new File(fullFileName); + PrintWriter outFileStream = null; + try + { + outFileStream = new PrintWriter(new FileOutputStream(outFile)); + outFileStream.println(" Message File "+msgFile.getMessageShortFileName()+" "); + outFileStream.println(""); + outFileStream.println(" "); + outFileStream.println("

    "+componentElement.getAttribute(XML_ATTR_NAME)+" Messages

    "); + outFileStream.println("
    "); + outFileStream.println(""); + outFileStream.println(""); + outFileStream.println(""); + outFileStream.println(""); + } + catch (IOException exc) + { + return issueErrorMessage("Unable to open given html file in printHTML: " + exc.getMessage(), echoErrorsToStandardOut); + } + + // pre-scan all subcomponents... + for (int subComponentIdx=0; subComponentIdx"); + outFileStream.println(""); + outFileStream.println(""); + } + outFileStream.println("
    "); + outFileStream.println("Sub-Component Summary
    "); + outFileStream.println(""+scName+"Message prefix="+msgPrefix+"
    "); + + // scan all subcomponents... + for (int subComponentIdx=0; subComponentIdx0)) + messageListNode = (Element)msgListNodes.item(0); + else + { + issueWarningMessage("unable to find MessageList nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + + NodeList msgNodes = messageListNode.getElementsByTagName(XML_TAG_MESSAGE); + if ((msgNodes==null) || (msgNodes.getLength()==0)) + { + issueWarningMessage("unable to find Message nodes for subComponent " + subComponentElement.getAttribute(XML_ATTR_NAME),echoErrorsToStandardOut); + continue; + } + if (subComponentIdx > 0) + outFileStream.println("
    "); + String scName = subComponentElement.getAttribute(XML_ATTR_NAME); + outFileStream.println("

    "+scName+" Messages

    "); + for (int msgIdx = 0; (msgIdx < msgNodes.getLength()); msgIdx++) + { + Element node = (Element)msgNodes.item(msgIdx); + String msgId = msgPrefix + node.getAttribute(XML_ATTR_ID); + char msgIndicator=node.getAttribute(XML_ATTR_INDICATOR).toUpperCase().charAt(0); + String msgSeverity = "Unknown"; + if (msgIndicator == SystemMessage.ERROR) + msgSeverity = "Error"; + else if (msgIndicator == SystemMessage.WARNING) + msgSeverity = "Warning"; + else if (msgIndicator == SystemMessage.INQUIRY) + msgSeverity = "Question"; + else if (msgIndicator == SystemMessage.INFORMATION) + msgSeverity = "Information"; + else if (msgIndicator == SystemMessage.COMPLETION) + msgSeverity = "Completion"; + else if (msgIndicator == SystemMessage.UNEXPECTED) + msgSeverity = "Unexpected"; + + String msgL1 = ""; + String msgL2 = ""; + // search for the l1 & l2 text + for (Node msgNode=node.getFirstChild(); + msgNode!=null; msgNode=msgNode.getNextSibling()) + { + // get Level One text + if (msgNode.getNodeName().equals(XML_TAG_LEVELONE)) + msgL1 = getNodeText(msgNode); + // get Level Two text + else if (msgNode.getNodeName().equals(XML_TAG_LEVELTWO)) + msgL2 = getNodeText(msgNode); + } + outFileStream.println("

    "+msgId+"

    "); + outFileStream.println("Severity: "+msgSeverity+"
    "); + outFileStream.println("LevelOne: "+msgL1+"
    "); + outFileStream.println("LevelTwo: "+msgL2+"
    "); + } + outFileStream.println("
    "); + } + outFileStream.println(""); + outFileStream.close(); + return true; + } + + /** + * Issue an error message + */ + private boolean issueErrorMessage(String errormsg, boolean echoStandardOut) + { + + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + * + SystemBasePlugin.logError("MessageFile error for msg file " + msgFile.getMessageShortFileName() + ": " + errormsg); + **/ + if (echoStandardOut) + System.out.println("MessageFile error for msg file " + msgFile.getMessageShortFileName() + ": " + errormsg); + return false; + } + /** + * Issue a warning message + */ + private boolean issueWarningMessage(String errormsg, boolean echoStandardOut) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("MessageFile warning for msg file " + msgFile.getMessageShortFileName() + ": " + errormsg); + */ + if (echoStandardOut) + System.out.println("MessageFile warning for msg file " + msgFile.getMessageShortFileName() + ": " + errormsg); + return false; + } + + /** + * loadAndParseXMLFile: + * tries to load and parse the specified XML file. + * @param String messageFileName: name of xml file which will contain the messages + */ + private Document loadAndParseXMLFile (String messageFileName) + { + DocumentBuilder parser = createXmlParser(); + + try + { + Document document = parser.parse(messageFileName); + return document; + } + catch (SAXException e) + { + // the parser was unable to parse the file. + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("SystemMessageFile: loadAndParseXMLFile "+e.toString(), e); + + MessageBox mb = new MessageBox(SystemPlugin.getActiveWorkbenchShell()); + mb.setText("Unexpected Error"); + mb.setMessage("Unable to load message file " + messageFileName ); + mb.open(); + */ + return null; + } + catch (IOException e) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + // there was an error reading the file + SystemBasePlugin.logError("SystemMessageFile: loadAndParseXMLFile "+e.toString(), e); + + MessageBox mb = new MessageBox(SystemPlugin.getActiveWorkbenchShell()); + mb.setText("Unexpected Error"); + mb.setMessage("Unable to load message file " + messageFileName ); + mb.open(); + */ + return null; + } + + // the file was successfully opened and parsed +// return parser.getDocument(); + } + + /** + * Create the XML parser + * Set its entity resolver and error handler. + * @return DocumentBuilder + */ + private DocumentBuilder createXmlParser() + { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(true); + DocumentBuilder parser; + try { + parser = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + // the configuration was not valid + /** TODO -move this elsewhere - can't depend on ui stuff + SystemBasePlugin.logError("SystemMessageFile: loadAndParseXMLFile, configuration not valid "+e.toString(), e); + */ + return null; + } +// DOMParser parser=new DOMParser(); +// try +// { +// parser.setFeature( "http://xml.org/sax/features/validation", true); +// } +// catch (SAXNotRecognizedException e) +// { +// // the feature was not recognized +// /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent +// SystemBasePlugin.logError("SystemMessageFile: loadAndParseXMLFile, feature not recognized "+e.toString(), e); +// */ +// return null; +// } +// catch (SAXNotSupportedException e) +// { +// // the feature requested was not supported +// /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent +// SystemBasePlugin.logError("SystemMessageFile: loadAndParseXMLFile, feature not recognized "+e.toString(), e); +// */ +// return null; +// } + parser.setEntityResolver(new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, java.io.IOException + { + /* + // This code does not work with fragments + Path path = new Path(systemId); + if (systemId.toUpperCase().endsWith("MESSAGEFILE.DTD")) + { + if (SystemPlugin.getBaseDefault().getDescriptor().find(path)==null) + { + path = new Path("messageFile.dtd"); + } + } + return new InputSource(SystemBasePlugin.getBaseDefault().getDescriptor().find(path).toString()); + */ + // If we have the input stream of the DTD just use it + if (dtdInputStream != null) + { + return new InputSource(dtdInputStream); + } + else // if we have the directory containing the DTD use that + { + // yantzi:artemis6.2 changed to use URI instead of URL (URIs handle the spaces) + //URL url = new URL(systemId); + //File dtdFile = new File(url.getFile()); + try + { + URI url = new URI(systemId); + File dtdFile = new File(url.getPath()); + if (!dtdFile.exists()) + { + // use default locaiton + systemId = defaultMsgFileLocation + File.separatorChar + dtdFile.getName(); + } + } + catch (URISyntaxException e) + { + // ignore and continue + } + + return new InputSource(systemId); + } + } + }); + parser.setErrorHandler(this); + return parser; + } + /** + * loadAndParseXMLFile: + * tries to load and parse the specified XML file . + * @param String messageFile: InputStream containing the XML file + */ + private Document loadAndParseXMLFile (InputStream messageFile) + { + DocumentBuilder parser = createXmlParser(); + try + { + InputSource in = new InputSource(messageFile); + + // DKM - hack! + // If systemId is null for the InputSource, then + // the current parser hits a fatal exception. + // This hack prevents that exception so that the + // specified EntityResolver will get used. + in.setSystemId("foo"); + Document document = parser.parse(in); + + //Document document = parser.parse(messageFile); + return document; + } + catch (SAXException e) + { + e.printStackTrace(); + // the parser was unable to parse the file. + return null; + } + catch (IOException e) + { + e.printStackTrace(); + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + */ + return null; + } + } + + /** + * XML Parser-required method: XML-parser warning. + */ + public void warning(SAXParseException ex) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("SystemMessageFile: warning parsing message file: "+ex.toString()); + */ + } + + /** + * XML Parser-required method: XML-parser Error. + */ + public void error(SAXParseException ex) + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("SystemMessageFile: Error parsing message file: "+ex.toString(), ex); + Shell shell = SystemPlugin.getActiveWorkbenchShell(); + if (shell.isEnabled() && !shell.isDisposed()) + { + MessageBox mb = new MessageBox(shell); + mb.setText("Error loading message file: "+ex.getMessage()); + mb.setMessage("Unable to load message file " + currMsgFile +". Error at line "+ex.getLineNumber()+" and column "+ex.getColumnNumber()); + mb.open(); + } + */ + } + + /** + * XML Parser-required method: XML-parser Fatal error. + */ + public void fatalError(SAXParseException ex) throws SAXException + { + /** TODO - DKM move this somewhere else since system message now needs to be eclipse independent + SystemBasePlugin.logError("SystemMessageFile: Fatal Error parsing message file: "+ex.toString(), ex); + */ + throw(ex); + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/HostProcessFilterImpl.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/HostProcessFilterImpl.java new file mode 100644 index 00000000000..ebc2c6c529e --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/HostProcessFilterImpl.java @@ -0,0 +1,443 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes; + + +import java.util.HashMap; +import java.util.StringTokenizer; + +import org.eclipse.rse.services.clientserver.NamePatternMatcher; + +/** + * A class representing a remote process filter string. This is a name pattern + * for returning lists of remote processes when used as input to the + * UniversalProcessMiner class. + * + * Valid generic names are names with one or two asterisks + * anywhere in the name, as in: + * + * ABC* or *ABC or A*C + * *ABC* or *A*C or A*C* + * + * + * To get the actual filter string back from objects of this class, just call {@link #toString()}. + * + */ +public class HostProcessFilterImpl implements IHostProcessFilter, Cloneable, ISystemProcessRemoteConstants +{ + + public static final String ALL = "*"; + + protected static final char WILDCARD = '*'; + + protected String name, username, gid, ppid, pid; + protected long minVM, maxVM; + protected boolean anystatus; + protected String status; + protected HashMap states; + + /** + * Constructor to use when there is no existing filter string. + */ + public HostProcessFilterImpl() + { + name = ALL; + username = ALL; + gid = ALL; + ppid = ALL; + pid = ALL; + minVM = 0; + maxVM = -1; + anystatus = true; + initStates(); + status = ""; + } + + protected void initStates() + { + states = new HashMap(); + for (int i = 0; i < ALL_STATES_STR.length; i++) + { + states.put(ALL_STATES_STR[i], new Boolean(false)); + } + } + + /** + * Constructor to use when filter string already exists. + */ + public HostProcessFilterImpl(String input) + { + anystatus = true; + StringTokenizer tz = new StringTokenizer(input, "|"); + String strMinVM = "0"; + String strMaxVM = "-1"; + + if (tz.hasMoreTokens()) + { + name = tz.nextToken(); + + if (tz.hasMoreTokens()) + { + username = tz.nextToken(); + + if (tz.hasMoreTokens()) + { + gid = tz.nextToken(); + if (tz.hasMoreTokens()) + { + status = tz.nextToken().trim(); + if (tz.hasMoreTokens()) + { + ppid = tz.nextToken(); + if (tz.hasMoreTokens()) + { + pid = tz.nextToken(); + if (tz.hasMoreTokens()) + { + strMinVM = tz.nextToken(); + if (tz.hasMoreTokens()) + { + strMaxVM = tz.nextToken(); + } + } + } + } + } + } + } + } + + if (!(status == null)) + { + if (!status.equals("")) + { + String[] allStates = status.split(","); + if (!(allStates == null)) + { + initStates(); + anystatus = false; + for (int i = 0; i < allStates.length; i++) + { + states.put(allStates[i], new Boolean(true)); + } + } + } + } + + if (name == null || name.equals("")) + name = ALL; + + if (username == null || username.equals("")) + username = ALL; + + if (gid == null || gid.equals("")) + gid = ALL; + + if (ppid == null || ppid.equals("")) + ppid = ALL; + + if (pid == null || pid.equals("")) + pid = ALL; + try + { + minVM = Long.parseLong(strMinVM); + } + catch (Exception e) + { + minVM = 0; + } + try + { + maxVM = Long.parseLong(strMaxVM); + } + catch (Exception e) + { + maxVM = -1; + } + if (minVM < 0) + { + minVM = 0; + } + if (maxVM < 0) + { + maxVM = -1; + } + } + + + public HashMap getStates() + { + return states; + } + + /** + * Return the process name part of this filter string. + */ + public String getName() + { + return name; + } + + /** + * Return the username part of this filter string. + */ + public String getUsername() + { + if (username.equals("${user.id}")) + { + return System.getProperty("user.name"); + } + return username; + } + + /** + * Return the process group id (gid) part of this filter string. + */ + public String getGid() + { + return gid; + } + + /** + * Return the process parent id (ppid) part of this filter string. + */ + public String getPpid() + { + return ppid; + } + + /** + * Return the process id (pid) part of this filter string. + */ + public String getPid() + { + return pid; + } + + /** + * Returns true when all process states are selected. The individal state + * queries will return false in this case. + */ + public boolean getAnyStatus() + { + return anystatus; + } + + /** + * Returns the minimum VM size for processes allowed by this filter + */ + public String getMinVM() + { + return "" + minVM; + } + + /** + * Returns the maximum VM size for processes allowed by this filter + */ + public String getMaxVM() + { + return "" + maxVM; + } + + + /** + * Set the name part of this filter string. This can be simple or + * generic, where generic is a name containing one or two asterisks + * anywhere in the name. + */ + public void setName(String obj) + { + name = obj; + } + + /** + * Set the user id (uid) part of this filter string. This can be simple or + * generic, where generic is a uid containing one or two asterisks anywhere + * in the name. + */ + public void setUsername(String obj) + { + username = obj; + } + + /** + * Set the process group id (gid) part of this filter string. + */ + public void setGid(String obj) + { + gid = obj; + } + + /** + * Set the process parent id part of this filter string. + */ + public void setPpid(String obj) + { + ppid = obj; + } + + /** + * Set the process id part of this filter string. + */ + public void setPid(String obj) + { + pid = obj; + } + + /** + * Select all/any process states + */ + public void setAnyStatus() + { + anystatus = true; + initStates(); + } + + /** + * Sets the minimum VM size for processes allowed by this filter + */ + public void setMinVM(String strMinVM) + { + try + { + minVM = Long.parseLong(strMinVM); + } + catch (Exception e) + { + minVM = 0; + } + } + + /** + * Sets the maximum VM size for processes allowed by this filter + */ + public void setMaxVM(String strMaxVM) + { + try + { + maxVM = Long.parseLong(strMaxVM); + } + catch (Exception e) + { + maxVM = 0; + } + } + + /** + * Convert this filter into a filter string. + */ + public String toString() + { + return name + "|" + username + "|" + gid + "|" + toStateString() + "|" + ppid + "|" + pid + "|" + minVM + "|" + maxVM; + } + + protected String toStateString() + { + String s = " "; + + if (!anystatus) + { + for (int i = 0; i < ALL_STATES_STR.length; i++) + { + Boolean currentState = (Boolean) states.get(ALL_STATES_STR[i]); + if (currentState.booleanValue()) s = s + ALL_STATES_STR[i]; + if (currentState.booleanValue()) s = s + ","; + } + if (!s.trim().equals("")) s = s.trim(); + if (s.endsWith(",")) s = s.substring(0, s.length() - 1); + } + return s; + } + + /** + * Returns whether this filter allows a process with the status line + * status to pass through. The status line contains some of the contents of + * the status file contained in the processes numbered directory in + * the /proc filesystem. For example, the status line of process 12345 is + * the contents of the file /proc/12345/stat. + * The status line must be structured as follows: + * "pid|name|status|tgid|ppid|tracerpid|uid|username|gid|vmSize|vmRSS" + */ + public boolean allows(String status) + { + NamePatternMatcher matcher = null; + String[] tokens = status.split("\\|"); + if (tokens.length < (PROCESS_ATTRIBUTES_COUNT -1)) return false; + + matcher = new NamePatternMatcher(gid, true, false); + if (!matcher.matches(tokens[PROCESS_ATTRIBUTES_INDEX_GID])) return false; + + matcher = new NamePatternMatcher(name, true, false); + if (!matcher.matches(tokens[PROCESS_ATTRIBUTES_INDEX_EXENAME])) return false; + + String state = tokens[PROCESS_ATTRIBUTES_INDEX_STATUS].trim(); + if (!satisfiesState(state)) return false; + + matcher = new NamePatternMatcher(getUsername(), true, false); + if (!matcher.matches(tokens[PROCESS_ATTRIBUTES_INDEX_USERNAME])) return false; + matcher = new NamePatternMatcher(ppid, true, false); + if (!matcher.matches(tokens[PROCESS_ATTRIBUTES_INDEX_PPID])) return false; + matcher = new NamePatternMatcher(pid, true, false); + if (!matcher.matches(tokens[PROCESS_ATTRIBUTES_INDEX_PID])) return false; + long vmSize = 0; + try + { + vmSize = Long.parseLong(tokens[PROCESS_ATTRIBUTES_INDEX_VMSIZE]); + } + catch (Exception e) + { + if (tokens[PROCESS_ATTRIBUTES_INDEX_VMSIZE].trim().equals("")) vmSize = 0; + else return false; + } + if (!(vmSize >= minVM)) return false; + if (maxVM > -1 && !(vmSize <= maxVM)) return false; + + return true; + } + + public boolean getSpecificState(String stateCode) + { + Boolean state = (Boolean) states.get(stateCode); + if (state == null) return false; + return state.booleanValue(); + } + + public void setSpecificState(String stateCode) + { + anystatus = false; + states.put(stateCode, new Boolean(true)); + } + + public boolean satisfiesState(String state) + { + if (!anystatus) + { + String[] allStates = state.split(","); + if (allStates == null) return false; + if (allStates.length == 0) return false; + boolean satisfied = false; + for (int i = 0; i < allStates.length; i++) + { + String nextState = allStates[i]; + satisfied = getSpecificState(nextState); + if (satisfied) break; + } + if (!satisfied) return false; + } + return true; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcess.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcess.java new file mode 100644 index 00000000000..00cac6237c6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcess.java @@ -0,0 +1,101 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes; + +/** + * + * @author mjberger + * + * This interface represents a simple abstract process on a host + * system. + */ +public interface IHostProcess +{ + + + /** + * Get the process id (pid) associated with this process. + */ + public long getPid(); + + /** + * Get the parent process id (ppid) associated with this process. + */ + public long getPPid(); + + /** + * Get the name of the executable owning this process + */ + public String getName(); + + /** + * Get the state of the process + */ + public String getState(); + + /** + * Get the Tgid + */ + public long getTgid(); + + /** + * Get the TracerPid + */ + public long getTracerPid(); + + /** + * Get the process owner's user id (uid) + */ + public long getUid(); + + /** + * Get the process owner's username + */ + public String getUsername(); + + /** + * Get the process owner's group id (gid) + */ + public long getGid(); + + /** + * Returns whether this is the root process or not + */ + public boolean isRoot(); + + /** + * Returns the virtual memory size of this process (in kB) + */ + public long getVmSizeInKB(); + + /** + * Returns the virtual memory resident set size of this process (in kB). + * This is the actual amount of RAM used by the process. + */ + public long getVmRSSInKB(); + + /** + * Get the display name for this process. + */ + public String getLabel(); + + /** + * Returns all properties of this process in the same format as given in the + * dataelement + */ + public String getAllProperties(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcessFilter.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcessFilter.java new file mode 100644 index 00000000000..7da76330ff2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/IHostProcessFilter.java @@ -0,0 +1,126 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes; + +import java.util.HashMap; + +public interface IHostProcessFilter +{ + public HashMap getStates(); + + /** + * Return the process name part of this filter string. + */ + public String getName(); + + /** + * Return the username part of this filter string. + */ + public String getUsername(); + + /** + * Return the process group id (gid) part of this filter string. + */ + public String getGid(); + + /** + * Return the process parent id (ppid) part of this filter string. + */ + public String getPpid(); + + /** + * Return the process id (pid) part of this filter string. + */ + public String getPid(); + + /** + * Returns true when all process states are selected. The individal state + * queries will return false in this case. + */ + public boolean getAnyStatus(); + + /** + * Returns the minimum VM size for processes allowed by this filter + */ + public String getMinVM(); + + /** + * Returns the maximum VM size for processes allowed by this filter + */ + public String getMaxVM(); + + /** + * Set the name part of this filter string. This can be simple or + * generic, where generic is a name containing one or two asterisks + * anywhere in the name. + */ + public void setName(String obj); + + /** + * Set the user id (uid) part of this filter string. This can be simple or + * generic, where generic is a uid containing one or two asterisks anywhere + * in the name. + */ + public void setUsername(String obj); + + /** + * Set the process group id (gid) part of this filter string. + */ + public void setGid(String obj); + + /** + * Set the process parent id part of this filter string. + */ + public void setPpid(String obj); + + /** + * Set the process id part of this filter string. + */ + public void setPid(String obj); + + /** + * Select all/any process states + */ + public void setAnyStatus(); + + /** + * Sets the minimum VM size for processes allowed by this filter + */ + public void setMinVM(String strMinVM); + + /** + * Sets the maximum VM size for processes allowed by this filter + */ + public void setMaxVM(String strMaxVM); + + /** + * Returns whether this filter allows a process with the status line + * status to pass through. The status line contains some of the contents of + * the status file contained in the processes numbered directory in + * the /proc filesystem. For example, the status line of process 12345 is + * the contents of the file /proc/12345/stat. + * The status line must be structured as follows: + * "pid|name|status|tgid|ppid|tracerpid|uid|username|gid|vmSize|vmRSS" + */ + public boolean allows(String status); + + public boolean getSpecificState(String stateCode); + + public void setSpecificState(String stateCode); + + public boolean satisfiesState(String state); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteConstants.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteConstants.java new file mode 100644 index 00000000000..bbf629fe27f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteConstants.java @@ -0,0 +1,194 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes; + + +public interface ISystemProcessRemoteConstants +{ + public static final int PROCESS_ATTRIBUTES_INDEX_PID = 0; + public static final int PROCESS_ATTRIBUTES_INDEX_EXENAME = 1; + public static final int PROCESS_ATTRIBUTES_INDEX_STATUS = 2; + public static final int PROCESS_ATTRIBUTES_INDEX_TGID = 3; + public static final int PROCESS_ATTRIBUTES_INDEX_PPID = 4; + public static final int PROCESS_ATTRIBUTES_INDEX_TRACERPID = 5; + public static final int PROCESS_ATTRIBUTES_INDEX_UID = 6; + public static final int PROCESS_ATTRIBUTES_INDEX_USERNAME = 7; + public static final int PROCESS_ATTRIBUTES_INDEX_GID = 8; + public static final int PROCESS_ATTRIBUTES_INDEX_VMSIZE = 9; + public static final int PROCESS_ATTRIBUTES_INDEX_VMRSS = 10; + public static final int PROCESS_ATTRIBUTES_COUNT = 11; + + public static final char STATE_ACTIVE = 'A'; + public static final char STATE_IDLE = 'I'; + public static final char STATE_NONEXISTENT = 'O'; + public static final char STATE_PAGING = 'W'; + public static final char STATE_RUNNING = 'R'; + public static final char STATE_SLEEPING = 'S'; + public static final char STATE_TRACED = 'T'; + public static final char STATE_WAITING = 'D'; + public static final char STATE_ZOMBIE = 'Z'; + + public static final char STATE_ZOS_SINGLE = '1'; + public static final char STATE_ZOS_MSGQRECEIVEWAIT = 'A'; + public static final char STATE_ZOS_MSGQSENDWAIT = 'B'; + public static final char STATE_ZOS_COMSYSKERNELWAIT = 'C'; + public static final char STATE_ZOS_SEMAPHOREWAIT = 'D'; + public static final char STATE_ZOS_QUIESCEFROZEN = 'E'; + public static final char STATE_ZOS_FILESYSKERNELWAIT = 'F'; + public static final char STATE_ZOS_MVSPAUSEWAIT = 'G'; + public static final char STATE_ZOS_PTHREADCREATEDTASKS = 'H'; + public static final char STATE_ZOS_SWAPPEDOUT = 'I'; + public static final char STATE_ZOS_PTHREADCREATED = 'J'; + public static final char STATE_ZOS_OTHERKERNELWAIT = 'K'; + public static final char STATE_ZOS_CANCELLED = 'L'; + public static final char STATE_ZOS_MULTITHREAD = 'M'; + public static final char STATE_ZOS_MEDIUMWEIGHTTHREAD = 'N'; + public static final char STATE_ZOS_ASYNCHRONOUSTHREAD = 'O'; + public static final char STATE_ZOS_PTRACEKERNELWAIT = 'P'; + public static final char STATE_ZOS_RUNNING = 'R'; + public static final char STATE_ZOS_SLEEPING = 'S'; + public static final char STATE_ZOS_STOPPED = 'T'; + public static final char STATE_ZOS_INITIALPROCESSTHREAD = 'U'; + public static final char STATE_ZOS_DETACHED = 'V'; + public static final char STATE_ZOS_WAITINGFORCHILD = 'W'; + public static final char STATE_ZOS_FORKING = 'X'; + public static final char STATE_ZOS_MVSWAIT = 'Y'; + public static final char STATE_ZOS_ZOMBIE = 'Z'; + + public static final int STATE_STARTING_INDEX = 0; + public static final int STATE_ACTIVE_INDEX = 0; + public static final int STATE_IDLE_INDEX = 1; + public static final int STATE_NONEXISTENT_INDEX = 2; + public static final int STATE_PAGING_INDEX = 3; + public static final int STATE_RUNNING_INDEX = 4; + public static final int STATE_SLEEPING_INDEX = 5; + public static final int STATE_TRACED_INDEX = 6; + public static final int STATE_WAITING_INDEX = 7; + public static final int STATE_ZOMBIE_INDEX = 8; + public static final int STATE_ENDING_INDEX = 9; + public static final int STATE_ZOS_STARTING_INDEX = 9; + public static final int STATE_ZOS_SINGLE_INDEX = 9; + public static final int STATE_ZOS_MSGQRECEIVEWAIT_INDEX = 10; + public static final int STATE_ZOS_MSGQSENDWAIT_INDEX = 11; + public static final int STATE_ZOS_COMSYSKERNELWAIT_INDEX = 12; + public static final int STATE_ZOS_SEMAPHOREWAIT_INDEX = 13; + public static final int STATE_ZOS_QUIESCEFROZEN_INDEX = 14; + public static final int STATE_ZOS_FILESYSKERNELWAIT_INDEX = 15; + public static final int STATE_ZOS_MVSPAUSEWAIT_INDEX = 16; + public static final int STATE_ZOS_PTHREADCREATEDTASKS_INDEX = 17; + public static final int STATE_ZOS_SWAPPEDOUT_INDEX = 18; + public static final int STATE_ZOS_PTHREADCREATED_INDEX = 19; + public static final int STATE_ZOS_OTHERKERNELWAIT_INDEX = 20; + public static final int STATE_ZOS_CANCELLED_INDEX = 21; + public static final int STATE_ZOS_MULTITHREAD_INDEX = 22; + public static final int STATE_ZOS_MEDIUMWEIGHTTHREAD_INDEX = 23; + public static final int STATE_ZOS_ASYNCHRONOUSTHREAD_INDEX = 24; + public static final int STATE_ZOS_PTRACEKERNELWAIT_INDEX = 25; + public static final int STATE_ZOS_RUNNING_INDEX = 26; + public static final int STATE_ZOS_SLEEPING_INDEX = 27; + public static final int STATE_ZOS_STOPPED_INDEX = 28; + public static final int STATE_ZOS_INITIALPROCESSTHREAD_INDEX = 29; + public static final int STATE_ZOS_DETACHED_INDEX = 30; + public static final int STATE_ZOS_WAITINGFORCHILD_INDEX = 31; + public static final int STATE_ZOS_FORKING_INDEX = 32; + public static final int STATE_ZOS_MVSWAIT_INDEX = 33; + public static final int STATE_ZOS_ZOMBIE_INDEX = 34; + public static final int STATE_ZOS_ENDING_INDEX = 35; + + public static final char[] ALL_STATES = + { + STATE_ACTIVE, + STATE_IDLE, + STATE_NONEXISTENT, + STATE_PAGING, + STATE_RUNNING, + STATE_SLEEPING, + STATE_TRACED, + STATE_WAITING, + STATE_ZOMBIE, + STATE_ZOS_SINGLE, + STATE_ZOS_MSGQRECEIVEWAIT, + STATE_ZOS_MSGQSENDWAIT, + STATE_ZOS_COMSYSKERNELWAIT, + STATE_ZOS_SEMAPHOREWAIT, + STATE_ZOS_QUIESCEFROZEN, + STATE_ZOS_FILESYSKERNELWAIT, + STATE_ZOS_MVSPAUSEWAIT, + STATE_ZOS_PTHREADCREATEDTASKS, + STATE_ZOS_SWAPPEDOUT, + STATE_ZOS_PTHREADCREATED, + STATE_ZOS_OTHERKERNELWAIT, + STATE_ZOS_CANCELLED, + STATE_ZOS_MULTITHREAD, + STATE_ZOS_MEDIUMWEIGHTTHREAD, + STATE_ZOS_ASYNCHRONOUSTHREAD, + STATE_ZOS_PTRACEKERNELWAIT, + STATE_ZOS_RUNNING, + STATE_ZOS_SLEEPING, + STATE_ZOS_STOPPED, + STATE_ZOS_INITIALPROCESSTHREAD, + STATE_ZOS_DETACHED, + STATE_ZOS_WAITINGFORCHILD, + STATE_ZOS_FORKING, + STATE_ZOS_MVSWAIT, + STATE_ZOS_ZOMBIE + }; + + public static final String[] ALL_STATES_STR = + { + "ASTATE_ACTIVE", + "ISTATE_IDLE", + "OSTATE_NONEXISTENT", + "WSTATE_PAGING", + "RSTATE_RUNNING", + "SSTATE_SLEEPING", + "TSTATE_TRACED", + "DSTATE_WAITING", + "ZSTATE_ZOMBIE", + "1STATE_ZOS_SINGLE", + "ASTATE_ZOS_MSGQRECEIVEWAIT", + "BSTATE_ZOS_MSGQSENDWAIT", + "CSTATE_ZOS_COMSYSKERNELWAIT", + "DSTATE_ZOS_SEMAPHOREWAIT", + "ESTATE_ZOS_QUIESCEFROZEN", + "FSTATE_ZOS_FILESYSKERNELWAIT", + "GSTATE_ZOS_MVSPAUSEWAIT", + "HSTATE_ZOS_PTHREADCREATEDTASKS", + "ISTATE_ZOS_SWAPPEDOUT", + "JSTATE_ZOS_PTHREADCREATED", + "KSTATE_ZOS_OTHERKERNELWAIT", + "LSTATE_ZOS_CANCELLED", + "MSTATE_ZOS_MULTITHREAD", + "NSTATE_ZOS_MEDIUMWEIGHTTHREAD", + "OSTATE_ZOS_ASYNCHRONOUSTHREAD", + "PSTATE_ZOS_PTRACEKERNELWAIT", + "RSTATE_ZOS_RUNNING", + "SSTATE_ZOS_SLEEPING", + "TSTATE_ZOS_STOPPED", + "USTATE_ZOS_INITIALPROCESSTHREAD", + "VSTATE_ZOS_DETACHED", + "WSTATE_ZOS_WAITINGFORCHILD", + "XSTATE_ZOS_FORKING", + "YSTATE_ZOS_MVSWAIT", + "ZSTATE_ZOS_ZOMBIE" + }; + + public static final String PROCESS_MINER_ERROR_NO_HANDLER = "No handler for this system type"; + public static final String PROCESS_MINER_SUCCESS = "SUCCESS"; + + public static final String PROCESS_SIGNAL_TYPE_DEFAULT = "default"; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteTypes.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteTypes.java new file mode 100644 index 00000000000..4462e7460da --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/ISystemProcessRemoteTypes.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes; + + +/** + * All remote object types we support. + * These can be used when registering property pages against remote universal process system objects. + */ +public interface ISystemProcessRemoteTypes +{ + + // ------------------ + // TYPE CATEGORIES... + // ------------------ + + /** + * There is only one type category for remote processes. + * It is "processes". + */ + public static final String TYPECATEGORY = "processes"; + + // ----------- + // TYPES... + // ----------- + + /** + * A process object + */ + public static final String TYPE_PROCESS = "process"; + + /** + * A root process object + */ + public static final String TYPE_ROOT = "rootprocess"; + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/IRemoteServerProcess.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/IRemoteServerProcess.java new file mode 100644 index 00000000000..a61982fa458 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/IRemoteServerProcess.java @@ -0,0 +1,106 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import org.eclipse.rse.services.clientserver.processes.IHostProcess; + +/** + * + * @author mjberger + * + * This interface represents a simple process on the remote server. + * It is simply a data structure for the passing of information about + * a process from the UniversalProcessMiner to the ProcessHandler + * that actually gets all the process information. The setters all + * take strings as input for the sake of convenience, since that is + * how the process information is mined. However, the getters continue + * to return the attributes as their real data types. NOTE THAT THE SETTERS + * HERE DO NOT ACTUALLY MODIFY ANY PROPERTIES OF THE UNDERLYING PROCESS. IN + * ORDER TO DO THIS YOU MUST SEND THE PROCESS A KILL SIGNAL THROUGH THE + * SUBSYSTEM. + *

    + */ +public interface IRemoteServerProcess extends IHostProcess +{ + /** + * Set the process id (pid) associated with this process. + */ + public void setPid(String pid); + + /** + * Set the parent process id (ppid) associated with this process. + */ + public void setPPid(String ppid); + + /** + * Set the name of the executable owning this process + */ + public void setName(String name); + + /** + * Set the state of the process + */ + public void setState(String state); + + /** + * Set the Tgid + */ + public void setTgid(String tgid); + + /** + * Set the TracerPid + */ + public void setTracerPid(String tracerpid); + + /** + * Set the process owner's user id (uid) + */ + public void setUid(String uid); + + /** + * Set the process owner's username + */ + public void setUsername(String username); + + /** + * Set the process owner's group id (gid) + */ + public void setGid(String gid); + + /** + * Sets all properties of this process in the same format as given in the + * dataelement + */ + public void setAllProperties(String allProperties); + + /** + * Sets the virtual memory size of this process (in kB) + */ + public void setVmSizeInKB(String size); + + /** + * Sets the virtual memory resident set size of this process (in kB). + * This is the actual amount of RAM used by the process. + */ + public void setVmRSSInKB(String size); + + /** + * Set the display name for this process. + */ + public void setLabel(String label); + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessComparator.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessComparator.java new file mode 100644 index 00000000000..2f7b36175ea --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessComparator.java @@ -0,0 +1,37 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import java.util.Comparator; + +/** + * Class for comparing two UniversalServerProcessImpl objects + * @author mjberger + * + */ +public class ProcessComparator implements Comparator +{ + /** + * Compares two UniversalServerProcessImpl objects by their PID's. + */ + public int compare(Object obj1, Object obj2) + { + UniversalServerProcessImpl p1 = (UniversalServerProcessImpl) obj1; + UniversalServerProcessImpl p2 = (UniversalServerProcessImpl) obj2; + return (int) (p1.getPid() - p2.getPid()); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandler.java new file mode 100644 index 00000000000..4f95bd3aae3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandler.java @@ -0,0 +1,49 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import java.util.SortedSet; + +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; + + +/** + * Because process mining is system-specific, this interface abstracts out + * the work from the UniversalProcessMiner, and allows system-specific classes + * to take care of the work individually. + */ +public interface ProcessHandler +{ + + /** + * Given a filter string, returns the results of querying all processes that match the filter. + * The results MUST BE SORTED NUMERICALLY BY PID. + * @return a list of the results of the query. Does not ever return null! + * @param rpfs The filter string to which the objects will be matched. + */ + public SortedSet lookupProcesses(IHostProcessFilter rpfs) throws Exception; + + /** + * Sends a kill signal to a process. + * @return the process after the signal is sent, or null if the process no longer exists. + * @param process The process to which the signal will be sent + * @param type The type of signal to send to the process, "default" for default + */ + public IHostProcess kill(IHostProcess process, String type) throws Exception; + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandlerManager.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandlerManager.java new file mode 100644 index 00000000000..9ef4c36b0a3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/ProcessHandlerManager.java @@ -0,0 +1,47 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + + + +public class ProcessHandlerManager +{ + + // the singleton instance + protected static ProcessHandlerManager _instance = new ProcessHandlerManager(); + + /** + * @return The singleton instance of this class. + */ + public static ProcessHandlerManager getInstance() + { + return _instance; + } + + /** + * Returns the ProcessHandler associated with the system type on which + * the server is running, or null if there is no associated ProcessHandler. + */ + public ProcessHandler getNewProcessHandler() + { + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("linux")) return new UniversalLinuxProcessHandler(); + else if (osName.startsWith("aix")) return new UniversalAIXProcessHandler(); + else if (osName.startsWith("z/os")) return new UniversalZOSProcessHandler(); + else return null; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalAIXProcessHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalAIXProcessHandler.java new file mode 100644 index 00000000000..a593c2c5fd4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalAIXProcessHandler.java @@ -0,0 +1,252 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.SortedSet; +import java.util.TreeSet; + +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; + + +public class UniversalAIXProcessHandler implements ProcessHandler, ISystemProcessRemoteConstants +{ + private static final String[] processAttributes = {"pid","ppid","comm","uid","user","gid","vsz","s","rss"}; + private static final String firstColumnHeader = "PID"; + protected HashMap _usernamesByUid; + protected HashMap _uidsByUserName; + private HashMap stateMap; + + /** + * Creates a new ProcessHandler for AIX platforms. + */ + public UniversalAIXProcessHandler() + { + stateMap = new HashMap(); + for (int i = STATE_STARTING_INDEX; i < STATE_ENDING_INDEX; i++) + { + stateMap.put(new Character(ALL_STATES[i]), ALL_STATES_STR[i]); + } + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.processes.clientserver.handlers.ProcessHandler#lookupProcesses(com.ibm.etools.systems.processes.clientserver.RemoteProcessFilterString) + */ + public SortedSet lookupProcesses(IHostProcessFilter rpfs) + throws Exception + { + SortedSet results = new TreeSet(new ProcessComparator()); + + // create the remote command with the AIX specific attributes + String cmdLine = "/usr/sysv/bin/ps -Alf -o "; + for (int i = 0; i < processAttributes.length; i++) + { + cmdLine = cmdLine + processAttributes[i]; + if ((processAttributes.length - i > 1)) cmdLine = cmdLine + ","; + } + // run the command and get output + Process ps = Runtime.getRuntime().exec(cmdLine); + InputStreamReader isr = new InputStreamReader(ps.getInputStream()); + if (isr == null) return null; + BufferedReader reader = new BufferedReader(isr); + if (reader == null) return null; + String nextLine = reader.readLine(); + if (nextLine != null && nextLine.trim().startsWith(firstColumnHeader)) nextLine = reader.readLine(); + while (nextLine != null) + { + String statusLine = ""; + // put the details of each process into a hashmap + HashMap psLineContents = getPSOutput(nextLine); + if (psLineContents == null) + { + nextLine = reader.readLine(); + continue; + } + + String pid = (String) psLineContents.get("pid"); + statusLine = pid + "|"; + + // add the name to the status string + String name = (String) psLineContents.get("comm"); + if (name == null) name = " "; + statusLine = statusLine + name + "|"; + + // add the status letter to the status string + String state = (String) psLineContents.get("s"); + if (state == null) state = " "; + String stateCode = convertToStateCode(state); + statusLine = statusLine + stateCode + "|"; + + // add the Tgid + String tgid = (String) psLineContents.get("tgid"); + if (tgid == null) tgid = " "; + statusLine = statusLine + tgid + "|"; + + // add the Ppid + String pPid = (String) psLineContents.get("ppid"); + if (pPid == null) pPid = " "; + statusLine = statusLine + pPid + "|"; + + // add the TracerPid + String tracerpid = (String) psLineContents.get("tracerpid"); + if (tracerpid == null) tracerpid = " "; + statusLine = statusLine + tracerpid + "|"; + + String uid = (String) psLineContents.get("uid"); + if (uid == null) uid = " "; + statusLine = statusLine + uid + "|"; // add the uid to the status string + + String username = (String) psLineContents.get("user"); + if (username == null) username = " "; + statusLine = statusLine + username + "|"; // add the username to the status string + + // add the gid to the status string + String gid = (String) psLineContents.get("gid"); + if (gid == null) gid = " "; + statusLine = statusLine + gid + "|"; + + // add the VmSize to the status string + String vmsize = (String) psLineContents.get("vsz"); + if (vmsize == null) vmsize = " "; + statusLine = statusLine + vmsize + "|"; + + // add the VmRSS to the status string + String vmrss = (String) psLineContents.get("rss"); + if (vmrss == null) vmrss = " "; + statusLine = statusLine + vmrss; + + if (rpfs.allows(statusLine)) + { + UniversalServerProcessImpl usp = new UniversalServerProcessImpl(statusLine); + results.add(usp); + } + nextLine = reader.readLine(); + } + reader.close(); + isr.close(); + if (results.size() == 0) return null; + return results; + } + + /** + * Parses one line of output from the ps command - placing the contents into + * a hashmap, where the keys are the names of process attributes and the values + * are the attribute values + * @param nextLine a line of output from the ps command + * @return a map of names-values of process attributes + */ + protected HashMap getPSOutput(String nextLine) + { + HashMap contents = new HashMap(); + String[] values = nextLine.trim().split("\\s+"); + if (values == null || values.length < processAttributes.length) return null; + for (int i = 0; i < processAttributes.length; i++) + { + contents.put(processAttributes[i], values[i]); + } + return contents; + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.processes.clientserver.handlers.ProcessHandler#kill(com.ibm.etools.systems.processes.clientserver.handlers.IRemoteServerProcess, java.lang.String) + */ + public IHostProcess kill(IHostProcess process, String type) + throws Exception + { + if (type.equals(PROCESS_SIGNAL_TYPE_DEFAULT)) type = ""; + else type = "-" + type; + // formulate command to send kill signal + String cmdLine = "kill " + type + " " + process.getPid(); + Runtime.getRuntime().exec(cmdLine); + + // after the kill command is executed, the process might have changed + // attributes, or might be gone, so requery + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setPid("" + process.getPid()); + SortedSet results = lookupProcesses(rpfs); + if (results == null || results.size() == 0) return null; + else return (IHostProcess) results.first(); + } + + /** + * Populates the internal hashmap with uid/username info + protected void populateUsernames() + { + _usernamesByUid = new HashMap(); + _uidsByUserName = new HashMap(); + + try + { + // read the uid info from the lsuser command + Process ps = Runtime.getRuntime().exec("lsuser -c -a id ALL"); + InputStreamReader isr = new InputStreamReader(ps.getInputStream()); + if (isr == null) return; + BufferedReader reader = new BufferedReader(isr); + if (reader == null) return; + + String nextLine; + + while ((nextLine = reader.readLine()) != null) + { + if (nextLine.trim().startsWith("#name")) continue; + String[] fields = nextLine.split(":"); + int length = fields.length; + if (length < 2) continue; + String uid = fields[1]; + String username = fields[0]; + if (uid != null && username != null) + { + _usernamesByUid.put(uid, username); + _uidsByUserName.put(username, uid); + } + } + reader.close(); + isr.close(); + } + catch (IOException e) + { return; } + catch (Exception e) + { return; } + }*/ + + /** + * Return the unique state code assocated with the state given by + * the ps listing on the AIX machine. + */ + protected String convertToStateCode(String state) + { + String stateCode = " "; + if (state == null) return stateCode; + if (state.trim().equals("")) return stateCode; + for (int i = 0; i < state.length(); i++) + { + String nextState = (String) stateMap.get(new Character(state.charAt(i))); + if (nextState != null) + { + stateCode = stateCode + nextState; + if (i < state.length() - 1) stateCode = stateCode + ","; + } + } + if (stateCode.trim().equals("")) return " "; + else return stateCode.trim(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalLinuxProcessHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalLinuxProcessHandler.java new file mode 100644 index 00000000000..fed786eb617 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalLinuxProcessHandler.java @@ -0,0 +1,316 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.SortedSet; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import org.eclipse.rse.services.clientserver.IServiceConstants; +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; + +public class UniversalLinuxProcessHandler implements ProcessHandler, IServiceConstants, ISystemProcessRemoteConstants +{ + + protected HashMap _usernamesByUid; + protected HashMap _uidsByUserName; + private HashMap stateMap; + + /** + * Creates a new ProcessHandler for Linux platforms. + */ + public UniversalLinuxProcessHandler() + { + stateMap = new HashMap(); + for (int i = STATE_STARTING_INDEX; i < STATE_ENDING_INDEX; i++) + { + stateMap.put(new Character(ALL_STATES[i]), ALL_STATES_STR[i]); + } + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.universal.processes.ProcessHandler#kill(com.ibm.etools.systems.universal.processes.IRemoteServerProcess, java.lang.String) + */ + public IHostProcess kill(IHostProcess process, String type) throws Exception + { + if (type.equals(PROCESS_SIGNAL_TYPE_DEFAULT)) type = ""; + else type = "-" + type; + // formulate command to send kill signal + String cmdLine = "kill " + type + " " + process.getPid(); + Runtime.getRuntime().exec(cmdLine); + + // after the kill command is executed, the process might have changed + // attributes, or might be gone, so requery + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setPid("" + process.getPid()); + SortedSet results = lookupProcesses(rpfs); + if (results == null || results.size() == 0) return null; + else return (IHostProcess) results.first(); + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.universal.processes.ProcessHandler#lookupProcesses(com.ibm.etools.systems.processes.clientserver.RemoteProcessFilterString, java.lang.String) + */ + public SortedSet lookupProcesses(IHostProcessFilter rpfs) throws Exception + { + File procDir = new File("/proc"); + + if (!procDir.exists()) + throw new Exception(FAILED_WITH_DOES_NOT_EXIST); + + if (!procDir.canRead()) + throw new Exception(FAILED_WITH_SECURITY); + + // list all subdirectories of /proc + File[] processes; + if (rpfs.getPid().indexOf("*") == -1) + { + processes = new File[1]; + processes[0] = new File(procDir, rpfs.getPid()); + } + else processes = procDir.listFiles(); + + SortedSet results = new TreeSet(new ProcessComparator()); + + for (int i = 0; i < processes.length; i++) + { + // make sure the directory is a process directory (an integer) + try + { Integer.valueOf(processes[i].getName()); } + catch (NumberFormatException e) + { continue; } + + String statusLine = ""; + try + { + // open the file containing the human-readable status info for the process + File statusFile = new File(processes[i], "status"); + if (!statusFile.exists() || !statusFile.canRead()) + continue; + + // read the status info from the stat file + FileReader fr = new FileReader(statusFile); + if (fr == null) continue; + BufferedReader reader = new BufferedReader(fr); + if (reader == null) continue; + HashMap statusFileContents = getStatusFileContents(reader); + + statusLine = processes[i].getName() + "|"; // add the pid to the status string + + // add the name to the status string + String name = (String) statusFileContents.get("name"); + if (name == null) name = " "; + //if (!pexematcher.matches(name)) continue; + statusLine = statusLine + name + "|"; + + // add the status letter to the status string + String state = (String) statusFileContents.get("state"); + if (state == null) state = " "; + String stateCode = convertToStateCode(state); + statusLine = statusLine + stateCode + "|"; + + // add the Tgid + String tgid = (String) statusFileContents.get("tgid"); + if (tgid == null) tgid = " "; + statusLine = statusLine + tgid + "|"; + + // add the Ppid + String pPid = (String) statusFileContents.get("ppid"); + if (pPid == null) pPid = " "; + //if (!ppidmatcher.matches(pPid)) continue; + statusLine = statusLine + pPid + "|"; + + // add the TracerPid + String tracerpid = (String) statusFileContents.get("tracerpid"); + if (tracerpid == null) tracerpid = " "; + statusLine = statusLine + tracerpid + "|"; + + String uid = (String) statusFileContents.get("uid"); + if (uid == null) uid = " "; + statusLine = statusLine + uid + "|"; // add the uid to the status string + + String username = getUsername(uid); + if (username == null) username = " "; + statusLine = statusLine + username + "|"; // add the username to the status string + + // add the gid to the status string + String gid = (String) statusFileContents.get("gid"); + if (gid == null) gid = " "; + statusLine = statusLine + gid + "|"; + + // add the VmSize to the status string + String vmsize = (String) statusFileContents.get("vmsize"); + if (vmsize == null) vmsize = " "; + statusLine = statusLine + vmsize + "|"; + + // add the VmRSS to the status string + String vmrss = (String) statusFileContents.get("vmrss"); + if (vmrss == null) vmrss = " "; + statusLine = statusLine + vmrss; + + reader.close(); + fr.close(); + } + catch (Exception e) + { + continue; + } + if (rpfs.allows(statusLine)) + { + UniversalServerProcessImpl usp = new UniversalServerProcessImpl(statusLine); + results.add(usp); + } + } // for loop + return results; + } + + /** + * Gets the uid associated with the given username on this system + */ + public String getUid(String username) + { + if (_uidsByUserName == null) populateUsernames(); + return (String) _uidsByUserName.get(username); + } + + /** + * Gets the username associated with the given uid on this system + */ + public String getUsername(String uid) + { + if (_usernamesByUid == null) populateUsernames(); + return (String) _usernamesByUid.get(uid); + } + + /** + * Given a handle to the status file for a process, parses the data + * in that status file and returns it as a key-value hashmap of + * attributes. + * @param reader A buffered reader of the status file + * @return a hashmap indexed by attribute name + */ + private HashMap getStatusFileContents(BufferedReader reader) + { + + HashMap contents = new HashMap(); + String nextLine; + try + { + while ((nextLine = reader.readLine()) != null) + { + if (nextLine == null) break; + String key = nextLine.substring(0, nextLine.indexOf(":")).trim().toLowerCase(); + String theRest = processStatusLine(nextLine, -1); + StringTokenizer tz = new StringTokenizer(theRest); + String value = null; + if (tz.hasMoreTokens()) value = tz.nextToken(); + if (key != null && value != null) contents.put(key, value); + } + } + catch (Exception e) + { + } + return contents; + } + + /** + * Returns all or part of line after the first ':' character, trimmed. + * @param line the line to process + * @param length the number of characters (after trimming) to return (-1 for all) + */ + private String processStatusLine(String line, int length) + { + if (length == -1) + { + return line.substring(line.indexOf(":") + 1).trim(); + } + else + return line.substring(line.indexOf(":") + 1).trim().substring(0, length); + } + + /** + * Populates the internal hashmap with uid/username info + */ + private void populateUsernames() + { + _usernamesByUid = new HashMap(); + _uidsByUserName = new HashMap(); + + try + { + // read the uid info using the getent command + Process ps = Runtime.getRuntime().exec("getent passwd"); + InputStreamReader isr = new InputStreamReader(ps.getInputStream()); + if (isr == null) return; + BufferedReader reader = new BufferedReader(isr); + if (reader == null) return; + + String nextLine; + + while ((nextLine = reader.readLine()) != null) + { + String[] fields = nextLine.split(":"); + int length = fields.length; + if (length < 3) continue; + String uid = fields[2]; + String username = fields[0]; + if (uid != null && username != null) + { + _usernamesByUid.put(uid, username); + _uidsByUserName.put(username, uid); + } + } + reader.close(); + isr.close(); + } + catch (IOException e) + { return; } + catch (Exception e) + { return; } + } + + /** + * Return the unique state code assocated with the state given by + * the status file on the Linux machine. + */ + protected String convertToStateCode(String state) + { + String stateCode = " "; + if (state == null) return stateCode; + if (state.trim().equals("")) return stateCode; + for (int i = 0; i < state.length(); i++) + { + String nextState = (String) stateMap.get(new Character(state.charAt(i))); + if (nextState != null) + { + stateCode = stateCode + nextState; + if (i < state.length() - 1) stateCode = stateCode + ","; + } + } + if (stateCode.trim().equals("")) return " "; + else return stateCode.trim(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalServerProcessImpl.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalServerProcessImpl.java new file mode 100644 index 00000000000..7b2cd9a96c1 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalServerProcessImpl.java @@ -0,0 +1,293 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import org.eclipse.rse.services.clientserver.IServiceConstants; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; + +/** + * @author mjberger + */ +public class UniversalServerProcessImpl implements IRemoteServerProcess, IServiceConstants, ISystemProcessRemoteConstants +{ + protected Object[] _properties = new Object[PROCESS_ATTRIBUTES_COUNT+1]; + + /** + * create a new UniversalServerProcessImpl with the default property set + */ + public UniversalServerProcessImpl() + { + _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME] = " "; + _properties[PROCESS_ATTRIBUTES_INDEX_GID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_PID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_PPID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_STATUS] = new String(" "); + _properties[PROCESS_ATTRIBUTES_INDEX_TGID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_UID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME] = " "; + _properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_VMRSS] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_COUNT] = " "; //set the label + } + + /** + * create a new UniversalServerProcessImpl with initial Attributes. + * This is equivalent to constructing the object, then calling setAllProperties(initialAttributes) + */ + public UniversalServerProcessImpl(String initialAttributes) + { + setAllProperties(initialAttributes); + } + + protected Long getLongAttribute(String value, long dflt) + { + long result; + try + { + result = Long.parseLong(value); + } + catch (NumberFormatException e) + { + return new Long(dflt); + } + return new Long(result); + } + + protected Integer getIntAttribute(String value, int dflt) + { + int result; + try + { + result = Integer.parseInt(value); + } + catch (NumberFormatException e) + { + return new Integer(dflt); + } + return new Integer(result); + } + + public void setPid(String pid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_PID] = getLongAttribute(pid, -1); + } + + public void setPPid(String ppid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_PPID] = getLongAttribute(ppid, -1); + + } + + public void setName(String name) + { + _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME] = name; + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.processes.clientserver.IRemoteProcess#getLabel() + */ + public String getLabel() + { + return (String) _properties[PROCESS_ATTRIBUTES_COUNT]; + } + + public void setLabel(String label) + { + _properties[PROCESS_ATTRIBUTES_COUNT] = label; + } + + public void setState(String state) + { + _properties[PROCESS_ATTRIBUTES_INDEX_STATUS] = state; + } + + public void setTgid(String tgid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_TGID] = getLongAttribute(tgid, -1); + } + + public void setTracerPid(String tracerpid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID] = getLongAttribute(tracerpid, -1); + } + + public void setUid(String uid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_UID] = getLongAttribute(uid, -1); + } + + public void setUsername(String username) + { + _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME] = username; + } + + public void setGid(String gid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_GID] = getLongAttribute(gid, -1); + } + + public void setVmSizeInKB(String size) + { + _properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE] = getLongAttribute(size, 0); + } + + public void setVmRSSInKB(String size) + { + _properties[PROCESS_ATTRIBUTES_INDEX_VMRSS] = getLongAttribute(size, 0); + } + + /** + * You can also set all attributes at once with your own string passed as a parameter, as long + * as the string is in the same format as outlined below (pass in null to use the DataElement's string): + *

    The string contains properties of the object in the following order + *

      + *
    • Process Id (pid) - long + *
    • Executable name - String + *
    • Status - char + *
    • Tgid - long + *
    • Process Parent id (ppid) - long + *
    • Tracer pid - long + *
    • User id (uid) - long + *
    • Username - String + *
    • Group id (gid) - long + *
    • VM Size - long + *
    • VM RSS - long + *
    + */ + public void setAllProperties(String allProperties) + { + String s = allProperties; + + if (s != null && s.length() > 0) + { + String[] str = s.split("\\"+TOKEN_SEPARATOR); + int numOfExpectedTokens = PROCESS_ATTRIBUTES_COUNT; + int tokens = str.length; + if (tokens == numOfExpectedTokens) + { + try + { + setPid(str[PROCESS_ATTRIBUTES_INDEX_PID]); + + setName(str[PROCESS_ATTRIBUTES_INDEX_EXENAME]); + + setTgid(str[PROCESS_ATTRIBUTES_INDEX_TGID]); + + setPPid(str[PROCESS_ATTRIBUTES_INDEX_PPID]); + + setTracerPid(str[PROCESS_ATTRIBUTES_INDEX_TRACERPID]); + + setUid(str[PROCESS_ATTRIBUTES_INDEX_UID]); + + setUsername(str[PROCESS_ATTRIBUTES_INDEX_USERNAME]); + + setGid(str[PROCESS_ATTRIBUTES_INDEX_GID]); + + setVmSizeInKB(str[PROCESS_ATTRIBUTES_INDEX_VMSIZE]); + + setVmRSSInKB(str[PROCESS_ATTRIBUTES_INDEX_VMRSS]); + + setState(str[PROCESS_ATTRIBUTES_INDEX_STATUS]); + + setLabel(getName()); + + } + catch (ArrayIndexOutOfBoundsException e) + { + // SystemPlugin.logError("Error in UniversalProcessImpl.getAttributes(). Attributes in unexpected format. Attributes = " + s); + } + } + } + } + + public long getPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_PID]).longValue(); + } + + public long getPPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_PPID]).longValue(); + } + + public String getName() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME]; + } + + public String getState() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_STATUS]; + } + + public long getTgid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_TGID]).longValue(); + } + + public long getTracerPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID]).longValue(); + } + + public long getUid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_UID]).intValue(); + } + + public String getUsername() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME]; + } + + public long getGid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_GID]).intValue(); + } + + public boolean isRoot() + { + return (getPPid() == 0); + } + + public long getVmSizeInKB() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE]).longValue(); + } + + public long getVmRSSInKB() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_VMRSS]).longValue(); + } + + /** + * Return all the properties of this data structure in one string. + * Properties are separated by IUniversalDataStoreConstants.TOKEN_SEPARATOR; + */ + public String getAllProperties() + { + String properties = ""; + for (int i = 0; i < PROCESS_ATTRIBUTES_COUNT; i++) + { + properties = properties + _properties[i].toString(); + if (i != PROCESS_ATTRIBUTES_COUNT - 1) + properties = properties + TOKEN_SEPARATOR; + } + return properties; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalZOSProcessHandler.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalZOSProcessHandler.java new file mode 100644 index 00000000000..8e14e520971 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/processes/handlers/UniversalZOSProcessHandler.java @@ -0,0 +1,186 @@ +/******************************************************************************** + * Copyright (c) 2005, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.processes.handlers; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl; + + +public class UniversalZOSProcessHandler extends UniversalAIXProcessHandler +{ + private static final String[] processAttributes = {"pid","ppid","comm","uid","user","gid","vsz","state"}; + private static final String firstColumnHeader = "PID"; + private HashMap stateMap; + + /** + * Creates a new ProcessHandler for z/OS platforms. + */ + public UniversalZOSProcessHandler() + { + super(); + stateMap = new HashMap(); + for (int i = STATE_ZOS_STARTING_INDEX; i < STATE_ZOS_ENDING_INDEX; i++) + { + stateMap.put(new Character(ALL_STATES[i]), ALL_STATES_STR[i]); + } + } + + /* (non-Javadoc) + * @see com.ibm.etools.systems.processes.clientserver.handlers.ProcessHandler#lookupProcesses(com.ibm.etools.systems.processes.clientserver.RemoteProcessFilterString) + */ + public SortedSet lookupProcesses(HostProcessFilterImpl rpfs) + throws Exception + { + SortedSet results = new TreeSet(new ProcessComparator()); + + // create the remote command with the AIX specific attributes + String cmdLine = "ps -A -o "; + for (int i = 0; i < processAttributes.length; i++) + { + cmdLine = cmdLine + processAttributes[i]; + if ((processAttributes.length - i > 1)) cmdLine = cmdLine + ","; + } + // run the command and get output + Process ps = Runtime.getRuntime().exec(cmdLine); + InputStreamReader isr = new InputStreamReader(ps.getInputStream()); + if (isr == null) return null; + BufferedReader reader = new BufferedReader(isr); + if (reader == null) return null; + String nextLine = reader.readLine(); + if (nextLine != null && nextLine.trim().startsWith(firstColumnHeader)) nextLine = reader.readLine(); + while (nextLine != null) + { + String statusLine = ""; + // put the details of each process into a hashmap + HashMap psLineContents = getPSOutput(nextLine); + if (psLineContents == null) + { + nextLine = reader.readLine(); + continue; + } + + String pid = (String) psLineContents.get("pid"); + statusLine = pid + "|"; + + // add the name to the status string + String name = (String) psLineContents.get("comm"); + if (name == null) name = " "; + statusLine = statusLine + name + "|"; + + // add the status letter to the status string + String state = (String) psLineContents.get("state"); + if (state == null) state = " "; + String stateCode = convertToStateCode(state); + statusLine = statusLine + stateCode + "|"; + + // add the Tgid + String tgid = (String) psLineContents.get("tgid"); + if (tgid == null) tgid = " "; + statusLine = statusLine + tgid + "|"; + + // add the Ppid + String pPid = (String) psLineContents.get("ppid"); + if (pPid == null) pPid = " "; + statusLine = statusLine + pPid + "|"; + + // add the TracerPid + String tracerpid = (String) psLineContents.get("tracerpid"); + if (tracerpid == null) tracerpid = " "; + statusLine = statusLine + tracerpid + "|"; + + String uid = (String) psLineContents.get("uid"); + if (uid == null) uid = " "; + statusLine = statusLine + uid + "|"; // add the uid to the status string + + String username = (String) psLineContents.get("user"); + if (username == null) username = " "; + statusLine = statusLine + username + "|"; // add the username to the status string + + // add the gid to the status string + String gid = (String) psLineContents.get("gid"); + if (gid == null) gid = " "; + statusLine = statusLine + gid + "|"; + + // add the VmSize to the status string + String vmsize = (String) psLineContents.get("vsz"); + if (vmsize == null) vmsize = " "; + statusLine = statusLine + vmsize +"|"; + + // add a dummy vmrss to the status string + // vmRss is not available on ZOS + String vmrss = " "; + statusLine = statusLine + vmrss; + + if (rpfs.allows(statusLine)) + { + UniversalServerProcessImpl usp = new UniversalServerProcessImpl(statusLine); + results.add(usp); + } + nextLine = reader.readLine(); + } + reader.close(); + isr.close(); + if (results.size() == 0) return null; + return results; + } + + /** + * Parses one line of output from the ps command - placing the contents into + * a hashmap, where the keys are the names of process attributes and the values + * are the attribute values + * @param nextLine a line of output from the ps command + * @return a map of names-values of process attributes + */ + protected HashMap getPSOutput(String nextLine) + { + HashMap contents = new HashMap(); + String[] values = nextLine.trim().split("\\s+"); + if (values == null || values.length < processAttributes.length) return null; + for (int i = 0; i < processAttributes.length; i++) + { + contents.put(processAttributes[i], values[i]); + } + return contents; + } + + /** + * Return the unique state code assocated with the state given by + * the ps listing on the z/OS machine. + */ + protected String convertToStateCode(String state) + { + String stateCode = " "; + if (state == null) return stateCode; + if (state.trim().equals("")) return stateCode; + for (int i = 0; i < state.length(); i++) + { + String nextState = (String) stateMap.get(new Character(state.charAt(i))); + if (nextState != null) + { + stateCode = stateCode + nextState; + if (i < state.length() - 1) stateCode = stateCode + ","; + } + } + if (stateCode.trim().equals("")) return " "; + else return stateCode.trim(); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchConstants.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchConstants.java new file mode 100644 index 00000000000..2cfffd949f4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchConstants.java @@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +/** + * An interface for search constants. + */ +public interface ISystemSearchConstants { + + public static final int LF_CHAR = '\n'; + public static final int CR_CHAR = '\r'; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchMatcher.java new file mode 100644 index 00000000000..ec22d5765e5 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/ISystemSearchMatcher.java @@ -0,0 +1,26 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import org.eclipse.rse.services.clientserver.IMatcher; + +/** + * An interface for matching that search will use. + */ +public interface ISystemSearchMatcher extends IMatcher { + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemNonRegexMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemNonRegexMatcher.java new file mode 100644 index 00000000000..93aaecc6dc5 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemNonRegexMatcher.java @@ -0,0 +1,400 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.util.Vector; + +/** + * A string pattern matcher, suppporting * and ? wildcards. + */ +public class SystemNonRegexMatcher { + protected String fPattern; + protected int fLength; // pattern length + protected boolean fIgnoreWildCards; + protected boolean fIgnoreCase; + protected boolean fHasLeadingStar; + protected boolean fHasTrailingStar; + protected String fSegments[]; //the given pattern is split into * separated segments + + /* boundary value beyond which we don't need to search in the text */ + protected int fBound= 0; + + + protected static final char fSingleWildCard= '\u0000'; + + public static class Position { + int start; //inclusive + int end; //exclusive + public Position(int start, int end) { + this.start= start; + this.end= end; + } + public int getStart() { + return start; + } + public int getEnd() { + return end; + } + } + /** + * StringMatcher constructor takes in a String object that is a simple + * pattern which may contain '*' for 0 and many characters and + * '?' for exactly one character. + * + * Literal '*' and '?' characters must be escaped in the pattern + * e.g., "\*" means literal "*", etc. + * + * Escaping any other character (including the escape character itself), + * just results in that character in the pattern. + * e.g., "\a" means "a" and "\\" means "\" + * + * If invoking the StringMatcher with string literals in Java, don't forget + * escape characters are represented by "\\". + * + * @param pattern the pattern to match text against + * @param ignoreCase if true, case is ignored + * @param ignoreWildCards if true, wild cards and their escape sequences are ignored + * (everything is taken literally). + */ + public SystemNonRegexMatcher(String pattern, boolean ignoreCase, boolean ignoreWildCards) { + if (pattern == null) + throw new IllegalArgumentException(); + fIgnoreCase= ignoreCase; + fIgnoreWildCards= ignoreWildCards; + fPattern= pattern; + fLength= pattern.length(); + + if (fIgnoreWildCards) { + parseNoWildCards(); + } else { + parseWildCards(); + } + } + /** + * Find the first occurrence of the pattern between startend(exclusive). + * @param text, the String object to search in + * @param start, the starting index of the search range, inclusive + * @param end, the ending index of the search range, exclusive + * @return an StringMatcher.Position object that keeps the starting + * (inclusive) and ending positions (exclusive) of the first occurrence of the + * pattern in the specified range of the text; return null if not found or subtext + * is empty (start==end). A pair of zeros is returned if pattern is empty string + * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc" + * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned + */ + public SystemNonRegexMatcher.Position find(String text, int start, int end) { + if (text == null) + throw new IllegalArgumentException(); + + int tlen= text.length(); + if (start < 0) + start= 0; + if (end > tlen) + end= tlen; + if (end < 0 ||start >= end ) + return null; + if (fLength == 0) + return new Position(start, start); + if (fIgnoreWildCards) { + int x= posIn(text, start, end); + if (x < 0) + return null; + return new Position(x, x+fLength); + } + + int segCount= fSegments.length; + if (segCount == 0)//pattern contains only '*'(s) + return new Position (start, end); + + int curPos= start; + int matchStart= -1; + int i; + for (i= 0; i < segCount && curPos < end; ++i) { + String current= fSegments[i]; + int nextMatch= regExpPosIn(text, curPos, end, current); + if (nextMatch < 0 ) + return null; + if(i == 0) + matchStart= nextMatch; + curPos= nextMatch + current.length(); + } + if (i < segCount) + return null; + return new Position(matchStart, curPos); + } + /** + * match the given text with the pattern + * @return true if matched eitherwise false + * @param text, a String object + */ + public boolean match(String text) { + return match(text, 0, text.length()); + } + /** + * Given the starting (inclusive) and the ending (exclusive) positions in the + * text, determine if the given substring matches with aPattern + * @return true if the specified portion of the text matches the pattern + * @param String text, a String object that contains the substring to match + * @param int start marks the starting position (inclusive) of the substring + * @param int end marks the ending index (exclusive) of the substring + */ + public boolean match(String text, int start, int end) { + if (null == text) + throw new IllegalArgumentException(); + + if (start > end) + return false; + + if (fIgnoreWildCards) + return (end - start == fLength) && fPattern.regionMatches(fIgnoreCase, 0, text, start, fLength); + int segCount= fSegments.length; + if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar)) // pattern contains only '*'(s) + return true; + if (start == end) + return fLength == 0; + if (fLength == 0) + return start == end; + + int tlen= text.length(); + if (start < 0) + start= 0; + if (end > tlen) + end= tlen; + + int tCurPos= start; + int bound= end - fBound; + if ( bound < 0) + return false; + int i=0; + String current= fSegments[i]; + int segLength= current.length(); + + /* process first segment */ + if (!fHasLeadingStar){ + if(!regExpRegionMatches(text, start, current, 0, segLength)) { + return false; + } else { + ++i; + tCurPos= tCurPos + segLength; + } + } + if ((fSegments.length == 1) && (!fHasLeadingStar) && (!fHasTrailingStar)) { + // only one segment to match, no wildcards specified + return tCurPos == end; + } + /* process middle segments */ + while (i < segCount) { + current= fSegments[i]; + int currentMatch; + int k= current.indexOf(fSingleWildCard); + if (k < 0) { + currentMatch= textPosIn(text, tCurPos, end, current); + if (currentMatch < 0) + return false; + } else { + currentMatch= regExpPosIn(text, tCurPos, end, current); + if (currentMatch < 0) + return false; + } + tCurPos= currentMatch + current.length(); + i++; + } + + /* process final segment */ + if (!fHasTrailingStar && tCurPos != end) { + int clen= current.length(); + return regExpRegionMatches(text, end - clen, current, 0, clen); + } + return i == segCount ; + } + + /** + * This method parses the given pattern into segments seperated by wildcard '*' characters. + * Since wildcards are not being used in this case, the pattern consists of a single segment. + */ + private void parseNoWildCards() { + fSegments= new String[1]; + fSegments[0]= fPattern; + fBound= fLength; + } + /** + * Parses the given pattern into segments seperated by wildcard '*' characters. + * @param p, a String object that is a simple regular expression with ‘*’ and/or ‘?’ + */ + private void parseWildCards() { + if(fPattern.startsWith("*"))//$NON-NLS-1$ + fHasLeadingStar= true; + if(fPattern.endsWith("*")) {//$NON-NLS-1$ + /* make sure it's not an escaped wildcard */ + if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') { + fHasTrailingStar= true; + } + } + + Vector temp= new Vector(); + + int pos= 0; + StringBuffer buf= new StringBuffer(); + while (pos < fLength) { + char c= fPattern.charAt(pos++); + switch (c) { + case '\\': + if (pos >= fLength) { + buf.append(c); + } else { + char next= fPattern.charAt(pos++); + /* if it's an escape sequence */ + if (next == '*' || next == '?' || next == '\\') { + buf.append(next); + } else { + /* not an escape sequence, just insert literally */ + buf.append(c); + buf.append(next); + } + } + break; + case '*': + if (buf.length() > 0) { + /* new segment */ + temp.addElement(buf.toString()); + fBound += buf.length(); + buf.setLength(0); + } + break; + case '?': + /* append special character representing single match wildcard */ + buf.append(fSingleWildCard); + break; + default: + buf.append(c); + } + } + + /* add last buffer to segment list */ + if (buf.length() > 0) { + temp.addElement(buf.toString()); + fBound += buf.length(); + } + + fSegments= new String[temp.size()]; + temp.copyInto(fSegments); + } + /** + * @param text, a string which contains no wildcard + * @param start, the starting index in the text for search, inclusive + * @param end, the stopping point of search, exclusive + * @return the starting index in the text of the pattern , or -1 if not found + */ + protected int posIn(String text, int start, int end) {//no wild card in pattern + int max= end - fLength; + + if (!fIgnoreCase) { + int i= text.indexOf(fPattern, start); + if (i == -1 || i > max) + return -1; + return i; + } + + for (int i= start; i <= max; ++i) { + if (text.regionMatches(true, i, fPattern, 0, fLength)) + return i; + } + + return -1; + } + /** + * @param text, a simple regular expression that may only contain '?'(s) + * @param start, the starting index in the text for search, inclusive + * @param end, the stopping point of search, exclusive + * @param p, a simple regular expression that may contains '?' + * @param caseIgnored, wether the pattern is not casesensitive + * @return the starting index in the text of the pattern , or -1 if not found + */ + protected int regExpPosIn(String text, int start, int end, String p) { + int plen= p.length(); + + int max= end - plen; + for (int i= start; i <= max; ++i) { + if (regExpRegionMatches(text, i, p, 0, plen)) + return i; + } + return -1; + } + /** + * + * @return boolean + * @param text, a String to match + * @param start, int that indicates the starting index of match, inclusive + * @param end int that indicates the ending index of match, exclusive + * @param p, String, String, a simple regular expression that may contain '?' + * @param ignoreCase, boolean indicating wether code>p is case sensitive + */ + protected boolean regExpRegionMatches(String text, int tStart, String p, int pStart, int plen) { + while (plen-- > 0) { + char tchar= text.charAt(tStart++); + char pchar= p.charAt(pStart++); + + /* process wild cards */ + if (!fIgnoreWildCards) { + /* skip single wild cards */ + if (pchar == fSingleWildCard) { + continue; + } + } + if (pchar == tchar) + continue; + if (fIgnoreCase) { + if (Character.toUpperCase(tchar) == Character.toUpperCase(pchar)) + continue; + // comparing after converting to upper case doesn't handle all cases; + // also compare after converting to lower case + if (Character.toLowerCase(tchar) == Character.toLowerCase(pchar)) + continue; + } + return false; + } + return true; + } + /** + * @param text, the string to match + * @param start, the starting index in the text for search, inclusive + * @param end, the stopping point of search, exclusive + * @param code>p, a string that has no wildcard + * @param ignoreCase, boolean indicating wether code>p is case sensitive + * @return the starting index in the text of the pattern , or -1 if not found + */ + protected int textPosIn(String text, int start, int end, String p) { + + int plen= p.length(); + int max= end - plen; + + if (!fIgnoreCase) { + int i= text.indexOf(p, start); + if (i == -1 || i > max) + return -1; + return i; + } + + for (int i= start; i <= max; ++i) { + if (text.regionMatches(true, i, p, 0, plen)) + return i; + } + + return -1; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchFileNameMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchFileNameMatcher.java new file mode 100644 index 00000000000..d2bab3420d8 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchFileNameMatcher.java @@ -0,0 +1,134 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.Vector; +import java.util.regex.Pattern; + + +/** + * A file name matcher for search. + */ +public class SystemSearchFileNameMatcher implements ISystemSearchMatcher { + + private String fileNamesString; + private boolean isRegex; + + // for non regular expression + private List nonRegexMatchers; + + // for regular regular expression + private Pattern pattern; + + /** + * Constructor to create a file name matcher. + * @param fileNamesString the file names string. + * @param isCaseSensitive true if the matching should be done in a case sensitive manner, false otherwise. + * @param isRegex true if the file names string is a regular expression, false otherwise. + * @throws NullPointerException if the file names string is null. + */ + public SystemSearchFileNameMatcher(String fileNamesString, boolean isCaseSensitive, boolean isRegex) { + + if (fileNamesString == null) { + throw new NullPointerException(); + } + + this.fileNamesString = fileNamesString; + this.isRegex = isRegex; + + // if the file names string is a regular expression, then simply add it + if (isRegex) { + + + try { + if (isCaseSensitive) { + pattern = Pattern.compile(fileNamesString); + } + else { + pattern = Pattern.compile(fileNamesString, Pattern.CASE_INSENSITIVE); + } + } + catch (Exception e) { + // TODO: log it. How? + } + } + // otherwise, get all the names from the names string, and add a non regex matcher for each + else { + nonRegexMatchers = new Vector(); + + Set names = SystemSearchUtil.getInstance().typesStringToSet(fileNamesString); + + Iterator iter = names.iterator(); + + while (iter.hasNext()) { + String name = (String)(iter.next()); + SystemNonRegexMatcher nonRegexMatcher = new SystemNonRegexMatcher(name, !isCaseSensitive, false); + nonRegexMatchers.add(nonRegexMatcher); + } + } + } + + /** + * Returns whether the file names string is empty. + * @return true if the file names string is empty, false otherwise. + */ + public boolean isFileNamesStringEmpty() { + return fileNamesString.length() == 0; + } + + /** + * Returns whether the file names string is "*". + * @return true if the file names string is "*", false otherwise. + */ + public boolean isFileNamesStringAsterisk() { + return fileNamesString.equals("*"); + } + + /** + * Returns whether there is a match for the given input. Returns true if the file names string + * is an empty string. + * @see org.eclipse.rse.services.clientserver.ISystemSearchMatcher#matches(java.lang.String) + */ + public boolean matches(String input) { + + if (isFileNamesStringEmpty()) { + return true; + } + + if (isRegex) { + return pattern.matcher(input).find(); + } + else { + Iterator iter = nonRegexMatchers.iterator(); + + while (iter.hasNext()) { + SystemNonRegexMatcher matcher = (SystemNonRegexMatcher)iter.next(); + + // TODO (KM): in SystemSearchStringMatcher, we had to use find() instead of match(). + // Should we use this here as well? What is the difference between match() and find()? Investigate. + if (matcher.match(input)) { + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchLineMatch.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchLineMatch.java new file mode 100644 index 00000000000..9f17693bba4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchLineMatch.java @@ -0,0 +1,84 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This class holds information about search results for a line of text. Its instance variables + * are public so that we can access them without having to call methods (for performance reasons). + */ +public class SystemSearchLineMatch { + + private String line; + private int lineNumber; + private List matches; + + /** + * Constructor to create a search result for a line. + * @param line the line. + * @param lineNumber the line number. + */ + public SystemSearchLineMatch(String line, int lineNumber) { + this.line = line; + this.lineNumber = lineNumber; + this.matches = new ArrayList(); + } + + /** + * Returns the line that matched. + * @return the line. + */ + public String getLine() { + return line; + } + + /** + * Returns the line number of the line that matched. + * @return the line number. + */ + public int getLineNumber() { + return lineNumber; + } + + /** + * Gets the iterator for the matches in the line. + * @return the iterator over the list of matches. + */ + public Iterator getMatches() { + return matches.iterator(); + } + + /** + * Gets the number of matches in the line. + * @return the number of matches. + */ + public int getNumOfMatches() { + return matches.size(); + } + + /** + * Adds an entry. + * @param startOffset the offset from the beginning of the file where the match begins. + * @param endOffset the offset from the beginning of the file where the match ends. + */ + public void addEntry(int startOffset, int endOffset) { + matches.add(new SystemSearchMatch(startOffset, endOffset)); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchMatch.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchMatch.java new file mode 100644 index 00000000000..05e6e88637b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchMatch.java @@ -0,0 +1,61 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +/** + * This class holds information about a particular match. + */ +public class SystemSearchMatch { + + private int startOffset; + private int endOffset; + + /** + * Constructor for system search match. + * @param startOffset the offset from the beginning of the file where the match begins. + * @param endOffset the offset from the beginning of the file where the match ends. + */ + public SystemSearchMatch(int startOffset, int endOffset) { + this.startOffset = startOffset; + this.endOffset = endOffset; + } + + /** + * Gets offset from the beginning of the file where the match begins. + * @return the offset where the match begins. + */ + public int getStartOffset() { + return startOffset; + } + + /** + * Gets offset from the beginning of the file where the match ends. + * @return the offset where the match ends. + */ + public int getEndOffset() { + return endOffset; + } + + /** + * Gets the length of the match. Start offset subtracted from end offset plus 1. + * @return the length of the match. + */ + public int getLength() { + //TODO: check this + return (endOffset - startOffset + 1); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatchLocator.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatchLocator.java new file mode 100644 index 00000000000..95bf7be4e62 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatchLocator.java @@ -0,0 +1,190 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +/** + * This class locates matches. + */ +public class SystemSearchStringMatchLocator implements ISystemSearchConstants { + + private Reader reader; + private SystemSearchStringMatcher stringMatcher; + private int fPushbackChar; + private boolean fPushback; + + /** + * Constructor for creating a match locator. + * @param reader the reader from which to read and look for matches. + * @param stringMatcher the search string matcher. + */ + public SystemSearchStringMatchLocator(Reader reader, SystemSearchStringMatcher stringMatcher) { + this.reader = reader; + this.stringMatcher = stringMatcher; + } + + /** + * Gets the search string matcher. + * @return the string matcher. + */ + public SystemSearchStringMatcher getStringMatcher() { + return stringMatcher; + } + + /** + * Gets the reader. + * @return the reader. + */ + public Reader getReader() { + return reader; + } + + /** + * Locates matches. + * @return an array of matches, or an empty array if none exists. + * @throws IOException if an I/O error occurs. + */ + public SystemSearchLineMatch[] locateMatches() throws IOException { + + int lineCounter = 1; + int charCounter = 0; + boolean eof = false; + + List matches = new ArrayList(); + + try { + + while (!eof) { + + StringBuffer sb = new StringBuffer(200); + int eolStrLength = readLine(reader, sb); + + eof = (eolStrLength == -1); + + int lineLength = sb.length(); + + String line = sb.toString(); + +// boolean firstMatch = false; +// SystemSearchLineMatch match = null; + + // TODO: need to handle gettting correct positions for non-regex at least +// while (lineLength != 0 && matcher.contains(input, pattern)) { +// +// int beginOffset = charCounter + input.getBeginOffset(); +// int endOffset = charCounter + input.getEndOffset(); +// +// // if we get a match for the first time, create a new line match +// if (!firstMatch) { +// match = new SystemSearchLineMatch(line.trim(), lineCounter); +// firstMatch = true; +// } +// +// // now add the match to the line match so that we store all the matches in the line +// match.addEntry(beginOffset, endOffset); +// } + + // this just assumes one match per line, there may be more (if we use the non-regex matcher) + if (lineLength != 0) { + + if (stringMatcher.matches(line)) { + + int beginOffset = charCounter + 0; + int endOffset = charCounter + lineLength; + + SystemSearchLineMatch match = new SystemSearchLineMatch(line.trim(), lineCounter); + match.addEntry(beginOffset, endOffset); + matches.add(match); + } + } + + charCounter += lineLength + eolStrLength; + lineCounter++; + } + } + catch (IOException e) { + // TODO: log error + } + finally { + + if (reader != null) { + reader.close(); + } + } + + SystemSearchLineMatch[] matchArray = new SystemSearchLineMatch[matches.size()]; + + matches.toArray(matchArray); + + return matchArray; + } + + /** + * Reads a line of text from the given reader. + * @param reader the reader. + * @param sb the buffer. + * @return the result of reading the line. + * @throws IOException if an I/O error occurs. + */ + protected int readLine(Reader reader, StringBuffer sb) throws IOException { + int ch = -1; + + // if there is a character from a previous read that we needs to be added + if (fPushback) { + ch = fPushbackChar; + fPushback = false; + } + else { + ch = reader.read(); + } + + // keep reading until eof + while (ch >= 0) { + + // if we get a line feed character, then we have read a line (in Unix) + if (ch == LF_CHAR) { + return 1; + } + + // otherwise if we get a carriage return character, then we need to check the next character + if (ch == CR_CHAR) { + ch = reader.read(); + + // if the character is a line feed, then we have read a line (in Windows) + if (ch == LF_CHAR) { + return 2; + } + // otherwise, we assume we are still in the same line (i.e. a carriage return does not count as a line separator) + // we remember the character for the next read + else { + fPushbackChar = ch; + fPushback = true; + return 1; + } + } + + sb.append((char)ch); + ch = reader.read(); + } + + return -1; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatcher.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatcher.java new file mode 100644 index 00000000000..23ee01dbbf8 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchStringMatcher.java @@ -0,0 +1,110 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.util.regex.Pattern; + + +/** + * A string matcher for search. + */ +public class SystemSearchStringMatcher implements ISystemSearchMatcher { + + private String searchString; + private boolean isRegex; + + // for a regular expression + private Pattern regexPattern; + + // for non regular expression + private SystemNonRegexMatcher nonRegexMatcher; + + /** + * Constructor to create a string matcher. + * @param searchString the search string. + * @param isCaseSensitive true if the matching should be done in a case sensitive manner, false otherwise. + * @param isRegex true if the search string is a regular expression, false otherwise. + * @throws + */ + public SystemSearchStringMatcher(String searchString, boolean isCaseSensitive, boolean isRegex) { + + if (searchString == null) { + throw new NullPointerException(); + } + + this.searchString = searchString; + this.isRegex = isRegex; + + // if the string pattern is a regular expression + if (isRegex) { + + + try { + + if (isCaseSensitive) { + regexPattern = Pattern.compile(searchString); + } + else { + regexPattern = Pattern.compile(searchString, Pattern.CASE_INSENSITIVE); + } + } + catch (Exception e) { + // TODO: log it + } + } + else { + nonRegexMatcher = new SystemNonRegexMatcher(searchString, !isCaseSensitive, false); + } + } + + /** + * Returns whether the search string is empty. + * @return true if the search string is empty, false otherwise. + */ + public boolean isSearchStringEmpty() { + return searchString.length() == 0; + } + + /** + * Returns whether the search string is "*". + * @return true if the search string is "*", false otherwise. + */ + public boolean isSearchStringAsterisk() { + return searchString.equals("*"); + } + + /** + * Returns whether there is a match for the given input. Returns true if the search string + * is an empty string. + * @see org.eclipse.rse.services.clientserver.ISystemSearchMatcher#matches(java.lang.String) + */ + public boolean matches(String input) { + + if (isSearchStringEmpty()) { + return true; + } + + if (isRegex) { + return regexPattern.matcher(input).find(); + } + else { + // TODO (KM): can't use nonRegexMatcher.match(input) here because it returns + // false even when there is a match inside the input. Investigate what is wrong. + return nonRegexMatcher.find(input, 0, input.length()) != null; + } + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchUtil.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchUtil.java new file mode 100644 index 00000000000..3f676172cbd --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/search/SystemSearchUtil.java @@ -0,0 +1,195 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.search; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.regex.Pattern; + + +/** + * A utility class useful for search. It is a singleton. + */ +public class SystemSearchUtil { + + private static SystemSearchUtil instance; + + public static String FILE_NAMES_SEP_STRING = ","; + + /** + * Constructor for the utility class. + */ + private SystemSearchUtil() { + super(); + } + + /** + * Gets the singleton instance of the class. + * @return the singleton instance. + */ + public static SystemSearchUtil getInstance() { + + if (instance == null) { + instance = new SystemSearchUtil(); + } + + return instance; + } + + /** + * Check whether a regex string is valid. + * @param regexString the regex string. + * @return true if the regex string is valid, false otherwise. + */ + public boolean isValidRegex(String regexString) { + + + try { + Pattern.compile(regexString); + return true; + } + // if we get an exception, then pattern is not valid + catch (Exception e) { + return false; + } + } + + /** + * Returns the file names from the given file names string. + * @param fileNamesString the file names string. + * @return a set of file names, or an empty set if none. + * @throws NullPointerException if the file names string is null. + */ + public Set typesStringToSet(String fileNamesString) { + + if (fileNamesString == null) { + throw new NullPointerException(); + } + + if (fileNamesString.equals("")) { + return new HashSet(); + } + + Set result = new HashSet(); + + // create a string tokenizer which has ',' as its delimiter + StringTokenizer tokenizer = new StringTokenizer(fileNamesString, FILE_NAMES_SEP_STRING); + + // go through each token + while (tokenizer.hasMoreTokens()) { + + // get rid of whitespace + String currentExtension = tokenizer.nextToken().trim(); + result.add(currentExtension); + } + + return result; + } + + /** + * Returns the file names from the given file names string. + * @param fileNamesString the file names string. + * @return a list of file names, or an empty list if none. + * @throws NullPointerException if the file names string is null. + */ + public List typesStringToList(String fileNamesString) { + + if (fileNamesString == null) { + throw new NullPointerException(); + } + + if (fileNamesString.equals("")) { + return new ArrayList(); + } + + List result = new ArrayList(); + + // create a string tokenizer which has ',' as its delimiter + StringTokenizer tokenizer = new StringTokenizer(fileNamesString, FILE_NAMES_SEP_STRING); + + // go through each token + while (tokenizer.hasMoreTokens()) { + + // get rid of whitespace + String currentExtension = tokenizer.nextToken().trim(); + result.add(currentExtension); + } + + return result; + } + + /** + * Convert list of types to string. + * @param types the list of types. + * @return the string representing the list of types. + */ + public String typesListToString(List types) { + + // get the iterator for the list of types + Iterator iter = types.iterator(); + + return typesIterToString(iter); + } + + /** + * Convert set of types to string. + * @param types the set of types. + * @return the string representing the set of types. + */ + public String typesSetToString(Set types) { + + // get the iterator for the set of types + Iterator iter = types.iterator(); + + return typesIterToString(iter); + } + + /** + * Convert iterator of types to string. + * @param iter iterator for types. + * @return the string representing the set of types. + */ + public String typesIterToString(Iterator iter) { + StringBuffer result = new StringBuffer(); + + boolean first = true; + + // iterate over the types + while (iter.hasNext()) { + + // if it's not the first entry, then precede with ',' followed by space, i.e. ' ' + if (!first) { + result.append(FILE_NAMES_SEP_STRING); + result.append(" "); + } + // if first entry, don't do anything + else { + first = false; + } + + result.append(iter.next()); + } + + return result.toString(); + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/ITarConstants.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/ITarConstants.java new file mode 100644 index 00000000000..ff346c13dc5 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/ITarConstants.java @@ -0,0 +1,132 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.util.tar; + +/** + * This interface contains all constants needed for the tar package.s + */ +public interface ITarConstants { + + /** + * The block size, 512. + */ + public static final int BLOCK_SIZE = 512; + + /** + * The separator character in tar entry paths, '/'. + */ + public static final char SEPARATOR_CHAR = '/'; + + /** + * The length of the name field, 100. + */ + public static final int NAME_LENGTH = 100; + + /** + * The length of the mode field, 8. + */ + public static final int MODE_LENGTH = 8; + + /** + * The length of the uid field, 8. + */ + public static final int UID_LENGTH = 8; + + /** + * The length of the gid field, 8. + */ + public static final int GID_LENGTH = 8; + + /** + * The length of the size field, 12. + */ + public static final int SIZE_LENGTH = 12; + + /** + * The length of the mtime field, 12. + */ + public static final int MTIME_LENGTH = 12; + + /** + * The length of the chksum field, 8. + */ + public static final int CHKSUM_LENGTH = 8; + + /** + * The length of the typeflag field, 1. + */ + public static final int TYPEFLAG_LENGTH = 1; + + /** + * The length of the linkname field, 100. + */ + public static final int LINKNAME_LENGTH = 100; + + /** + * The length of the magic field, 6. + */ + public static final int MAGIC_LENGTH = 6; + + /** + * The length of the version field, 2. + */ + public static final int VERSION_LENGTH = 2; + + /** + * The length of the uname field, 32. + */ + public static final int UNAME_LENGTH = 32; + + /** + * The length of the gname field, 32. + */ + public static final int GNAME_LENGTH = 32; + + /** + * The length of the devmajor field, 8. + */ + public static final int DEVMAJOR_LENGTH = 8; + + /** + * The length of the devminor field, 8. + */ + public static final int DEVMINOR_LENGTH = 8; + + /** + * The length of the prefix field, 155. + */ + public static final int PREFIX_LENGTH = 155; + + /** + * The total length of the header. + */ + public static final int HEADER_LENGTH = NAME_LENGTH + MODE_LENGTH + UID_LENGTH + GID_LENGTH + SIZE_LENGTH + + MTIME_LENGTH + CHKSUM_LENGTH + TYPEFLAG_LENGTH + LINKNAME_LENGTH + + MAGIC_LENGTH + VERSION_LENGTH + UNAME_LENGTH + GNAME_LENGTH + + DEVMAJOR_LENGTH + DEVMINOR_LENGTH + PREFIX_LENGTH; + + // type flag constants + public static final char TF_OLDNORMAL = '\0'; + public static final char TF_NORMAL = '0'; + public static final char TF_LINK = '1'; + public static final char TF_SYMLINK = '2'; + public static final char TF_CHAR = '3'; + public static final char TF_BLOCK = '4'; + public static final char TF_DIR = '5'; + public static final char TF_FIFO = '6'; + public static final char TF_CONTIGUOUS = '7'; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarEntry.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarEntry.java new file mode 100644 index 00000000000..7b2800bd511 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarEntry.java @@ -0,0 +1,550 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.util.tar; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * This class represents a tar file entry. + */ +public class TarEntry implements ITarConstants, Cloneable { + + // NOTE: Read the GNU tar specification to understand what each of the fields mean. + // http://www.gnu.org/software/tar/manual/html_mono/tar.html#SEC118 + + // TODO (KM): Do we need to worry about ASCII? I think we do. We are constantly + // switching between bytes and String assuming local encoding. However, the tar specification states + // local ASCII variant must always be used. I think our code will probably fail on non-ASCII machines + // (e.g. Japanese, iSeries IFS, etc.). Need to test such a scenario to be sure though. + // Also, what does local variant of ASCII mean anyway? In a Japanese locale, what would be the + // local variant of ASCII? Can we just use US-ASCII everywhere and get away with it. I think + // that should work. Local variant of ASCII possibly means slightly different versions of ASCII used + // on different machines, but not between locales. + + // block header fields + public byte[] name = new byte[NAME_LENGTH]; + public byte[] mode = new byte[MODE_LENGTH]; + public byte[] uid = new byte[UID_LENGTH]; + public byte[] gid = new byte[GID_LENGTH]; + public byte[] size = new byte[SIZE_LENGTH]; + public byte[] mtime = new byte[MTIME_LENGTH]; + public byte[] chksum = new byte[CHKSUM_LENGTH]; + public byte typeflag; + public byte[] linkname = new byte[LINKNAME_LENGTH]; + public byte[] magic = new byte[MAGIC_LENGTH]; + public byte[] version = new byte[VERSION_LENGTH]; + public byte[] uname = new byte[UNAME_LENGTH]; + public byte[] gname = new byte[GNAME_LENGTH]; + public byte[] devmajor = new byte[DEVMAJOR_LENGTH]; + public byte[] devminor = new byte[DEVMINOR_LENGTH]; + public byte[] prefix = new byte[PREFIX_LENGTH]; + + /** + * Creates a new tar entry with the specified name. Use the setter methods to + * populate the other fields of the entry. + * @param name the name of the tar entry. + * @throws NullPointerException if the name is null. + * @throws IllegalArgumentException if the length of the name is greater that + */ + public TarEntry(String name) { + setName(name); + } + + /** + * Creates a new tar entry from the given block data. Fills in all the fields from the + * block data. + * @param blockData the block data. + * @throws NullPointerException if block data is null. + * @throws IllegalArgumentException if the block data is less than the length of a block. + * @throws IOException if an I/O error occurs. + */ + TarEntry(byte[] blockData) throws IOException { + checkNull(blockData); + + if (blockData.length != BLOCK_SIZE) { + throw new IllegalArgumentException(); + } + + populateFields(blockData); + } + + /** + * Fills in the fields of the entry from block data. + * @param blockData data in a header block. + * @throws IOException if an I/O error occurs. + */ + private void populateFields(byte[] blockData) throws IOException { + + InputStream byteStream = new ByteArrayInputStream(blockData); + + // read the name + byteStream.read(name); + + // if the name is an empty string, then don't fill in other fields, + // since this indicates that we have reached end of file + if (getName().equals("")) { + return; + } + + byteStream.read(mode); + byteStream.read(uid); + byteStream.read(gid); + byteStream.read(size); + byteStream.read(mtime); + byteStream.read(chksum); + typeflag = (byte)byteStream.read(); + byteStream.read(linkname); + byteStream.read(magic); + byteStream.read(version); + byteStream.read(uname); + byteStream.read(gname); + byteStream.read(devmajor); + byteStream.read(devminor); + byteStream.read(prefix); + } + + /** + * Checks whether the given object is null, and throws a NullPointerException if the + * obect is null. + * @param o an object + * @throws NullPointerException if the given object is null. + */ + private void checkNull(Object o) { + + if (o == null) { + throw new NullPointerException(); + } + } + + /** + * Sets the name of the tar entry. + * @param fileName the name for the tar entry. + * @throws NullPointerException if the name is null. + */ + public void setName(String fileName) { + checkNull(fileName); + + int length = NAME_LENGTH - fileName.length(); + + // append null characters to the name + for (int i = 0; i < length; i++) { + fileName = fileName + "\0"; + } + + name = fileName.getBytes(); + } + + /** + * Gets the name. + * @return the name. + */ + public String getName() { + return (new String(name)).trim(); + } + + /** + * Sets the user mod. + * @param canRead true if the user has read permission, false otherwise. + * @param canWrite true if the user has write permission, false otherwise. + * @param canExecute true if the user has execute permission, false otherwise. + */ + public void setUserMode(boolean canRead, boolean canWrite, boolean canExecute) { + + int mod = 00; + + if (canRead) { + mod += 04; + } + + if (canWrite) { + mod += 02; + } + + if (canExecute) { + mod += 01; + } + + String modString = "0100" + Integer.toString(mod, 8) + "44"; + modString = modString + "\0"; + + mode = modString.getBytes(); + } + + /** + * Gets the mode in octal. + * @return the mode. + */ + public String getMode() { + return (new String(mode)).trim(); + } + + /** + * Gets the uid in octal. + * @return the uid. + */ + public String getUID() { + return (new String(uid)).trim(); + } + + /** + * Gets the gid in octal. + * @return the gid. + */ + public String getGID() { + return (new String(gid)).trim(); + } + + /** + * Sets the file size in bytes. + * @param fileSize the file size. + */ + public void setSize(long fileSize) { + + // get the octal representation of the file size as a string + String sizeString = Long.toString(fileSize, 8).trim(); + + // get the length of the string + int length = sizeString.length(); + + int diff = SIZE_LENGTH - length - 1; + + // prepend the string with 0s + for (int i = 0; i < diff; i++) { + sizeString = "0" + sizeString; + } + + // append a space at the end + sizeString = sizeString + " "; + + size = sizeString.getBytes(); + } + + /** + * Gets the size in bytes. + * @return the size. + */ + public long getSize() { + return Long.parseLong((new String(size)).trim(), 8); + } + + /** + * Sets the modification time. + * @param modTime the modification time, in milliseconds since 00:00:00 GMT, January 1, 1970. + */ + public void setModificationTime(long modTime) { + + // get the octal representation of the modification time as a string + String mtimeString = Long.toString(modTime/1000, 8).trim(); + + // get the length of the string + int length = mtimeString.length(); + + int diff = MTIME_LENGTH - length - 1; + + // prepend the string with 0s + for (int i = 0; i < diff; i++) { + mtimeString = "0" + mtimeString; + } + + // append a space at the end + mtimeString = mtimeString + " "; + + mtime = mtimeString.getBytes(); + } + + /** + * Gets the modification time, in milliseconds since 00:00:00 GMT, January 1, 1970. + * @return the modification time. + */ + public long getModificationTime() { + return Long.parseLong((new String(mtime)).trim(), 8) * 1000; + } + + /** + * Gets the checksum. + * @return the checksum. + */ + public long getChecksum() { + return Long.parseLong((new String(chksum)).trim(), 8); + } + + /** + * Gets the type of file archived. + * @return the type flag. + */ + public char getTypeFlag() { + return (char)typeflag; + } + + /** + * Gets the link name. + * @return the link name. + */ + public String getLinkName() { + return (new String(linkname)).trim(); + } + + /** + * Returns whether the archive was output in the P1003 archive format. + * This is not used. + * @return the magic field. + */ + public String getMagic() { + return (new String(magic)).trim(); + } + + /** + * Gets the version in octal. + * @return the version. + */ + public String getVersion() { + return (new String(version)).trim(); + } + + /** + * Sets the user name of the tar entry. + * @param userName the user name for the tar entry. + * @throws NullPointerException if the user name is null. + */ + public void setUserName(String userName) { + checkNull(userName); + + int length = UNAME_LENGTH - userName.length(); + + // append null characters to the user name + for (int i = 0; i < length; i++) { + userName = userName + "\0"; + } + + uname = userName.getBytes(); + } + + /** + * Gets the user name. + * @return the user name. + */ + public String getUserName() { + return (new String(uname)).trim(); + } + + /** + * Gets the group name. + * @return the group name. + */ + public String getGroupName() { + return (new String(gname)).trim(); + } + + /** + * Gets the major device number in octal. + * @return the major device number. + */ + public String getDevMajor() { + return (new String(devmajor)).trim(); + } + + /** + * Gets the minor device number in octal. + * @return the minor device number. + */ + public String getDevMinor() { + return (new String(devminor)).trim(); + } + + /** + * Gets the prefix in octal. + * @return the prefix. + */ + public String getPrefix() { + return (new String(prefix)).trim(); + } + + /** + * Returns whether the entry represents a directory. + * @return true if the entry represents a directory, false otherwise. + */ + public boolean isDirectory() { + + String entryName = getName(); + + if (entryName.endsWith("/")) { + return true; + } + else { + return false; + } + } + + /** + * Write the fields to the given output stream. + * @param out the output stream to write to. + */ + public void writeFields(OutputStream outStream) throws IOException { + outStream.write(name); + outStream.write(mode); + outStream.write(uid); + outStream.write(gid); + outStream.write(size); + outStream.write(mtime); + outStream.write(chksum); + outStream.write(typeflag); + outStream.write(linkname); + outStream.write(magic); + outStream.write(version); + outStream.write(uname); + outStream.write(gname); + outStream.write(devmajor); + outStream.write(devminor); + outStream.write(prefix); + } + + /** + * Calculates the checksum of the entry. + */ + public void calculateChecksum() { + int sum = 0; + + // add name bytes + for (int i = 0; i < name.length; i++) { + sum += name[i]; + } + + // add mode bytes + for (int i = 0; i < mode.length; i++) { + sum += mode[i]; + } + + // add uid bytes + for (int i = 0; i < uid.length; i++) { + sum += uid[i]; + } + + // add gid bytes + for (int i = 0; i < gid.length; i++) { + sum += gid[i]; + } + + // add size bytes + for (int i = 0; i < size.length; i++) { + sum += size[i]; + } + + // add mtime bytes + for (int i = 0; i < mtime.length; i++) { + sum += mtime[i]; + } + + // add checksum bytes assuming check sum is blank spaces + char space = ' '; + byte spaceByte = (byte)space; + + for (int i = 0; i < chksum.length; i++) { + sum += spaceByte; + } + + // add typeflag byte + sum += typeflag; + + // add linkname bytes + for (int i = 0; i < linkname.length; i++) { + sum += linkname[i]; + } + + // add magic bytes + for (int i = 0; i < magic.length; i++) { + sum += magic[i]; + } + + // add version bytes + for (int i = 0; i < version.length; i++) { + sum += version[i]; + } + + // add uname bytes + for (int i = 0; i < uname.length; i++) { + sum += uname[i]; + } + + // add gname bytes + for (int i = 0; i < gname.length; i++) { + sum += gname[i]; + } + + // add devmajor bytes + for (int i = 0; i < devmajor.length; i++) { + sum += devmajor[i]; + } + + // add devminor bytes + for (int i = 0; i < devminor.length; i++) { + sum += devminor[i]; + } + + // add prefix bytes + for (int i = 0; i < prefix.length; i++) { + sum += prefix[i]; + } + + // get the octal representation of the sum as a string + String sumString = Long.toString(sum, 8).trim(); + + // get the length of the string + int length = sumString.length(); + + int diff = CHKSUM_LENGTH - length - 2; + + // prepend the string with 0s + for (int i = 0; i < diff; i++) { + sumString = "0" + sumString; + } + + // append a null character + sumString = sumString + "\0"; + + // append a space + sumString = sumString + " "; + + // set the checksum + chksum = sumString.getBytes(); + } + + /** + * @see java.lang.Object#clone() + */ + public Object clone() throws CloneNotSupportedException { + TarEntry newEntry = new TarEntry(getName()); + newEntry.mode = this.mode; + newEntry.uid = this.uid; + newEntry.gid = this.gid; + newEntry.size = this.size; + newEntry.mtime = this.mtime; + newEntry.chksum = this.chksum; + newEntry.typeflag = this.typeflag; + newEntry.linkname = this.linkname; + newEntry.magic = this.magic; + newEntry.version = this.version; + newEntry.uname = this.uname; + newEntry.gname = this.gname; + newEntry.devmajor = this.devmajor; + newEntry.devminor = this.devminor; + newEntry.prefix = this.prefix; + return newEntry; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarFile.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarFile.java new file mode 100644 index 00000000000..efc0e14bf7d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarFile.java @@ -0,0 +1,332 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.util.tar; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Vector; + +/** + * This class is used to read entries from a tar file. + */ +public class TarFile implements ITarConstants { + + private File file; + private Vector blockHeaders; + + private class TarEntryInputStream extends InputStream { + + private long size; + private InputStream stream; + private long numRead; + + /** + * Creates a tar entry input stream. + * @param size the size of the data in the tar entry. + * @param stream the underlying input stream. + */ + public TarEntryInputStream(long size, InputStream stream) { + this.size = size; + this.stream = stream; + numRead = 0; + } + + /** + * @see java.io.InputStream#read() + */ + public int read() throws IOException { + + if (numRead >= size) { + return -1; + } + else { + numRead += 1; + return stream.read(); + } + } + + /** + * @see java.io.InputStream#available() + */ + public int available() throws IOException { + + // get difference between file size and how much we have already read + long diff = size - numRead; + + // get how much we can read from underlying stream. + int av = stream.available(); + + // return the smaller of the two + // note although diff is a long, if it's smaller than av, we know it must fit + // in an integer. + return (int)Math.min(diff, av); + } + + + /** + * @see java.io.InputStream#close() + */ + public void close() throws IOException { + stream.close(); + } + + /** + * @see java.io.InputStream#mark(int) + */ + public synchronized void mark(int readLimit) { + stream.mark(readLimit); + } + + /** + * @see java.io.InputStream#markSupported() + */ + public boolean markSupported() { + return stream.markSupported(); + } + + /** + * @see java.io.InputStream#reset() + */ + public synchronized void reset() throws IOException { + stream.reset(); + } + } + + /** + * Opens a tar file for reading given the specified File object. + * @param file the tar file to be opened for reading. + * @throws FileNotFoundException if the file does not exist. + * @throws IOException if an I/O error occurs. + */ + public TarFile(File file) throws FileNotFoundException, IOException { + this.file = file; + loadTarEntries(); + } + + /** + * Opens a tar file for reading given the file name. + * @param name the name of the tar file to be opened for reading. + * @throws FileNotFoundException if the file with the given name does not exist. + * @throws IOException if an I/O error occurs. + */ + public TarFile(String name) throws FileNotFoundException, IOException { + this(new File(name)); + } + + /** + * Loads tar entries. + * @throws FileNotFoundException if the file does not exist. + * @throws IOException if an I/O error occurs. + */ + private void loadTarEntries() throws FileNotFoundException, IOException { + InputStream stream = getInputStream(); + blockHeaders = new Vector(); + + // now read all the block headers + byte[] blockData = readBlock(stream); + + // while end of stream is not reached, extract block headers + while (blockData.length != 0) { + + // extract the header from the block + TarEntry header = extractBlockHeader(blockData); + + // if header is not null, we add it to our list of headers + if (header != null) { + + // add header + blockHeaders.add(header); + + // determine how many blocks make up the contents of the file + long fileSize = header.getSize(); + int numFileBlocks = (int)(fileSize / BLOCK_SIZE); + numFileBlocks += (int)((fileSize % BLOCK_SIZE) > 0 ? 1 : 0); + + // if the file is a symbolic link, number of blocks will be 0 + if (header.getTypeFlag() == ITarConstants.TF_SYMLINK) { + numFileBlocks = 0; + } + + // skip the blocks that contain file content + stream.skip(numFileBlocks * BLOCK_SIZE); + } + + // now read the next block + blockData = readBlock(stream); + } + + stream.close(); + } + + /** + * Gets the input stream for the tar file. + * @return the input stream for the tar file. + * @throws FileNotFoundException if the file does not exist. + */ + private InputStream getInputStream() throws FileNotFoundException { + FileInputStream stream = new FileInputStream(file); + return stream; + } + + /** + * Reads the next block. + * @param stream the input stream of the tar file. + * @return the data in the next block, or an empty array if end of stream has been reached. + * @throws IOException if an I/O error occurs. + */ + private byte[] readBlock(InputStream stream) throws IOException { + byte[] blockData = new byte[BLOCK_SIZE]; + + // read a block of data + int byteRead = 0; + + for (int i = 0; i < BLOCK_SIZE; i++) { + byteRead = stream.read(); + + if (byteRead != -1) { + blockData[i] = (byte)byteRead; + } + else { + break; + } + } + + // if end of stream has been reached, return an empty array + if (byteRead == -1) { + return new byte[0]; + } + + return blockData; + } + + /** + * Extracts the header of a block given the block data. + * @param blockData the block data. + * @return the header of the block, or null if the block indicates end of file. + */ + private TarEntry extractBlockHeader(byte[] blockData) throws IOException { + + TarEntry entry = new TarEntry(blockData); + + // if the name of the entry is an empty string, it means we have reached end of file + // so just return null + if (entry.getName().equals("")) { + return null; + } + else { + return entry; + } + } + + /** + * Returns an enumeration of the tar file entries. + * @return an enumeration of the tar file entries. + */ + public Enumeration entries() { + return blockHeaders.elements(); + } + + /** + * Returns the number of entries in the tar file. + * @return the number of entries in the tar file. + */ + public int size() { + return blockHeaders.size(); + } + + /** + * Returns the tar file entry with that name, or null if not found. + * @param name the name of the entry. + * @return the tar file entry, or null if not found. + */ + public TarEntry getEntry(String name) { + + // TODO: could we maybe keep a hash instead to make it faster? + // The hash could be keyed by names. But tars do allow headers with the same name. + // Research this. + Enumeration headers = entries(); + + // go through all block headers + while (headers.hasMoreElements()) { + TarEntry entry = (TarEntry)(headers.nextElement()); + String entryName = entry.getName(); + + // if name of entry matches the given name, then that is the entry we are looking for + if (entryName.equals(name) || entryName.equals(name + "/")) { + return entry; + } + } + + return null; + } + + /** + * Returns the input stream of the data in the given entry. + * @param entry the entry. + * @return the input stream containing the data in that entry. + * @throws IOException if an I/O error occurs. + */ + public InputStream getInputStream(TarEntry entry) throws IOException { + InputStream stream = getInputStream(); + + // now read all the block headers + byte[] blockData = readBlock(stream); + + // while end of stream is not reached, extract block headers + while (blockData.length != 0) { + + // extract the header from the block + TarEntry header = extractBlockHeader(blockData); + + // if header is not null, we add it to our list of headers + if (header != null) { + + long fileSize = header.getSize(); + + // if the header name does not match the entry name + if (!header.getName().equals(entry.getName())) { + + // determine how many blocks make up the contents of the file + int numFileBlocks = (int)(fileSize / BLOCK_SIZE); + numFileBlocks += (int)((fileSize % BLOCK_SIZE) > 0 ? 1 : 0); + + // if the file is a symbolic link, number of blocks will be 0 + if (header.getTypeFlag() == ITarConstants.TF_SYMLINK) { + numFileBlocks = 0; + } + + // skip the blocks that contain file content + stream.skip(numFileBlocks * BLOCK_SIZE); + } + // the header name matches the entry name, so return the input stream with + // the data for that entry + else { + return new TarEntryInputStream(fileSize, stream); + } + } + + // now read the next block + blockData = readBlock(stream); + } + + return null; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarOutputStream.java b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarOutputStream.java new file mode 100644 index 00000000000..53d516d8c7b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/clientserver/org/eclipse/rse/services/clientserver/util/tar/TarOutputStream.java @@ -0,0 +1,131 @@ +/******************************************************************************** + * Copyright (c) 2003, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.clientserver.util.tar; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * This class implements an output stream filter for writing files in the + * tar file format. + */ +public class TarOutputStream extends OutputStream implements ITarConstants { + + private OutputStream out; + private boolean isClosed; + private boolean entryOpen; + private long dataCount; + + /** + * Creates a new tar output stream. + * @param out the actual output stream. + */ + public TarOutputStream(OutputStream out) { + this.out = out; + isClosed = false; + entryOpen = false; + } + + /** + * @see java.io.OutputStream#close() + */ + public void close() throws IOException { + + // if not already closed, then close the stream + // before closing though, write out a block of empty data + if (!isClosed) { + + byte[] dummy = new byte[BLOCK_SIZE]; + out.write(dummy); + + out.close(); + + isClosed = true; + } + } + + /** + * Ensure that the stream is open. + * @throws IOException if the stream is closed. + */ + private void ensureOpen() throws IOException { + + if (isClosed) { + throw new IOException("Stream closed"); + } + } + + /** + * @see java.io.OutputStream#write(int) + */ + public void write(int b) throws IOException { + ensureOpen(); + out.write(b); + dataCount += 1; + } + + /** + * Begins writing a new tar entry, and positions the stream to the start of the entry data. + * Closes the current entry if still active. + * @throws IOException if an I/O occurs. + */ + public void putNextEntry(TarEntry entry) throws IOException { + + // previous entry open, so close it + if (entryOpen) { + closeEntry(); + } + + // defer to the entry to write the entry fields + entry.writeFields(out); + + // get the part of a block we need to fill + int diff = BLOCK_SIZE - HEADER_LENGTH; + + // fill the block if we have used a part of it + if (diff != 0) { + byte[] dummy = new byte[diff]; + out.write(dummy); + } + + // set data count to 0 + dataCount = 0; + + // indicate that entry is open + entryOpen = true; + } + + /** + * Closes the current tar entry, and positions the stream for writing the next entry. + * @throws IOException if an I/O error occurs. + */ + public void closeEntry() throws IOException { + + // get the part of a block + int temp = (int)(dataCount % BLOCK_SIZE); + + // fill the rest of the block with dummy data if we have filled part of a block + if (temp != 0) { + int diff = BLOCK_SIZE - temp; + byte[] dummy = new byte[diff]; + out.write(dummy); + } + + // indicate that entry has been closed + entryOpen = false; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/plugin.properties b/rse/plugins/org.eclipse.rse.services/plugin.properties new file mode 100644 index 00000000000..a5a3f218261 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/plugin.properties @@ -0,0 +1,12 @@ +############################################################################### +# Copyright (c) 2000, 2006 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 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +plugin.name = RSE Services Framework diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/Activator.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/Activator.java new file mode 100644 index 00000000000..4207f484d95 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/Activator.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class to be used in the desktop. + */ +public class Activator extends AbstractUIPlugin { + + //The shared instance. + private static Activator plugin; + + /** + * The constructor. + */ + public Activator() { + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns an image descriptor for the image file at the given + * plug-in relative path. + * + * @param path the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin("com.ibm.rse.services.files", path); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/IService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/IService.java new file mode 100644 index 00000000000..342bfeea2c6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/IService.java @@ -0,0 +1,28 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; + +public interface IService +{ + public String getName(); + public String getDescription(); + public void initService(IProgressMonitor monitor); + public SystemMessage getMessage(String messageID); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/AbstractFileService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/AbstractFileService.java new file mode 100644 index 00000000000..3ed6b2acd5f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/AbstractFileService.java @@ -0,0 +1,99 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.files; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; + + +public abstract class AbstractFileService implements IFileService +{ + + public static final int FILE_TYPE_FILES_AND_FOLDERS = 0; + public static final int FILE_TYPE_FILES = 1; + public static final int FILE_TYPE_FOLDERS = 2; + + + + public IHostFile[] getFiles(IProgressMonitor monitor, String remoteParent, String fileFilter) + { + return internalFetch(monitor, remoteParent, fileFilter, FILE_TYPE_FILES); + } + + public IHostFile[] getFolders(IProgressMonitor monitor, String remoteParent, String fileFilter) + { + return internalFetch(monitor, remoteParent, fileFilter, FILE_TYPE_FOLDERS); + } + + public IHostFile[] getFilesAndFolders(IProgressMonitor monitor, String parentPath, String fileFilter) + { + return internalFetch(monitor, parentPath, fileFilter, FILE_TYPE_FILES_AND_FOLDERS); + } + + protected abstract IHostFile[] internalFetch(IProgressMonitor monitor, String parentPath, String fileFilter, int fileType); + + + protected boolean isRightType(int fileType, IHostFile node) + { + switch (fileType) + { + case FILE_TYPE_FILES_AND_FOLDERS: + return true; + case FILE_TYPE_FILES: + if (node.isFile()) + { + return true; + } + else + { + return false; + } + case FILE_TYPE_FOLDERS: + if (node.isDirectory()) + { + return true; + } + else + { + return false; + } + default: + return true; + } + } + + /** + * Dummy impl for now + */ + public SystemMessage getMessage(String messageID) + { + return null; + } + + public boolean deleteBatch(IProgressMonitor monitor, String[] remoteParents, String[] fileNames) throws SystemMessageException + { + boolean ok = true; + for (int i = 0; i < remoteParents.length; i++) + { + ok = ok && delete(monitor, remoteParents[i], fileNames[i]); + } + return ok; + } + + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IFileService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IFileService.java new file mode 100644 index 00000000000..2a449ed7b55 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IFileService.java @@ -0,0 +1,225 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.files; + +import java.io.File; +import java.io.InputStream; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.IService; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; + + +/** + * A IFileService is an abstraction of a file service that runs over some sort of connection. + * It can be shared among multiple instances of a subsystem. At some point this file + * service layer may become official API but for now it is experimental. Each + * subsystem is currently responsible for layering an abstraction over whatever it + * wants to construct as a service. + *

    + * This is a very bare bones definition. A real definition would probably have changed + * terminology, use URI's rather than Strings, and have much more robust error handling. + *

    + * Implementers of this interface will have to either be instantiated, initialized, or + * somehow derive a connection as part of its state. + */ +public interface IFileService extends IService +{ + + /** + * Copy a file to the remote file system. The remote target is denoted by a + * string representing the parent and a string representing the file. + * @param stream input stream to transfer + * @param remoteParent - a string designating the parent folder of the target for this file. + * @param remoteFile - a string designating the name of the file to be written on the remote system. + * @param isBinary - indicates whether the file is text or binary + * @param hostEncoding - the tgt encoding of the file (if text) + * @return true if the file was uploaded + */ + public boolean upload(IProgressMonitor monitor, InputStream stream, String remoteParent, String remoteFile, boolean isBinary, String hostEncoding) throws SystemMessageException; + + /** + * Copy a file to the remote file system. The remote target is denoted by a + * string representing the parent and a string representing the file. + * @param localFile - a real file in the local file system. + * @param remoteParent - a string designating the parent folder of the target for this file. + * @param remoteFile - a string designating the name of the file to be written on the remote system. + * @param isBinary - indicates whether the file is text or binary + * @param srcEncoding - the src encoding of the file (if text) + * @param hostEncoding - the tgt encoding of the file (if text) + * @return true if the file was uploaded + */ + public boolean upload(IProgressMonitor monitor, File localFile, String remoteParent, String remoteFile, boolean isBinary, String srcEncoding, String hostEncoding) throws SystemMessageException; + + /** + * Copy a file from the remote file system to the local system. + * @param remoteParent - a String designating the remote parent. + * @param remoteFile - a String designating the remote file residing in the parent. + * @param localFile - The file that is to be written. If the file exists it is + * overwritten. + * @param isBinary - indicates whether the file is text on binary + * @param hostEncoding - the encoding on the host (if text) + * @return true if the file was copied from the remote system. + * @throws SystemMessageException + */ + public boolean download(IProgressMonitor monitor, String remoteParent, String remoteFile, File localFile, boolean isBinary, String hostEncoding) throws SystemMessageException; + + /** + * Return the host file given the parent path and file name + * @param remoteParent + * @param name + * @return + */ + public IHostFile getFile(IProgressMonitor monitor, String remoteParent, String name) throws SystemMessageException; + + /** + * @param remoteParent - the name of the parent directory on the remote file + * system from which to retrieve the child list. + * @param fileFilter - a string that can be used to filter the children. Only + * those files matching the filter make it into the list. The interface + * does not dictate where the filtering occurs. + * @return the list of host files. + */ + public IHostFile[] getFilesAndFolders(IProgressMonitor monitor, String remoteParent, String fileFilter) throws SystemMessageException; + + /** + * @param remoteParent - the name of the parent directory on the remote file + * system from which to retrieve the child list. + * @param fileFilter - a string that can be used to filter the children. Only + * those files matching the filter make it into the list. The interface + * does not dictate where the filtering occurs. + * @return the list of host files. + */ + public IHostFile[] getFiles(IProgressMonitor monitor, String remoteParent, String fileFilter) throws SystemMessageException; + + /** + * @param remoteParent - the name of the parent directory on the remote file + * system from which to retrieve the child list. + * @param fileFilter - a string that can be used to filter the children. Only + * those files matching the filter make it into the list. The interface + * does not dictate where the filtering occurs. + * @return the list of host files. + */ + public IHostFile[] getFolders(IProgressMonitor monitor, String remoteParent, String fileFilter) throws SystemMessageException; + + /** + * Return the list of roots for this system + * @return the list of host files. + */ + public IHostFile[] getRoots(IProgressMonitor monitor) throws SystemMessageException; + + /** + * @return the String containing the name of the user's home directory on this + * connection that would be contained in implementations of this service. + */ + public IHostFile getUserHome(); + + /** + * Create a file on the host + * @param monitor the progress monitor + * @param remoteParent the parent directory + * @param fileName the name of the new file + * @return the newly created file + */ + public IHostFile createFile(IProgressMonitor monitor, String remoteParent, String fileName) throws SystemMessageException; + + /** + * Create a folder on the host + * @param monitor the progress monitor + * @param remoteParent the parent directory + * @param folderName the name of the new folder + * @return the newly created folder + */ + public IHostFile createFolder(IProgressMonitor monitor, String remoteParent, String folderName) throws SystemMessageException; + + /** + * Deletes a file or folder on the host + * @param monitor the progress monitor + * @param remoteParent the folder containing the file to delete + * @param fileName the name of the file or folder to delete + * @return true if successful + */ + public boolean delete(IProgressMonitor monitor, String remoteParent, String fileName) throws SystemMessageException; + + /** + * Deletes a set of files or folders on the host + * @param monitor the progress monitor + * @param remoteParents the array of folders containing the files to delete + * @param fileNames the names of the files or folders to delete + * @return true iff all deletes are successful + */ + public boolean deleteBatch(IProgressMonitor monitor, String[] remoteParents, String[] fileNames) throws SystemMessageException; + + /** + * Renames a file or folder on the host + * @param monitor the progress monitor + * @param remoteParent the folder containing the file to rename + * @param oldName the old name of the file or folder to rename + * @param newName the new name for the file + * @return true if successful + */ + public boolean rename(IProgressMonitor monitor, String remoteParent, String oldName, String newName) throws SystemMessageException; + + /** + * Renames a file or folder on the host + * @param monitor the progress monitor + * @param remoteParent the folder containing the file to rename + * @param oldName the old name of the file or folder to rename + * @param newName the new name for the file + * @param oldFile the file to update with the change + * @return true if successful + */ + public boolean rename(IProgressMonitor monitor, String remoteParent, String oldName, String newName, IHostFile oldFile) throws SystemMessageException; + + /** + * Move the file or folder specified + * @param monitor the progress monitor + * @param srcParent the folder containing the file or folder to move + * @param srcName the new of the file or folder to move + * @param tgtParent the destination folder for the move + * @param tgtName the name of the moved file or folder + * @return + */ + public boolean move(IProgressMonitor monitor, String srcParent, String srcName, String tgtParent, String tgtName) throws SystemMessageException; + + /** + * Copy the file or folder to the specified destination + * @param monitor the progress monitor + * @param srcParent the folder containing the file or folder to copy + * @param srcName the new of the file or folder to copy + * @param tgtParent the destination folder for the copy + * @param tgtName the name of the copied file or folder + * @return + */ + public boolean copy(IProgressMonitor monitor, String srcParent, String srcName, String tgtParent, String tgtName) throws SystemMessageException; + + /** + * Copy a set of files or folders to the specified destination + * @param monitor the progress monitor + * @param srcParents the folders containing each file or folder to copy + * @param srcNames the names of the files or folders to copy + * @param tgtParent the destination folder for the copy + * @return + */ + public boolean copyBatch(IProgressMonitor monitor, String[] srcParents, String[] srcNames, String tgtParent) throws SystemMessageException; + + /** + * Indicates whether the file system is case sensitive + * @return + */ + public boolean isCaseSensitive(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IHostFile.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IHostFile.java new file mode 100644 index 00000000000..a596ae3bd45 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/files/IHostFile.java @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.files; + +public interface IHostFile +{ + public String getName(); + public String getParentPath(); + public String getAbsolutePath(); + + public boolean isHidden(); + public boolean isDirectory(); + public boolean isRoot(); + public boolean isFile(); + public boolean exists(); + public boolean isArchive(); + + public long getSize(); + public long getModifiedDate(); + + public void renameTo(String newAbsolutePath); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractHostProcess.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractHostProcess.java new file mode 100644 index 00000000000..2b723d36525 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractHostProcess.java @@ -0,0 +1,291 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.processes; + +import org.eclipse.rse.services.clientserver.IServiceConstants; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteConstants; + +public class AbstractHostProcess implements IHostProcess, IServiceConstants, ISystemProcessRemoteConstants +{ + protected Object[] _properties = new Object[PROCESS_ATTRIBUTES_COUNT+1]; + + /** + * create a new AbstractHostProcess with the default property set + */ + public AbstractHostProcess() + { + _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME] = " "; + _properties[PROCESS_ATTRIBUTES_INDEX_GID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_PID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_PPID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_STATUS] = new String(" "); + _properties[PROCESS_ATTRIBUTES_INDEX_TGID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_UID] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME] = " "; + _properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_INDEX_VMRSS] = new Long(-1); + _properties[PROCESS_ATTRIBUTES_COUNT] = " "; //set the label + } + + /** + * create a new AbstractHostProcess with initial Attributes. + * This is equivalent to constructing the object, then calling setAllProperties(initialAttributes) + */ + public AbstractHostProcess(String initialAttributes) + { + setAllProperties(initialAttributes); + } + + protected Long getLongAttribute(String value, long dflt) + { + long result; + try + { + result = Long.parseLong(value); + } + catch (NumberFormatException e) + { + return new Long(dflt); + } + return new Long(result); + } + + protected Integer getIntAttribute(String value, int dflt) + { + int result; + try + { + result = Integer.parseInt(value); + } + catch (NumberFormatException e) + { + return new Integer(dflt); + } + return new Integer(result); + } + + public void setPid(String pid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_PID] = getLongAttribute(pid, -1); + } + + public void setPPid(String ppid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_PPID] = getLongAttribute(ppid, -1); + + } + + public void setName(String name) + { + _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME] = name; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.clientserver.processes.IHostProcess#getLabel() + */ + public String getLabel() + { + return (String) _properties[PROCESS_ATTRIBUTES_COUNT]; + } + + public void setLabel(String label) + { + _properties[PROCESS_ATTRIBUTES_COUNT] = label; + } + + public void setState(String state) + { + _properties[PROCESS_ATTRIBUTES_INDEX_STATUS] = state; + } + + public void setTgid(String tgid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_TGID] = getLongAttribute(tgid, -1); + } + + public void setTracerPid(String tracerpid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID] = getLongAttribute(tracerpid, -1); + } + + public void setUid(String uid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_UID] = getLongAttribute(uid, -1); + } + + public void setUsername(String username) + { + _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME] = username; + } + + public void setGid(String gid) + { + _properties[PROCESS_ATTRIBUTES_INDEX_GID] = getLongAttribute(gid, -1); + } + + public void setVmSizeInKB(String size) + { + _properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE] = getLongAttribute(size, 0); + } + + public void setVmRSSInKB(String size) + { + _properties[PROCESS_ATTRIBUTES_INDEX_VMRSS] = getLongAttribute(size, 0); + } + + /** + * You can also set all attributes at once with your own string passed as a parameter, as long + * as the string is in the same format as outlined below (pass in null to use the DataElement's string): + *

    The string contains properties of the object in the following order + *

      + *
    • Process Id (pid) - long + *
    • Executable name - String + *
    • Status - char + *
    • Tgid - long + *
    • Process Parent id (ppid) - long + *
    • Tracer pid - long + *
    • User id (uid) - long + *
    • Username - String + *
    • Group id (gid) - long + *
    • VM Size - long + *
    • VM RSS - long + *
    + */ + public void setAllProperties(String allProperties) + { + String s = allProperties; + + if (s != null && s.length() > 0) + { + String[] str = s.split("\\"+TOKEN_SEPARATOR); + int numOfExpectedTokens = PROCESS_ATTRIBUTES_COUNT; + int tokens = str.length; + if (tokens == numOfExpectedTokens) + { + try + { + setPid(str[PROCESS_ATTRIBUTES_INDEX_PID]); + + setName(str[PROCESS_ATTRIBUTES_INDEX_EXENAME]); + + setTgid(str[PROCESS_ATTRIBUTES_INDEX_TGID]); + + setPPid(str[PROCESS_ATTRIBUTES_INDEX_PPID]); + + setTracerPid(str[PROCESS_ATTRIBUTES_INDEX_TRACERPID]); + + setUid(str[PROCESS_ATTRIBUTES_INDEX_UID]); + + setUsername(str[PROCESS_ATTRIBUTES_INDEX_USERNAME]); + + setGid(str[PROCESS_ATTRIBUTES_INDEX_GID]); + + setVmSizeInKB(str[PROCESS_ATTRIBUTES_INDEX_VMSIZE]); + + setVmRSSInKB(str[PROCESS_ATTRIBUTES_INDEX_VMRSS]); + + setState(str[PROCESS_ATTRIBUTES_INDEX_STATUS]); + + setLabel(getName()); + + } + catch (ArrayIndexOutOfBoundsException e) + { + // SystemPlugin.logError("Error in AbstractHostProcess.getAttributes(). Attributes in unexpected format. Attributes = " + s); + } + } + } + } + + public long getPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_PID]).longValue(); + } + + public long getPPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_PPID]).longValue(); + } + + public String getName() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_EXENAME]; + } + + public String getState() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_STATUS]; + } + + public long getTgid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_TGID]).longValue(); + } + + public long getTracerPid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_TRACERPID]).longValue(); + } + + public long getUid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_UID]).intValue(); + } + + public String getUsername() + { + return (String) _properties[PROCESS_ATTRIBUTES_INDEX_USERNAME]; + } + + public long getGid() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_GID]).intValue(); + } + + public boolean isRoot() + { + return (getPPid() == 0); + } + + public long getVmSizeInKB() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_VMSIZE]).longValue(); + } + + public long getVmRSSInKB() + { + return ((Long)_properties[PROCESS_ATTRIBUTES_INDEX_VMRSS]).longValue(); + } + + /** + * Return all the properties of this data structure in one string. + * Properties are separated by IUniversalDataStoreConstants.TOKEN_SEPARATOR; + */ + public String getAllProperties() + { + String properties = ""; + for (int i = 0; i < PROCESS_ATTRIBUTES_COUNT; i++) + { + properties = properties + _properties[i].toString(); + if (i != PROCESS_ATTRIBUTES_COUNT - 1) + properties = properties + TOKEN_SEPARATOR; + } + return properties; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractProcessService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractProcessService.java new file mode 100644 index 00000000000..7ddbbbca6da --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/AbstractProcessService.java @@ -0,0 +1,90 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.processes; + +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.rse.services.clientserver.processes.HostProcessFilterImpl; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; + +public abstract class AbstractProcessService implements IProcessService +{ + public IHostProcess[] listAllProcesses(IProgressMonitor monitor, String exeNameFilter, String userNameFilter, String stateFilter) throws SystemMessageException + { + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setName(exeNameFilter); + rpfs.setUsername(userNameFilter); + rpfs.setSpecificState(stateFilter); + return listAllProcesses(monitor, rpfs); + } + + public IHostProcess[] listAllProcesses(IProgressMonitor monitor) throws SystemMessageException + { + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + return listAllProcesses(monitor, rpfs); + } + + /** + * At this point there is only one root process, the 'init' process with pid 1 + */ + public IHostProcess[] listRootProcesses(IProgressMonitor monitor) throws SystemMessageException + { + IHostProcess[] roots = new IHostProcess[1]; + roots[0] = getProcess(monitor, 1); + return roots; + } + + public IHostProcess[] listChildProcesses(IProgressMonitor monitor, long parentPID) throws SystemMessageException + { + String pPidString = "" + parentPID; + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setPpid(pPidString); + + return listAllProcesses(monitor, rpfs); + } + + public IHostProcess[] listChildProcesses(IProgressMonitor monitor, long parentPID, IHostProcessFilter filter) throws SystemMessageException + { + String pPidString = "" + parentPID; + filter.setPpid(pPidString); + + return listAllProcesses(monitor, filter); + } + + public IHostProcess getParentProcess(IProgressMonitor monitor, long PID) throws SystemMessageException + { + return getProcess(monitor, getProcess(monitor, PID).getPPid()); + } + + public IHostProcess getProcess(IProgressMonitor monitor, long PID) throws SystemMessageException + { + String pidString = "" + PID; + HostProcessFilterImpl rpfs = new HostProcessFilterImpl(); + rpfs.setPid(pidString); + + IHostProcess[] results = listAllProcesses(monitor, rpfs); + if (results == null) return null; + else return results[0]; + } + + public SystemMessage getMessage(String messageID) + { + return null; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/IProcessService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/IProcessService.java new file mode 100644 index 00000000000..4c48a8437b6 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/processes/IProcessService.java @@ -0,0 +1,108 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.processes; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.IService; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.clientserver.processes.IHostProcess; +import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter; + +/** + * An IProcessService is an abstraction of a process service that runs over some sort of connection. + * It can be shared among multiple instances of a subsystem. Each + * subsystem is currently responsible for layering an abstraction over whatever it + * wants to construct as a service. + *

    + * Implementers of this interface will have to either be instantiated, initialized, or + * somehow derive a connection as part of its state. + */ +public interface IProcessService extends IService +{ + /** + * Return a list of all processes on the remote system. + * @param monitor A progress monitor to which progress will be reported + */ + public IHostProcess[] listAllProcesses(IProgressMonitor monitor) throws SystemMessageException; + + /** + * Return a list of all processes on the remote system. + * @param monitor A progress monitor to which progress will be reported + * @param filter An object to filter results by + */ + public IHostProcess[] listAllProcesses(IProgressMonitor monitor, IHostProcessFilter filter) throws SystemMessageException; + + /** + * Return a list of all processes on the remote system. + * @param monitor A progress monitor to which progress will be reported + * @param exeNameFilter The executable name to filter results by, or null if no exeName filtering + * @param userNameFilter The user name to filter results by, or null if no userName filtering + * @param stateFilter The state code to filter results by, or null if no state filtering + */ + public IHostProcess[] listAllProcesses(IProgressMonitor monitor, String exeNameFilter, String userNameFilter, String stateFilter) throws SystemMessageException; + + /** + * Returns root processes on the remote system + * @param monitor A progress monitor to which progress will be reported + */ + public IHostProcess[] listRootProcesses(IProgressMonitor monitor) throws SystemMessageException; + + /** + * Return a list of all remote child processes of the given parent process on the remote system + * @param monitor A progress monitor to which progress will be reported + * @param parentPID The ID of the parent process whose children are to be listed + */ + public IHostProcess[] listChildProcesses(IProgressMonitor monitor, long parentPID) throws SystemMessageException; + + /** + * Return a list of all remote child processes of the given parent process on the remote system + * @param monitor A progress monitor to which progress will be reported + * @param parentPID The ID of the parent process whose children are to be listed + * @param filter A filter to narrow results by + */ + public IHostProcess[] listChildProcesses(IProgressMonitor monitor, long parentPID, IHostProcessFilter filter) throws SystemMessageException; + + /** + * Given a process, return its parent process object. + * @param monitor A progress monitor to which progress will be reported + * @param PID the ID of the process to return parent of. + */ + public IHostProcess getParentProcess(IProgressMonitor monitor, long PID) throws SystemMessageException; + + /** + * Given a pid, return an IHostProcess object for it. + * @param monitor A progress monitor to which progress will be reported + * @param PID The process ID of the desired process + */ + public IHostProcess getProcess(IProgressMonitor monitor, long PID) throws SystemMessageException; + + /** + * Kills a process. + * @param monitor A progress monitor to which progress will be reported + * @param PID the ID of the process to be killed. + * @param signal the signal to send to the process + * @return false if the given process doesn't exist, else true. Throws an exception if anything fails. + */ + public boolean kill(IProgressMonitor monitor, long PID, String signal) throws SystemMessageException; + + /** + * Returns a list of the types of signals that can be sent to + * a process on the remote system. + * @return the signal types, or null if there are none, or they cannot be found. + */ + public String[] getSignalTypes(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResult.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResult.java new file mode 100644 index 00000000000..862dd9c6f3b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResult.java @@ -0,0 +1,252 @@ +/******************************************************************************** + * Copyright (c) 2002, 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Platform; +import org.eclipse.rse.services.clientserver.SystemSearchString; +import org.eclipse.rse.services.files.IHostFile; + + +/** + * The RemoteSearchResultImpl class is an implementation of IRemoteSearchResult. + * It is used for storing information about a particular search result. + */ +public class AbstractSearchResult implements IAdaptable, IHostSearchResult +{ + + + private String _text; + private int _line = 0; + private int _index = -1; + + private Object _parent; + private SystemSearchString _matchingSearchString; + private IHostSearchResultConfiguration _configuration; + + private List _matches; + + protected class RemoteSearchResultMatch + { + + private int _startOffset = -1; + private int _endOffset = -1; + + private RemoteSearchResultMatch(int startOffset, int endOffset) { + this._startOffset = startOffset; + this._endOffset = endOffset; + } + } + + /** + * Constructor to create a result. + * @param parent container of the result. + * @param searchString the search string for which the result was produced. + */ + public AbstractSearchResult(IHostSearchResultConfiguration configuration, Object parent, SystemSearchString searchString) + { + _parent = parent; + _matchingSearchString = searchString; + _matches = new ArrayList(); + _configuration = configuration; + } + + + + /** + * Sets the displayable text for the search result. + * @param text the displayable text. + */ + public void setText(String text) { + _text = text; + } + + /** + * Sets the associated line number for the result. + * @param line the line number. + */ + public void setLine(int line) { + _line = line; + } + + /** + * Sets the index of the search result in the context of its parent. + * @param index the index. + */ + public void setIndex(int index) { + _index = index; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResult#getText() + */ + public String getText() { + return _text; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResult#getLine() + */ + public int getLine() { + return _line; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResult#getIndex() + */ + public int getIndex() { + return _index; + } + + /** + * Gets the absolute path of the file for which the result was found. + * @return the absolute path of the file. + */ + public String getAbsolutePath() { + + if (_parent instanceof IHostFile) { + return ((IHostFile)_parent).getAbsolutePath(); + } + else { + return null; + } + } + + /** + * Gets the containing object for the search result. + * @return the containing parent. + */ + public Object getParent() { + return _parent; + } + + public void setParent(Object parent) + { + _parent = parent; + } + + /** + * Gets the associated adapter for this search result. + * @param adapterType the adapter type. + */ + public Object getAdapter(Class adapterType) { + return Platform.getAdapterManager().getAdapter(this, adapterType); + } + + /** + * Returns children of the search result, if applicable. + * @return null for this implementation. + */ + public Object[] getChildren() { + return null; + } + + /** + * Indicates whether this search result has children + * @return false since there are no children. + */ + public boolean hasChildren() { + return false; + } + + /** + * Gets the displayable label for this output. Calls getText(). + * @return the label. + */ + public String getLabel() { + return getText(); + } + + /** + * Gets the search string that this result matches. + * @return the search string. + */ + public SystemSearchString getMatchingSearchString() { + return _matchingSearchString; + } + + /** + * Add a match to the result. A match comprises a char start offset and a char end offset, both + * relative to the beginning of the file. The matches are added in order. + * @param startOffset the char start offset, from the beginning of the file. + * @param endOffset the char end offset, from the beginning of the file. + */ + public void addMatch(int startOffset, int endOffset) { + _matches.add(new RemoteSearchResultMatch(startOffset, endOffset)); + } + + /** + * Gets the number of matches in this line. + * @return the number of matches. + */ + public int numOfMatches() { + return _matches.size(); + } + + /** + * Gets the char start offset for the given match index. + * @param matchIndex the match index. For example, to get the start offset for the first match, specify 0. + * @return the char start offset, or -1 if there is no match corresponding to the given index. + */ + public int getCharStart(int matchIndex) { + RemoteSearchResultMatch match = (RemoteSearchResultMatch)(_matches.get(matchIndex)); + + if (match != null) { + return match._startOffset; + } + else { + return -1; + } + } + + /** + * Gets the char end offset for the given match index. + * @param matchIndex the match index. For example, to get the end offset for the first match, specify 0. + * @return the char end offset, or -1 if there is no match corresponding to the given index. + */ + public int getCharEnd(int matchIndex) { + RemoteSearchResultMatch match = (RemoteSearchResultMatch)(_matches.get(matchIndex)); + + if (match != null) { + return match._endOffset; + } + else { + return -1; + } + } + + /** + * @return the char start offset of the first match. + */ + public int getCharEnd() { + return getCharEnd(0); + } + + /** + * @return the char end offset of the first match. + */ + public int getCharStart() { + return getCharStart(0); + } + + public IHostSearchResultConfiguration getConfiguration() + { + return _configuration; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResultConfiguration.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResultConfiguration.java new file mode 100644 index 00000000000..55e3774f084 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchResultConfiguration.java @@ -0,0 +1,223 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.rse.services.clientserver.SystemSearchString; + + +/** + * This class represents a search result configuration. A configuration + * consists of a search target and a search string, and belongs to a search + * result set. Once a search has been started via a subsystem, the results + * are stored in the configuration itself. The status of the search can also be queried from + * the configuration. + */ +public abstract class AbstractSearchResultConfiguration implements IHostSearchResultConfiguration +{ + + protected IHostSearchResultSet parentResultSet; + protected Object searchTarget; + protected SystemSearchString searchString; + protected Vector results; + protected Map _containedResults; + protected int status; + protected ISearchService _searchService; + protected ISearchHandler _searchHandler; + + + /** + * Constructor for a result set configuration. Sets status to RUNNING. + * @param resultSet the parent result set. + * @param searchObject the target of the search. + * @param searchString the search string. + */ + public AbstractSearchResultConfiguration(IHostSearchResultSet resultSet, Object searchObject, SystemSearchString string, ISearchService searchService) + { + results = new Vector(); + setParentResultSet(resultSet); + setSearchTarget(searchObject); + setSearchString(string); + setStatus(RUNNING); + _searchService = searchService; + _containedResults = new HashMap(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#setParentResultSet(org.eclipse.rse.services.search.IHostSearchResultSet) + */ + public void setParentResultSet(IHostSearchResultSet resultSet) + { + this.parentResultSet = resultSet; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getParentResultSet() + */ + public IHostSearchResultSet getParentResultSet() { + return parentResultSet; + } + + public ISearchService getSearchService() + { + return _searchService; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#setSearchTarget(java.lang.Object) + */ + public void setSearchTarget(Object searchObject) { + this.searchTarget = searchObject; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getSearchTarget() + */ + public Object getSearchTarget() { + return searchTarget; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#setSearchString(org.eclipse.rse.services.clientserver.SystemSearchString) + */ + public void setSearchString(SystemSearchString string) { + this.searchString = string; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getSearchString() + */ + public SystemSearchString getSearchString() + { + return searchString; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#addResult(java.lang.Object) + */ + public void addResult(Object result) + { + results.add(result); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#removeResult(java.lang.Object) + */ + public void removeResult(Object result) + { + results.remove(result); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#removeAndAddResult(java.lang.Object, java.lang.Object) + */ + public void removeAndAddResult(Object oldResult, Object newResult) + { + results.remove(oldResult); + results.add(newResult); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getResults() + */ + public Object[] getResults() + { + return results.toArray(); + } + + public IHostSearchResult[] getContainedResults(Object resultContainer) + { + return (IHostSearchResult[])_containedResults.get(resultContainer); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getResultsSize() + */ + public int getResultsSize() + { + return results.size(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#removeResults() + */ + public void removeResults() + { + results.removeAllElements(); + _containedResults.clear(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#setStatus(int) + */ + public void setStatus(int status) { + this.status = status; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#getStatus() + */ + public int getStatus() { + return status; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#cancel() + */ + public void cancel() { + + // if not running, return + if (getStatus() != RUNNING) { + return; + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultConfiguration#dispose() + */ + public void dispose() { + + // cancel search first + cancel(); + + // remove results + removeResults(); + } + + public void addResults(Object container, IHostSearchResult[] results) + { + _containedResults.put(container, results); + } + + public void setSearchHandler(ISearchHandler searchHandler) + { + _searchHandler = searchHandler; + } + + + /** + * Gets the search handler. + * @return the search handler. + */ + public ISearchHandler getSearchHandler() + { + return _searchHandler; + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchService.java new file mode 100644 index 00000000000..32d81dd9b62 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/AbstractSearchService.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.files.IFileService; + + + +public abstract class AbstractSearchService implements ISearchService +{ + protected Map _searches; + + public AbstractSearchService() + { + _searches = new HashMap(); + } + + public final void search(IProgressMonitor monitor, IHostSearchResultConfiguration searchConfig, IFileService fileService) + { + ISearchHandler handler = internalSearch(monitor, searchConfig, fileService); + _searches.put(searchConfig, handler); + } + + + public final void cancelSearch(IProgressMonitor monitor, IHostSearchResultConfiguration searchConfig) + { + ISearchHandler handler = (ISearchHandler)_searches.get(searchConfig); + handler.cancel(monitor); + } + + + protected abstract ISearchHandler internalSearch(IProgressMonitor monitor, IHostSearchResultConfiguration searchConfig, IFileService fileService); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/HostSearchResultSet.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/HostSearchResultSet.java new file mode 100644 index 00000000000..b647081bba4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/HostSearchResultSet.java @@ -0,0 +1,292 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Platform; + + +/** + * A remote search result set represents a page in the Remote Search view. + * A search result set contains multiple search configurations and their results. + * This allows it to contain results from multiple connections, filters, and folders + * (from different systems). + */ +public class HostSearchResultSet implements IHostSearchResultSet, IAdaptable +{ + + protected Vector configurations; + protected String name; + + /** + * Constructor to create a result set. + */ + public HostSearchResultSet() { + configurations = new Vector(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#setName(java.lang.String) + */ + public void setName(String name) { + this.name = name; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#getName() + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#addSearchConfiguration(org.eclipse.rse.services.search.IHostSearchResultConfiguration) + */ + public void addSearchConfiguration(IHostSearchResultConfiguration config) { + configurations.add(config); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#removeSearchConfiguration(org.eclipse.rse.services.search.IHostSearchResultConfiguration) + */ + public void removeSearchConfiguration(IHostSearchResultConfiguration config) { + configurations.remove(config); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#getSearchConfigurations() + */ + public Iterator getSearchConfigurations() { + return configurations.iterator(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#addResult(org.eclipse.rse.services.search.IHostSearchResultConfiguration, java.lang.Object) + */ + public void addResult(IHostSearchResultConfiguration config, Object result) { + config.addResult(result); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#removeResult(org.eclipse.rse.services.search.IHostSearchResultConfiguration, java.lang.Object) + */ + public void removeResult(IHostSearchResultConfiguration config, Object result) { + config.removeResult(result); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#getResultsForConfiguration(org.eclipse.rse.services.search.IHostSearchResultConfiguration) + */ + public Object[] getResultsForConfiguration(IHostSearchResultConfiguration config) { + return config.getResults(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#getAllResults() + */ + public Object[] getAllResults() { + + List list = new ArrayList(); + + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) + { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + list.addAll(Arrays.asList(config.getResults())); + } + + return list.toArray(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#removeAllResults() + */ + public void removeAllResults() { + + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + config.removeResults(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#getNumOfResults() + */ + public int getNumOfResults() { + + int resultSize = 0; + + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + resultSize += config.getResultsSize(); + } + + return resultSize; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#cancel() + */ + public void cancel() { + + // cancel each config that is running + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + if (config.getStatus() == IHostSearchConstants.RUNNING) { + config.cancel(); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#removeResult(java.lang.Object) + */ + public void removeResult(Object result) { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + config.removeResult(result); + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#removeAndAddResult(java.lang.Object, java.lang.Object) + */ + public void removeAndAddResult(Object oldResult, Object newResult) { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + config.removeAndAddResult(oldResult, newResult); + } + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#dispose() + */ + public void dispose() { + + // first cancel all configs that are still running + cancel(); + + // now dispose each configuration + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + config.dispose(); + } + + // remove all the configurations + configurations.removeAllElements(); + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#isCancelled() + */ + public boolean isCancelled() { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + // if a config is not cancelled, the search is not cancelled + if (config.getStatus() != IHostSearchConstants.CANCELLED) { + return false; + } + } + + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#isFinished() + */ + public boolean isFinished() { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + // if a config is not finished, the search is not finished + if (config.getStatus() != IHostSearchConstants.FINISHED) { + return false; + } + } + + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#isRunning() + */ + public boolean isRunning() { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + // if a config is running, the search is running + if (config.getStatus() == IHostSearchConstants.RUNNING) { + return true; + } + } + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.services.search.IHostSearchResultSet#isDisconnected() + */ + public boolean isDisconnected() { + Iterator iter = getSearchConfigurations(); + + while (iter.hasNext()) { + IHostSearchResultConfiguration config = (IHostSearchResultConfiguration)iter.next(); + + // if a config is not disconnected, the search is not disconnected + if (config.getStatus() != IHostSearchConstants.DISCONNECTED) { + return false; + } + } + + return true; + } + + /** + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + return Platform.getAdapterManager().getAdapter(this, adapter); + } +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchConstants.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchConstants.java new file mode 100644 index 00000000000..99e75249512 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchConstants.java @@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +public interface IHostSearchConstants { + + /** + * Status indicating configuration is still running, 0. + */ + public static final int RUNNING = 0; + + /** + * Status indicating configuration has finished, 1. + */ + public static final int FINISHED = 1; + + /** + * Status indicating configuration has been cancelled, 2. + */ + public static final int CANCELLED = 2; + + /** + * Status indicating configuration has been disconnected, 3. + */ + public static final int DISCONNECTED = 3; +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResult.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResult.java new file mode 100644 index 00000000000..f75a48c112d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResult.java @@ -0,0 +1,94 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import org.eclipse.rse.services.clientserver.SystemSearchString; + + +public interface IHostSearchResult +{ + public static final String SEARCH_RESULT_DELIMITER = ":SEARCH"; + public static final String SEARCH_RESULT_OPEN_DELIMITER = "<"; + public static final String SEARCH_RESULT_CLOSE_DELIMITER = ">"; + public static final String SEARCH_RESULT_INDEX_DELIMITER = ":"; + + public void setParent(Object parent); + + public Object getParent(); + + + public int getLine(); + + /** + * Gets the search string that this result matches. + * @return the search string. + */ + public SystemSearchString getMatchingSearchString(); + + /** + * Gets the path to the file that this output references if it references any. It may return null if + * no such association exists. This may be used to jump to an editor from a view which displays + * this + * + * @return the path of the referenced file if there is one + */ + public String getAbsolutePath(); + + /** + * Gets the text to display for a search result. + * @return the text. + */ + public String getText(); + + /** + * Gets the index of this search result in the context of its parent. + * @return the index. + */ + public int getIndex(); + + + /** + * Add a match to the result. A match comprises a char start offset and a char end offset, both + * relative to the beginning of the file. The matches are added in order. + * @param startOffset the char start offset, from the beginning of the file. + * @param endOffset the char end offset, from the beginning of the file. + */ + public void addMatch(int startOffset, int endOffset); + + /** + * Gets the number of matches in this line. + * @return the number of matches. + */ + public int numOfMatches(); + + /** + * Gets the char start offset for the given match index. + * @param matchIndex the match index. For example, to get the start offset for the first match, specify 0. + * @return the char start offset. + */ + public int getCharStart(int matchIndex); + + /** + * Gets the char end offset for the given match index. + * @param matchIndex the match index. For example, to get the end offset for the first match, specify 0. + * @return the char end offset. + */ + public int getCharEnd(int matchIndex); + + + public IHostSearchResultConfiguration getConfiguration(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfiguration.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfiguration.java new file mode 100644 index 00000000000..5bf8e016a8a --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfiguration.java @@ -0,0 +1,141 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import org.eclipse.rse.services.clientserver.SystemSearchString; + +/** + * An interface representing a search result configuration. + */ +public interface IHostSearchResultConfiguration extends IHostSearchConstants { + + /** + * Sets the parent result set. + * @param resultSet the parent result set. + */ + public void setParentResultSet(IHostSearchResultSet resultSet); + + /** + * Gets the parent result set. + * @return the parent result set. + */ + public IHostSearchResultSet getParentResultSet(); + + /** + * Gets the results contained within the resultContainer + * @param resultContainer + * @return + */ + public IHostSearchResult[] getContainedResults(Object resultContainer); + + /** + * Sets the object to be searched. + * @param searchObject the object to be searched. + */ + public void setSearchTarget(Object searchObject); + + /** + * Gets the object to be searched. + * @return the object to be searched. + */ + public Object getSearchTarget(); + + /** + * Sets the search string. + * @param string the search string. + */ + public void setSearchString(SystemSearchString string); + + /** + * Gets the search string. + * @return string the search string. + */ + public SystemSearchString getSearchString(); + + /** + * Adds a search result. + * @param result a search result. + */ + public void addResult(Object result); + + /** + * Adds a set of search results along their associated container + * @param container + * @param results + */ + public void addResults(Object container, IHostSearchResult[] results); + + /** + * Removes a search result. + * @param result a search result. + */ + public void removeResult(Object result); + + /** + * Removes the old result and adds a new result. + * @param oldResult the old result. + * @param newResult the new result. + */ + public void removeAndAddResult(Object oldResult, Object newResult); + + /** + * Gets search results. + * @return search results. + */ + public Object[] getResults(); + + /** + * Gets the size of the results. + * @return the size of the results. + */ + public int getResultsSize(); + + /** + * Removes all search results. + */ + public void removeResults(); + + /** + * Sets the status of the search. One of RUNNING, FINISHED, + * CANCELLED, or DISCONNECTED. + * @param the status. + */ + public void setStatus(int status); + + /** + * Gets the status of the search. One of RUNNING, FINISHED, + * CANCELLED, or DISCONNECTED. + * @return the status of the search. + */ + public int getStatus(); + + /** + * Cancels the search if it is running. + */ + public void cancel(); + + /** + * Cancels the search and then removes the search results. Implementors should call super first. + */ + public void dispose(); + + /** + * Sets the search handler + * @param handler + */ + public void setSearchHandler(ISearchHandler handler); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfigurationFactory.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfigurationFactory.java new file mode 100644 index 00000000000..baf0d9d822b --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultConfigurationFactory.java @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import org.eclipse.rse.services.clientserver.SystemSearchString; + +public interface IHostSearchResultConfigurationFactory +{ + public IHostSearchResultConfiguration createSearchConfiguration(IHostSearchResultSet resultSet, Object searchTarget, SystemSearchString searchString); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultSet.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultSet.java new file mode 100644 index 00000000000..dad13692fc7 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/IHostSearchResultSet.java @@ -0,0 +1,147 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import java.util.Iterator; + +/** + * A remote search result set represents a page in the Remote Search view. + * A search result set contains multiple search configurations and their results. + * This allows it to contain results from multiple connections, filters, and folders + * (from different systems). + */ +public interface IHostSearchResultSet { + + /** + * Sets the name of the search. + * @param name the name of the search. + */ + public void setName(String name); + + /** + * Gets the name of the search that is being run. + * @return the name of the search. + */ + public String getName(); + + /** + * Add a search configuration. + * @param config a search configuration. + */ + public void addSearchConfiguration(IHostSearchResultConfiguration config); + + /** + * Removes a search configuration. + * @param config a search configuration. + */ + public void removeSearchConfiguration(IHostSearchResultConfiguration config); + + /** + * Returns an iterator over search configurations. + * @return an iterator over search configurations. + */ + public Iterator getSearchConfigurations(); + + /** + * Add a result for a search configuration. + * @param config a search configuration that was previously added. + * @param result a search result. + */ + public void addResult(IHostSearchResultConfiguration config, Object result); + + /** + * Removes a result from a search configuration. + * @param config a search configuration that was previously added. + * @param result a search result. + */ + public void removeResult(IHostSearchResultConfiguration config, Object result); + + /** + * Removes a result from all search configurations where it exists. + * @param result a search result. + */ + public void removeResult(Object result); + + /** + * Removes the old result from configurations where it is found, and + * add the new result to those configurations. + * @param oldResult the old result. + * @param newResult the new result. + */ + public void removeAndAddResult(Object oldResult, Object newResult); + + /** + * Returns the results of a particular search configuration. + * @param config a search configuration. + * @return the results for the given search configuration. + */ + public Object[] getResultsForConfiguration(IHostSearchResultConfiguration config); + + /** + * Returns all results of the search. + * @return all results of the search. + */ + public Object[] getAllResults(); + + /** + * Removes all results of the search. + */ + public void removeAllResults(); + + /** + * Gets the number of results. + * @return the number of results. + */ + public int getNumOfResults(); + + /** + * Cancels the search. Cancel those configurations that are still running. + */ + public void cancel(); + + /** + * Removes all configurations. First cancels the search, then calls the dispose method of + * the configurations before removing them. + */ + public void dispose(); + + /** + * Returns whether search is running. A search is running if any of the configurations is running. + * @return true if the search is running, false otherwise. + */ + public boolean isRunning(); + + /** + * Returns whether the search is cancelled. A search is cancelled if all of the configurations are + * cancelled. + * @return true if the search is cancelled, false otherwise. + */ + public boolean isCancelled(); + + /** + * Returns whether the search is finished. A search is finished if all the configurations are finished. + * @return true if the search is finished, false otherwise. + */ + public boolean isFinished(); + + /** + * Returns whether the search is disconnected. A search is disconnected if all the configurations are + * disconnected. + * @return true if the search is disconnected, false otherwise. + */ + public boolean isDisconnected(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchHandler.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchHandler.java new file mode 100644 index 00000000000..1fc97b5aefd --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchHandler.java @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import org.eclipse.core.runtime.IProgressMonitor; + +public interface ISearchHandler +{ + public void search(IProgressMonitor monitor); + public void cancel(IProgressMonitor monitor); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchService.java new file mode 100644 index 00000000000..401fcef2665 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/search/ISearchService.java @@ -0,0 +1,27 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.search; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.files.IFileService; + +public interface ISearchService +{ + public void search(IProgressMonitor monitor, IHostSearchResultConfiguration searchConfig, IFileService fileService); + public void cancelSearch(IProgressMonitor monitor, IHostSearchResultConfiguration searchConfig); + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShell.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShell.java new file mode 100644 index 00000000000..0ac8e3f750d --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShell.java @@ -0,0 +1,37 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + + +public abstract class AbstractHostShell implements IHostShell +{ + + public void addOutputListener(IHostShellOutputListener listener) + { + IHostShellOutputReader outReader = getStandardOutputReader(); + if (outReader != null) + { + outReader.addOutputListener(listener); + } + IHostShellOutputReader errReader = getStandardErrorReader(); + if (errReader != null) + { + errReader.addOutputListener(listener); + } + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShellOutputReader.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShellOutputReader.java new file mode 100644 index 00000000000..b00aba64db9 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/AbstractHostShellOutputReader.java @@ -0,0 +1,194 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractHostShellOutputReader extends Thread implements IHostShellOutputReader +{ + protected List _listeners; + protected int _waitIncrement = 2; + protected boolean _keepRunning = true; + + protected List _linesOfOutput; + protected int _consumerOffset; + protected IHostShell _hostShell; + protected boolean _isErrorReader = false; + + + protected long _timeOfLastEvent = 0; + protected int _sizeAtLastEvent = 0; + + public AbstractHostShellOutputReader(IHostShell hostShell, boolean isErrorReader) + { + _hostShell = hostShell; + _listeners = new ArrayList(); + _linesOfOutput = new ArrayList(); + _consumerOffset = 0; + _isErrorReader = isErrorReader; + _timeOfLastEvent = System.currentTimeMillis(); + } + + public boolean isErrorReader() + { + return _isErrorReader; + } + + public IHostShell getHostShell() + { + return _hostShell; + } + + public void setWaitTime(int value) + { + _waitIncrement = value; + } + + public int getWaitTime() + { + return _waitIncrement; + } + + + public void handle() + { + Object line = internalReadLine(); + + if (line != null) + { + if (line instanceof String) + { + //if (lineStr.length() > 0) + addLine(line); + } + else + { + addLine(line); + } + } + + else + { + finish(); + } + + } + + protected void addLine(Object line) + { + _linesOfOutput.add(line); + int sizenow = _linesOfOutput.size(); + int deltaSize = sizenow - _sizeAtLastEvent; + + long timenow = System.currentTimeMillis(); + //if ((timenow - _timeOfLastEvent) > 10 || deltaSize > 2) + { + + + // notify listeners + HostShellChangeEvent event = new HostShellChangeEvent(_hostShell, this, _sizeAtLastEvent, deltaSize); + fireOutputChanged(event); + _timeOfLastEvent = timenow; + _sizeAtLastEvent = sizenow; + } + } + + public Object readLine() + { + if (!isAlive()) + { + internalReadLine(); + start(); + } + return _linesOfOutput.get(_consumerOffset++); + } + + public Object readLine(int lineNumber) + { + return _linesOfOutput.get(lineNumber); + } + + + + public void setLineOffset(int lineNumber) + { + _consumerOffset = lineNumber; + } + public void addOutputListener(IHostShellOutputListener listener) + { + _listeners.add(listener); + if (!isAlive()) + { + start(); + } + } + + + public void fireOutputChanged(IHostShellChangeEvent event) + { + for (int i = 0; i < _listeners.size(); i++) + { + IHostShellOutputListener listener = (IHostShellOutputListener)_listeners.get(i); + listener.shellOutputChanged(event); + } + } + + public void dispose() + { + _listeners.clear(); + } + + public boolean isFinished() + { + return !_keepRunning; + } + + public void finish() + { + if (_keepRunning) + { + + _waitIncrement = 0; + _keepRunning = false; + dispose(); + } + } + + public void run() + { + while (_keepRunning) + { + try + { + Thread.sleep(_waitIncrement); + Thread.yield(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + finish(); + return; + } + + handle(); + } + } + + protected abstract Object internalReadLine(); + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/HostShellChangeEvent.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/HostShellChangeEvent.java new file mode 100644 index 00000000000..50b45036b5c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/HostShellChangeEvent.java @@ -0,0 +1,67 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +public class HostShellChangeEvent implements IHostShellChangeEvent +{ + protected IHostShell _hostShell; + protected IHostShellOutputReader _reader; + protected int _offset; + protected int _range; + + public HostShellChangeEvent(IHostShell shell, IHostShellOutputReader reader, int offset, int range) + { + _hostShell = shell; + _reader = reader; + _offset = offset; + _range = range; + } + + public IHostShell getHostShell() + { + return _hostShell; + } + + public IHostShellOutputReader getReader() + { + return _reader; + } + + public Object[] getLines() + { + Object[] lines = new Object[_range]; + int r = 0; + int size = _offset + _range ; + for (int i= _offset; i < size; i++) + { + lines[r] = _reader.readLine(i); + r++; + } + return lines; + } + + public Object[] getLineObjects() + { + return getLines(); + } + + public boolean isError() + { + return _reader.isErrorReader(); + } + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShell.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShell.java new file mode 100644 index 00000000000..8139cfcb51c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShell.java @@ -0,0 +1,32 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + + +public interface IHostShell +{ + public boolean isActive(); + public void writeToShell(String command); + + public void addOutputListener(IHostShellOutputListener listener); + + public IHostShellOutputReader getStandardOutputReader(); + public IHostShellOutputReader getStandardErrorReader(); + + public void exit(); + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellChangeEvent.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellChangeEvent.java new file mode 100644 index 00000000000..156dbf56d70 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellChangeEvent.java @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +public interface IHostShellChangeEvent +{ + public IHostShell getHostShell(); + public IHostShellOutputReader getReader(); + public Object[] getLines(); + public boolean isError(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputListener.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputListener.java new file mode 100644 index 00000000000..2eba910ab90 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputListener.java @@ -0,0 +1,22 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +public interface IHostShellOutputListener +{ + public void shellOutputChanged(IHostShellChangeEvent event); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputNotifier.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputNotifier.java new file mode 100644 index 00000000000..da7273e4493 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputNotifier.java @@ -0,0 +1,23 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +public interface IHostShellOutputNotifier +{ + public void fireOutputChanged(IHostShellChangeEvent event); + +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputReader.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputReader.java new file mode 100644 index 00000000000..29cd9ddb0bf --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IHostShellOutputReader.java @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +public interface IHostShellOutputReader extends IHostShellOutputNotifier +{ + public Object readLine(); + public Object readLine(int index); + public void addOutputListener(IHostShellOutputListener listener); + public boolean isErrorReader(); +} \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IShellService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IShellService.java new file mode 100644 index 00000000000..910720b2d40 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/services/shells/IShellService.java @@ -0,0 +1,70 @@ +/******************************************************************************** + * Copyright (c) 2006 IBM Corporation. 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: + * {Name} (company) - description of contribution. + ********************************************************************************/ + +package org.eclipse.rse.services.shells; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.IService; + +/** + * IShellService is an abstraction for running shells and + * shell commands + * + */ +public interface IShellService extends IService +{ + /** + * Launch a new shell in the specified directory + * @param monitor + * @param initialWorkingDirectory + * @return + */ + public IHostShell launchShell(IProgressMonitor monitor, String initialWorkingDirectory, String[] environment); + + /** + * Launch a new shell in the specified directory + * @param monitor + * @param initialWorkingDirectory + * @param encoding + * @return + */ + public IHostShell launchShell(IProgressMonitor monitor, String initialWorkingDirectory, String encoding, String[] environment); + + /** + * Run a command in it's own shell + * @param monitor + * @param initialWorkingDirectory + * @param command + * @return + */ + public IHostShell runCommand(IProgressMonitor monitor, String initialWorkingDirectory, String command, String[] environment); + + /** + * Run a command in it's own shell + * @param monitor + * @param initialWorkingDirectory + * @param command + * @param encoding + * @return + */ + public IHostShell runCommand(IProgressMonitor monitor, String initialWorkingDirectory, String command, String encoding, String[] environment); + + /** + * Return an array of environment variables that describe the environment on the host + * @return + */ + public String[] getHostEnvironment(); +} \ No newline at end of file