From 9db0e7c00addf33f380345ad30bdfb1376d60d9b Mon Sep 17 00:00:00 2001 From: Martin Oberhuber < martin.oberhuber@windriver.com> Date: Sat, 12 Apr 2008 01:25:35 +0000 Subject: [PATCH] [190231] Prepare API for UI/Non-UI Splitting --- .../rse/core/IRSEInteractionProvider.java | 121 +++++++++++++ .../rse/core/IRSERunnableWithProgress.java | 61 +++++++ .../org/eclipse/rse/core/RSECorePlugin.java | 56 ++++-- .../ui/DefaultUIInteractionProvider.java | 163 ++++++++++++++++++ .../rse/core/subsystems/SubSystem.java | 75 ++++---- 5 files changed, 425 insertions(+), 51 deletions(-) create mode 100644 rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java create mode 100644 rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSERunnableWithProgress.java create mode 100644 rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java new file mode 100644 index 00000000000..0a491ede8b2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - [190231] initial API and implementation + * IBM Corporation - Javadoc for runInDefaultContext() method + *******************************************************************************/ +package org.eclipse.rse.core; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; + +/** + * Interaction Provider Interface. + * + * Classes implementing this interface provide a means for RSE to communicate + * with the outside world: via progress monitors, events and messages. A UI + * implementation of this interface would typically use UI components for user + * interaction; although this can be changed also intermittently. + * + * Non-UI headless applications may log messages rather than doing interactive + * messages, and may use different Threads for sending messages. + * + * @since org.eclipse.rse.core 3.0 + */ +public interface IRSEInteractionProvider { + + /** + * Return a default progress monitor for the context that's currently + * active. + * + * Usually, long-running operations should always be created from the client + * with a progress monitor that they can use. Historically, however, this + * has not always been done and is especially problematic in operations that + * are performed as the result of Callbacks. + * + * For such situations, this method returns a default progress monitor in a + * context that we guess. We try to use one default progress use one for all + * phases of a single operation, such as connecting and resolving. + * + * @return a default progress monitor + */ + public IProgressMonitor getDefaultProgressMonitor(); + + /** + *
+ * Runs the given IRSERunnableWithProgress
in the default
+ * context available to this interaction provider, that provides a progress
+ * monitor. For example, if the default context is a
+ * ProgressMonitorDialog
then the runnable is run using the
+ * dialog's progress monitor. This method is derived from
+ * IRunnableContext#run()
.
+ *
+ * If fork
is false
, the current thread is
+ * used to run the runnable. Note that if fork
is
+ * true
, it is unspecified whether or not this method blocks
+ * until the runnable has been run. Implementers should document whether the
+ * runnable is run synchronously (blocking) or asynchronously
+ * (non-blocking), or if no assumption can be made about the blocking
+ * behaviour.
+ *
true
if the runnable should be run in a
+ * separate thread, and false
to run in the same
+ * thread
+ * @param cancellable true
to enable the cancellation, and
+ * false
to make the operation uncancellable
+ * @param runnable the runnable to run
+ *
+ * @exception InvocationTargetException wraps any exception or error which
+ * occurs while running the runnable
+ * @exception InterruptedException propagated by the context if the runnable
+ * acknowledges cancellation by throwing this exception. This
+ * should not be thrown if cancellable is false
.
+ */
+ public void runInDefaultContext(boolean fork, boolean cancellable, IRSERunnableWithProgress runnable) throws InvocationTargetException,
+ InterruptedException;
+
+ /**
+ * Asynchronously run the given runnable in a separate thread.
+ *
+ * UI implementations should have the runnable run in the dispatch thread,
+ * where it has access to UI components. This is used for notifications.
+ * Non-UI applications may choose any Thread they like, provided that two
+ * conditions are met:
+ * IRSERunnableWithProgress
interface should be implemented
+ * by any class whose instances are intended to be executed as a long-running
+ * operation. Long-running operations are typically presented at the UI via a
+ * modal dialog showing a progress indicator and a Cancel button.
+ *
+ * This interface is derived from
+ * org.eclipse.jface.operation.IRunnableWithProgress
, but
+ * brought into no-UI space. The class must define a run
method
+ * that takes a progress monitor. The run
method is usually not
+ * invoked directly, but rather by passing the
+ * IRunnableWithProgress
to the run
method of an
+ * IRunnableContext
, which provides the UI for the progress
+ * monitor and Cancel button.
+ *
+ * @see IRSEInteractionProvider
+ * @since org.eclipse.rse.core 3.0
+ */
+public interface IRSERunnableWithProgress {
+ /**
+ * Runs this operation. Progress should be reported to the given progress
+ * monitor. This method is usually invoked by an
+ * IRunnableContext
's run
method, which
+ * supplies the progress monitor. A request to cancel the operation should
+ * be honored and acknowledged by throwing InterruptedException
.
+ *
+ * @param monitor the progress monitor to use to display progress and
+ * receive requests for cancellation
+ * @exception InvocationTargetException if the run method must propagate a
+ * checked exception, it should wrap it inside an
+ * InvocationTargetException
; runtime
+ * exceptions are automatically wrapped in an
+ * InvocationTargetException
by the calling
+ * context
+ * @exception InterruptedException if the operation detects a request to
+ * cancel, using IProgressMonitor.isCanceled()
,
+ * it should exit by throwing
+ * InterruptedException
+ *
+ * @see IRSEInteractionProvider
+ */
+ public void run(IProgressMonitor monitor) throws InvocationTargetException,
+ InterruptedException;
+}
diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java
index decc88b6ead..1e8f73ea4c5 100644
--- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java
+++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java
@@ -22,6 +22,7 @@
* Martin Oberhuber (Wind River) - [215820] Move SystemRegistry implementation to Core
* David Dykstal (IBM) - [197167] adding notification and waiting for RSE model
* Martin Oberhuber (Wind River) - [cleanup] Add API "since" Javadoc tags
+ * Martin Oberhuber (Wind River) - [190231] Prepare API for UI/Non-UI Splitting
********************************************************************************/
package org.eclipse.rse.core;
@@ -57,7 +58,7 @@ import org.osgi.framework.BundleContext;
* RSECorePlugin provides the activation for the RSE core and acts as the
* primary registry for logging, persistence, and the main RSE service
* registries.
- *
+ *
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@@ -65,7 +66,7 @@ public class RSECorePlugin extends Plugin {
/**
* The plugin id for this plugin. Value "org.eclipse.rse.core".
- *
+ *
* @since org.eclipse.rse.core 3.0
*/
public static final String PLUGIN_ID = "org.eclipse.rse.core"; //$NON-NLS-1$
@@ -85,7 +86,7 @@ public class RSECorePlugin extends Plugin {
* {@link #isInitComplete(int)} which will return true if all phases of
* initialization are complete. Clients must not assume any particular
* ordering among phases based on the value.
- *
+ *
* @since org.eclipse.rse.core 3.0
*/
public static final int INIT_ALL = 0;
@@ -95,7 +96,7 @@ public class RSECorePlugin extends Plugin {
* {@link #isInitComplete(int)} which will return true if the model phase of
* the initialization is complete. Clients must not assume any particular
* ordering among phases based on the value.
- *
+ *
* @since org.eclipse.rse.core 3.0
*/
public static final int INIT_MODEL = 1;
@@ -105,7 +106,7 @@ public class RSECorePlugin extends Plugin {
* {@link #isInitComplete(int)} which will return true if the initializer
* phase of the initialization is complete. Clients must not assume any
* particular ordering among phases based on the value.
- *
+ *
* @since org.eclipse.rse.core 3.0
*/
public static final int INIT_INITIALIZER = 2;
@@ -115,6 +116,7 @@ public class RSECorePlugin extends Plugin {
private ISystemRegistry _systemRegistry = null;
private IRSEPersistenceManager _persistenceManager = null;
private ISubSystemConfigurationProxy[] _subsystemConfigurations = null;
+ private IRSEInteractionProvider _interactionProvider = null;
/**
* Returns the singleton instance of RSECorePlugin.
@@ -127,7 +129,7 @@ public class RSECorePlugin extends Plugin {
/**
* Waits until the RSE model has been fully restored from its persistent
* form. Should be used before accessing pieces of the model.
- *
+ *
* @return an IStatus indicating how the initialization ended.
* @throws InterruptedException if this wait was interrupted for some
* reason.
@@ -139,7 +141,7 @@ public class RSECorePlugin extends Plugin {
/**
* Waits until the RSE has completed a specific phase of its initialization.
- *
+ *
* @param phase the phase to wait for completion.
* @throws InterruptedException if this wait was interrupted for some
* reason.
@@ -156,7 +158,7 @@ public class RSECorePlugin extends Plugin {
/**
* Check whether the initialization of the RSE model is complete for a given
* phase.
- *
+ *
* @param phase the phase identifier.
* @return true
if the initialization for the given phase has
* completed regardless of its status of that completion.
@@ -175,7 +177,7 @@ public class RSECorePlugin extends Plugin {
* initialization phases complete. If the listener is added after the phase
* has completed it will not be invoked. If the listener is already in the
* set it will not be added again. Listeners may be notified in any order.
- *
+ *
* @param listener the listener to be added
* @since org.eclipse.rse.core 3.0
*/
@@ -186,7 +188,7 @@ public class RSECorePlugin extends Plugin {
/**
* Removes a listener to the set of listeners to be notified when phases
* complete. If the listener is not in the set this does nothing.
- *
+ *
* @param listener the listener to be removed
* @since org.eclipse.rse.core 3.0
*/
@@ -214,7 +216,7 @@ public class RSECorePlugin extends Plugin {
/**
* Return the master profile manager singleton.
- *
+ *
* @return the RSE Profile Manager Singleton.
* @since org.eclipse.rse.core 3.0
*/
@@ -226,7 +228,7 @@ public class RSECorePlugin extends Plugin {
* Check if the SystemRegistry has been instantiated already. Use this when
* you don't want to start the system registry as a side effect of
* retrieving it.
- *
+ *
* @return true
if the System Registry has been instantiated
* already.
* @since org.eclipse.rse.core 3.0
@@ -398,6 +400,36 @@ public class RSECorePlugin extends Plugin {
getLogger().logError("Unexpected Exception", t); //$NON-NLS-1$
}
+ /**
+ * Set the default interaction provider.
+ *
+ * When RSE is run with UI, the UI plugins need to set an UI-based
+ * interaction provider for showing dialogs from Core operations. Non-UI
+ * headless operations can use an Interaction Provider that just logs its
+ * messages and works without other UI.
+ *
+ * @param p the interaction provider to set.
+ * @since org.eclipse.rse.core 3.0
+ */
+ public void setDefaultInteractionProvider(IRSEInteractionProvider p) {
+ synchronized (this) {
+ _interactionProvider = p;
+ }
+ }
+
+ /**
+ * Get the default interface for interacting with the user or other outside
+ * world.
+ *
+ * @return the default interaction provider.
+ * @since org.eclipse.rse.core 3.0
+ */
+ public IRSEInteractionProvider getDefaultInteractionProvider() {
+ synchronized (this) {
+ return _interactionProvider;
+ }
+ }
+
/**
* Register declared keystore providers.
*/
diff --git a/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java b/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java
new file mode 100644
index 00000000000..8fb5858b5a4
--- /dev/null
+++ b/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2008 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Oberhuber (Wind River) - [190231] initial API and implementation
+ * Martin Oberhuber (Wind River) - brought in methods from SubSystem (c) IBM
+ *******************************************************************************/
+package org.eclipse.rse.internal.ui;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.rse.core.IRSEInteractionProvider;
+import org.eclipse.rse.core.IRSERunnableWithProgress;
+import org.eclipse.rse.services.clientserver.messages.SystemMessage;
+import org.eclipse.rse.ui.RSEUIPlugin;
+import org.eclipse.rse.ui.SystemBasePlugin;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A Default Interaction Provider that runs in the Eclipse / SWT UI.
+ * Meant to provide the same functionality as it was there before
+ * UI / Non-UI Splitting.
+ * @since org.eclipse.rse.ui 3.0
+ */
+public class DefaultUIInteractionProvider implements IRSEInteractionProvider {
+
+ private Shell shell = null;
+
+ private class NullRunnableContext implements IRunnableContext {
+ public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
+ IProgressMonitor monitor = new NullProgressMonitor();
+ runnable.run(monitor);
+ }
+ }
+
+ /**
+ * Get the progress monitor dialog for this operation. We try to use one for
+ * all phases of a single operation, such as connecting and resolving.
+ *
+ * @deprecated this is scheduled to be removed since we want to avoid UI
+ * components in SubSystem.
+ */
+ protected IRunnableContext getRunnableContext(/* Shell rshell */) {
+ if (Display.getCurrent() == null) {
+ return new NullRunnableContext();
+ }
+ // for wizards and dialogs use the specified context that was placed in
+ // the registry
+ IRunnableContext irc = RSEUIPlugin.getTheSystemRegistryUI().getRunnableContext();
+ if (irc != null) {
+ SystemBasePlugin.logInfo("Got runnable context from system registry"); //$NON-NLS-1$
+ return irc;
+ } else {
+ // for other cases, use statusbar
+ IWorkbenchWindow win = SystemBasePlugin.getActiveWorkbenchWindow();
+ if (win != null) {
+ Shell winShell = getActiveWorkbenchShell();
+ if (winShell != null && !winShell.isDisposed() && winShell.isVisible()) {
+ SystemBasePlugin.logInfo("Using active workbench window as runnable context"); //$NON-NLS-1$
+ shell = winShell;
+ return win;
+ // dwd } else {
+ // dwd win = null;
+ }
+ }
+ // dwd if (shell == null || shell.isDisposed() ||
+ // !shell.isVisible()) {
+ // dwd SystemBasePlugin.logInfo("Using progress monitor dialog with
+ // given shell as parent");
+ // dwd shell = rshell;
+ // dwd }
+ // dwd IRunnableContext dlg = new ProgressMonitorDialog(rshell);
+ IRunnableContext dlg = new ProgressMonitorDialog(shell);
+ return dlg;
+ }
+ }
+
+ /**
+ * Helper/convenience method. Return shell of active window.
+ */
+ public static Shell getActiveWorkbenchShell() {
+ Shell result = null;
+ if (PlatformUI.isWorkbenchRunning()) {
+ try {
+ IWorkbenchWindow window = getActiveWorkbenchWindow();
+ if (window != null) {
+ result = window.getShell();
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ } else // workbench has not been loaded yet!
+ {
+ return null;
+ }
+ return result;
+ }
+
+ /**
+ * Helper/convenience method. Return active window
+ */
+ public static IWorkbenchWindow getActiveWorkbenchWindow() {
+ return RSEUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
+ }
+
+ public void runInDefaultContext(boolean fork, boolean cancellable, IRSERunnableWithProgress runnable) throws InvocationTargetException,
+ InterruptedException {
+ // TODO Auto-generated method stub
+ }
+
+ private Display getDefaultDisplay() {
+ Display d = Display.getCurrent();
+ if (d == null) {
+ d = SystemBasePlugin.getActiveWorkbenchShell().getDisplay();
+ if (d == null) {
+ d = Display.getDefault();
+ }
+ }
+ return d;
+ }
+
+ public void asyncExec(Runnable runnable) {
+ getDefaultDisplay().asyncExec(runnable);
+ }
+
+ public void flushRunnableQueue() {
+ Display d = Display.getCurrent();
+ if (d == null) {
+ getDefaultDisplay().syncExec(new Runnable() {
+ public void run() {
+ flushRunnableQueue();
+ }
+ });
+ } else {
+ while (d.readAndDispatch()) {
+ // flush the event queue
+ }
+ }
+ }
+
+ public IProgressMonitor getDefaultProgressMonitor() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void showMessage(SystemMessage msg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java b/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java
index aa8b7f3a22b..ff723b9259a 100644
--- a/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java
+++ b/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java
@@ -36,6 +36,7 @@
* David McKnight (IBM) - [220547] [api][breaking] SimpleSystemMessage needs to specify a message id and some messages should be shared
* David Dykstal (IBM) - [225089][ssh][shells][api] Canceling connection leads to exception
* Martin Oberhuber (Wind River) - [218304] Improve deferred adapter loading
+ * Martin Oberhuber (Wind River) - [190231] Prepare API for UI/Non-UI Splitting
********************************************************************************/
package org.eclipse.rse.core.subsystems;
@@ -62,6 +63,7 @@ import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
+import org.eclipse.rse.core.IRSEInteractionProvider;
import org.eclipse.rse.core.RSECorePlugin;
import org.eclipse.rse.core.RSEPreferencesManager;
import org.eclipse.rse.core.events.ISystemModelChangeEvent;
@@ -101,7 +103,6 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PropertyPage;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.progress.WorkbenchJob;
@@ -164,8 +165,9 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider
protected ISubSystemConfiguration parentSubSystemConfiguration;
protected String previousUserIdKey;
-
+ private IRSEInteractionProvider _interactionProvider = null;
protected Shell shell = null;
+
protected boolean supportsConnecting = true;
protected boolean sortResults = true;
protected boolean runInThread = true;
@@ -184,7 +186,6 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider
protected String _name = null;
protected String _subsystemConfigurationId = null;
protected boolean _hidden = false;
-
private boolean _isInitialized = false;
@@ -225,6 +226,37 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider
_connectorService.registerSubSystem(this);
}
+ /**
+ * Set an Interaction Provider specific for this subsystem.
+ *
+ * @param p the new interaction provider to use, or null
to
+ * fall back to the default interaction provider (from
+ * RSECorePlugin).
+ * @since 3.0
+ */
+ public void setInteractionProvider(IRSEInteractionProvider p) {
+ synchronized (this) {
+ _interactionProvider = p;
+ }
+ }
+
+ /**
+ * Get the current Interaction Provider. Returns a specific one for this
+ * subsystem if it has been set, or falls back to the default one from
+ * RSECorePlugin otherwise.
+ *
+ * @return the interaction provider to use.
+ * @since 3.0
+ */
+ public IRSEInteractionProvider getInteractionProvider() {
+ synchronized (this) {
+ if (_interactionProvider != null) {
+ return _interactionProvider;
+ }
+ }
+ return RSECorePlugin.getDefault().getDefaultInteractionProvider();
+ }
+
/**
* Internal method to select the appropriate command subsystem when there are multiple defined for this connection.
* The default implementation is to return the first, but child classes can refine this. Input is always an array of
@@ -2908,7 +2940,7 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider
// for other cases, use statusbar
IWorkbenchWindow win = SystemBasePlugin.getActiveWorkbenchWindow();
if (win != null) {
- Shell winShell = getActiveWorkbenchShell();
+ Shell winShell = SystemBasePlugin.getActiveWorkbenchShell();
if (winShell != null && !winShell.isDisposed() && winShell.isVisible()) {
SystemBasePlugin.logInfo("Using active workbench window as runnable context"); //$NON-NLS-1$
shell = winShell;
@@ -2935,41 +2967,6 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider
return shell;
}
- /**
- * Helper/convenience method. Return shell of active window.
- */
- public static Shell getActiveWorkbenchShell()
- {
- Shell result = null;
- if (PlatformUI.isWorkbenchRunning())
- {
- try
- {
- IWorkbenchWindow window = getActiveWorkbenchWindow();
- if (window != null)
- {
- result = window.getShell();
- }
- }
- catch (Exception e)
- {
- return null;
- }
- }
- else // workbench has not been loaded yet!
- {
- return null;
- }
- return result;
- }
- /**
- * Helper/convenience method. Return active window
- */
- public static IWorkbenchWindow getActiveWorkbenchWindow()
- {
- return RSEUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
- }
-
/**
* Private. Do not override.
* @generated This field/method will be replaced during code generation