Bug 502360 - Provide public Log API in org.eclipse.core.runtime
Change-Id: I775ed05e98442205facdf7b20d5a7cac9608fb88
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Log.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Log.java
new file mode 100644
index 0000000..dae7a10
--- /dev/null
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Log.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Google, 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:
+ * Stefan Xenos <sxenos@gmail.com> (Google) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.runtime;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * Contains utility functions for logging.
+ *
+ * @since 3.13
+ */
+public final class Log {
+ /**
+ * Writes an error message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ * @param exception
+ * exception to log or null if none.
+ */
+ public static void error(Object context, String message, Throwable exception) {
+ log(IStatus.ERROR, context, IStatus.OK, message, exception);
+ }
+
+ /**
+ * Writes an error message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ */
+ public static void error(Object context, String message) {
+ log(IStatus.ERROR, context, IStatus.OK, message, null);
+ }
+
+ /**
+ * Writes a warning message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ * @param exception
+ * exception to log or null if none.
+ */
+ public static void warning(Object context, String message, Throwable exception) {
+ log(IStatus.WARNING, context, IStatus.OK, message, exception);
+ }
+
+ /**
+ * Writes a warning message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ */
+ public static void warning(Object context, String message) {
+ log(IStatus.WARNING, context, IStatus.OK, message, null);
+ }
+
+ /**
+ * Writes an info message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ * @param exception
+ * exception to log or null if none.
+ */
+ public static void info(Object context, String message, Throwable exception) {
+ log(IStatus.INFO, context, IStatus.OK, message, exception);
+ }
+
+ /**
+ * Writes an info message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param message
+ * message string to be logged.
+ */
+ public static void info(Object context, String message) {
+ log(IStatus.INFO, context, IStatus.OK, message, null);
+ }
+
+ /**
+ * Writes a status message to the log.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @param toLog
+ * status message to be logged.
+ */
+ public static void log(Object context, IStatus toLog) {
+ getLog(context).log(toLog);
+ }
+
+ /**
+ * Returns the {@link ILog} associated with the given context object.
+ *
+ * @param context
+ * a {@link Class} or object that was loaded from the plugin that
+ * generated the message or a {@link String} containing the
+ * bundle's symbolic name.
+ * @return the {@link ILog} associated with the given context object.
+ */
+ public static ILog getLog(Object context) {
+ Bundle bundle = getBundleForContext(context);
+ return Platform.getLog(bundle);
+ }
+
+ private static void log(int severity, Object context, int code, String message, Throwable exception) {
+ Bundle bundle = getBundleForContext(context);
+ String symbolicName = bundle.getSymbolicName();
+ Platform.getLog(bundle).log(new Status(severity, symbolicName, code, message, exception));
+ }
+
+ /**
+ * Returns the bundle for the given object if the given object didn't come
+ * from a plugin bundle. If the given context is a String, it is used as the
+ * symbolic name of the bundle. If the given context is a Class, the bundle
+ * that contains that class is returned. Otherwise, the class of the given
+ * object is used.
+ */
+ private static Bundle getBundleForContext(Object context) {
+ Bundle bundle;
+ if (context instanceof String) {
+ bundle = Platform.getBundle((String) context);
+ if (bundle == null) {
+ throw new IllegalArgumentException(
+ "Bundle not found while attempting to write to log. Invalid bundle id = " + context); //$NON-NLS-1$
+ }
+ return bundle;
+ }
+ Class classFromBundle;
+ if (context instanceof Class) {
+ classFromBundle = (Class) context;
+ } else {
+ classFromBundle = context.getClass();
+ }
+ bundle = FrameworkUtil.getBundle(classFromBundle);
+ if (bundle == null) {
+ throw new IllegalArgumentException("Context must be a Class or Object that was loaded from an Eclipse" //$NON-NLS-1$
+ + " plugin bundle. Context was " + context); //$NON-NLS-1$
+ }
+ return bundle;
+ }
+}
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/AllTests.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/AllTests.java
index c3f41f7..5e7f509 100644
--- a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/AllTests.java
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/AllTests.java
@@ -28,6 +28,7 @@
suite.addTest(IAdapterManagerTest.suite());
suite.addTest(IAdapterManagerServiceTest.suite());
suite.addTest(AdapterManagerDynamicTest.suite());
+ suite.addTest(LogTest.suite());
suite.addTest(OperationCanceledExceptionTest.suite());
suite.addTest(PathTest.suite());
suite.addTest(PlatformTest.suite());
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/LogTest.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/LogTest.java
new file mode 100644
index 0000000..a15eab0
--- /dev/null
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/LogTest.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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:
+ * Stefan Xenos - initial API and implementation
+ * Stefan Xenos - bug 174539 - add a 1-argument convert(...) method
+ * Stefan Xenos - bug 174040 - SubMonitor#convert doesn't always set task name
+ * Stefan Xenos - bug 206942 - Regression test for infinite progress reporting rate
+ * IBM Corporation - bug 252446 - SubMonitor.newChild passes zero ticks to child
+ * Alexander Kurtakov <akurtako@redhat.com> - bug 458490
+ *******************************************************************************/
+package org.eclipse.core.tests.runtime;
+
+import java.util.ArrayList;
+import java.util.List;
+import junit.framework.*;
+import org.eclipse.core.runtime.*;
+
+public class LogTest extends TestCase {
+ private static String testMessage;
+
+ private final List<IStatus> loggedStatus = new ArrayList<>();
+
+ private ILogListener logListener = new ILogListener() {
+ @Override
+ public void logging(IStatus status, String plugin) {
+ if (plugin.equals(RuntimeTestsPlugin.PI_RUNTIME_TESTS)) {
+ loggedStatus.add(status);
+ }
+ }
+ };
+
+ public LogTest() {
+ super();
+ }
+
+ public LogTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ testMessage = getName();
+ Log.getLog(this).addLogListener(logListener);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ Log.getLog(this).removeLogListener(logListener);
+ }
+
+ public void testCorrectLogIsSelectedForObjectContext() {
+ assertEquals(RuntimeTestsPlugin.getPlugin().getLog(), Log.getLog(this));
+ }
+
+ public void testCorrectLogIsSelectedForClassContext() {
+ assertEquals(RuntimeTestsPlugin.getPlugin().getLog(), Log.getLog(LogTest.class));
+ }
+
+ public void testCorrectLogIsSelectedForStringContext() {
+ assertEquals(RuntimeTestsPlugin.getPlugin().getLog(), Log.getLog(RuntimeTestsPlugin.PI_RUNTIME_TESTS));
+ }
+
+ public void testLogError() {
+ Log.error(this, testMessage);
+ assertLogged(IStatus.ERROR, testMessage, null);
+ }
+
+ public void testLogErrorWithException() {
+ RuntimeException exception = new RuntimeException();
+ Log.error(this, testMessage, exception);
+ assertLogged(IStatus.ERROR, testMessage, exception);
+ }
+
+ public void testLogWarning() {
+ Log.warning(this, testMessage);
+ assertLogged(IStatus.WARNING, testMessage, null);
+ }
+
+ public void testLogWarningWithException() {
+ RuntimeException exception = new RuntimeException();
+ Log.warning(this, testMessage, exception);
+ assertLogged(IStatus.WARNING, testMessage, exception);
+ }
+
+ public void testLogInfo() {
+ Log.info(this, testMessage);
+ assertLogged(IStatus.INFO, testMessage, null);
+ }
+
+ public void testLogInfoWithException() {
+ RuntimeException exception = new RuntimeException();
+ Log.info(this, testMessage, exception);
+ assertLogged(IStatus.INFO, testMessage, exception);
+ }
+
+ public void testLog() {
+ Status status = new Status(IStatus.ERROR, RuntimeTestsPlugin.PI_RUNTIME_TESTS, testMessage);
+ Log.log(this, status);
+ assertLogged(IStatus.ERROR, testMessage, null);
+ }
+
+ private void assertLogged(int error, String message, Throwable exception) {
+ assertEquals("The wrong number of messages were logged", 1, loggedStatus.size());
+ IStatus status = loggedStatus.get(0);
+ assertEquals("The log message had the wrong severity", error, status.getSeverity());
+ assertEquals("The wrong exception was logged", exception, status.getException());
+ }
+
+ public static Test suite() {
+ return new TestSuite(LogTest.class);
+ }
+}