1 /*******************************************************************************
2  * Copyright (c) 2005, 2009 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.core.runtime;
15 
16 import org.eclipse.core.internal.runtime.*;
17 import org.eclipse.osgi.util.NLS;
18 
19 /**
20  * Runs the given ISafeRunnable in a protected mode: exceptions and certain
21  * errors thrown in the runnable are logged and passed to the runnable's
22  * exception handler.  Such exceptions are not rethrown by this method.
23  * <p>
24  * This class can be used without OSGi running.
25  * </p>
26  * @since org.eclipse.equinox.common 3.2
27  */
28 public final class SafeRunner {
29 
30 	/**
31 	 * Runs the given runnable in a protected mode. Exceptions
32 	 * thrown in the runnable are logged and passed to the runnable's
33 	 * exception handler. Such exceptions are not rethrown by this method.
34 	 * <p>
35 	 * In addition to catching all {@link Exception} types, this method also catches certain {@link Error}
36 	 * types that typically result from programming errors in the code being executed.
37 	 * Severe errors that are not generally safe to catch are not caught by this method.
38 	 * </p>
39 	 *
40 	 * @param code the runnable to run
41 	 */
run(ISafeRunnable code)42 	public static void run(ISafeRunnable code) {
43 		Assert.isNotNull(code);
44 		try {
45 			code.run();
46 		} catch (Exception | LinkageError | AssertionError e) {
47 			handleException(code, e);
48 		}
49 	}
50 
51 	/**
52 	 * Runs the given runnable in a protected mode and returns the result given by the runnable. Exceptions
53 	 * thrown in the runnable are logged and passed to the runnable's
54 	 * exception handler. Such exceptions are not rethrown by this method, instead null is returned.
55 	 * <p>
56 	 * In addition to catching all {@link Exception} types, this method also catches certain {@link Error}
57 	 * types that typically result from programming errors in the code being executed.
58 	 * Severe errors that are not generally safe to catch are not caught by this method.
59 	 * </p>
60 	 * @param <T> the result type
61 	 *
62 	 * @param code the runnable to run
63 	 * @return the result
64 	 *
65 	 * @since 3.11
66 	 */
run(ISafeRunnableWithResult<T> code)67 	public static <T> T run(ISafeRunnableWithResult<T> code) {
68 		Assert.isNotNull(code);
69 		try {
70 			return code.runWithResult();
71 		} catch (Exception | LinkageError | AssertionError e) {
72 			handleException(code, e);
73 			return null;
74 		}
75 	}
76 
handleException(ISafeRunnable code, Throwable exception)77 	private static void handleException(ISafeRunnable code, Throwable exception) {
78 		if (!(exception instanceof OperationCanceledException)) {
79 			String pluginId = getBundleIdOfSafeRunnable(code);
80 			IStatus status = convertToStatus(exception, pluginId);
81 			makeSureUserSeesException(exception, status);
82 		}
83 		code.handleException(exception);
84 	}
85 
makeSureUserSeesException(Throwable exception, IStatus status)86 	private static void makeSureUserSeesException(Throwable exception, IStatus status) {
87 		if (RuntimeLog.isEmpty()) {
88 			exception.printStackTrace();
89 		} else {
90 			RuntimeLog.log(status);
91 		}
92 	}
93 
getBundleIdOfSafeRunnable(ISafeRunnable code)94 	private static String getBundleIdOfSafeRunnable(ISafeRunnable code) {
95 		Activator activator = Activator.getDefault();
96 		String pluginId = null;
97 		if (activator != null)
98 			pluginId = activator.getBundleId(code);
99 		if (pluginId == null)
100 			return IRuntimeConstants.PI_COMMON;
101 		return pluginId;
102 	}
103 
convertToStatus(Throwable exception, String pluginId)104 	private static IStatus convertToStatus(Throwable exception, String pluginId) {
105 		String message = NLS.bind(CommonMessages.meta_pluginProblems, pluginId);
106 		if (exception instanceof CoreException) {
107 			MultiStatus status = new MultiStatus(pluginId, IRuntimeConstants.PLUGIN_ERROR, message, exception);
108 			status.merge(((CoreException) exception).getStatus());
109 			return status;
110 		}
111 		return new Status(IStatus.ERROR, pluginId, IRuntimeConstants.PLUGIN_ERROR, message, exception);
112 	}
113 }