1 /*******************************************************************************
2  * Copyright (c) 2000, 2020 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  *     Alexander Fedorov (ArSysOp) - Bug 561712
14  *******************************************************************************/
15 package org.eclipse.core.runtime;
16 
17 import java.util.Optional;
18 import org.eclipse.core.internal.runtime.LocalizationUtils;
19 import org.osgi.framework.FrameworkUtil;
20 
21 /**
22  * A concrete status implementation, suitable either for
23  * instantiating or subclassing.
24  * <p>
25  * This class can be used without OSGi running.
26  * </p>
27  */
28 public class Status implements IStatus {
29 
30 	/**
31 	 * Constant used to indicate an unknown plugin id.
32 	 */
33 	private static final String unknownId = "unknown"; //$NON-NLS-1$
34 
35 	/**
36 	 * A standard OK status with an "ok" message.
37 	 *
38 	 * @since 3.0
39 	 */
40 	public static final IStatus OK_STATUS = new Status(OK, unknownId, OK, LocalizationUtils.safeLocalize("ok"), null); //$NON-NLS-1$
41 	/**
42 	 * A standard CANCEL status with no message.
43 	 *
44 	 * @since 3.0
45 	 */
46 	public static final IStatus CANCEL_STATUS = new Status(CANCEL, unknownId, 1, "", null); //$NON-NLS-1$
47 	/**
48 	 * The severity. One of
49 	 * <ul>
50 	 * <li><code>CANCEL</code></li>
51 	 * <li><code>ERROR</code></li>
52 	 * <li><code>WARNING</code></li>
53 	 * <li><code>INFO</code></li>
54 	 * <li>or <code>OK</code> (0)</li>
55 	 * </ul>
56 	 */
57 	private int severity = OK;
58 
59 	/** Unique identifier of plug-in.
60 	 */
61 	private String pluginId;
62 
63 	/** Plug-in-specific status code.
64 	 */
65 	private int code;
66 
67 	/** Message, localized to the current locale.
68 	 */
69 	private String message;
70 
71 	/** Wrapped exception, or <code>null</code> if none.
72 	 */
73 	private Throwable exception = null;
74 
75 	/** Constant to avoid generating garbage.
76 	 */
77 	private static final IStatus[] theEmptyStatusArray = new IStatus[0];
78 
79 	/**
80 	 * Creates a new status object.  The created status has no children.
81 	 *
82 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
83 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
84 	 * @param caller the relevant class to build unique identifier from
85 	 * @param code the caller-specific status code, or <code>OK</code>
86 	 * @param message a human-readable message, localized to the
87 	 *    current locale
88 	 * @param exception a low-level exception, or <code>null</code> if not
89 	 *    applicable
90 	 *
91 	 * @since 3.12
92 	 */
Status(int severity, Class<?> caller, int code, String message, Throwable exception)93 	public Status(int severity, Class<?> caller, int code, String message, Throwable exception) {
94 		setSeverity(severity);
95 		setPlugin(identifier(caller));
96 		setCode(code);
97 		setMessage(message);
98 		setException(exception);
99 	}
100 
101 	/**
102 	 * Creates a new status object.  The created status has no children.
103 	 *
104 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
105 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
106 	 * @param pluginId the unique identifier of the relevant plug-in
107 	 * @param code the plug-in-specific status code, or <code>OK</code>
108 	 * @param message a human-readable message, localized to the
109 	 *    current locale
110 	 * @param exception a low-level exception, or <code>null</code> if not
111 	 *    applicable
112 	 */
Status(int severity, String pluginId, int code, String message, Throwable exception)113 	public Status(int severity, String pluginId, int code, String message, Throwable exception) {
114 		setSeverity(severity);
115 		setPlugin(pluginId);
116 		setCode(code);
117 		setMessage(message);
118 		setException(exception);
119 	}
120 
121 	/**
122 	 * Simplified constructor of a new status object; assumes that code is <code>OK</code>.
123 	 * The created status has no children.
124 	 *
125 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
126 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
127 	 * @param caller the relevant class to build unique identifier from
128 	 * @param message a human-readable message, localized to the
129 	 *    current locale
130 	 * @param exception a low-level exception, or <code>null</code> if not
131 	 *    applicable
132 	 *
133 	 * @since 3.12
134 	 */
Status(int severity, Class<?> caller, String message, Throwable exception)135 	public Status(int severity, Class<?> caller, String message, Throwable exception) {
136 		setSeverity(severity);
137 		setPlugin(identifier(caller));
138 		setMessage(message);
139 		setException(exception);
140 		setCode(OK);
141 	}
142 
143 	/**
144 	 * Simplified constructor of a new status object; assumes that code is <code>OK</code>.
145 	 * The created status has no children.
146 	 *
147 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
148 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
149 	 * @param pluginId the unique identifier of the relevant plug-in
150 	 * @param message a human-readable message, localized to the
151 	 *    current locale
152 	 * @param exception a low-level exception, or <code>null</code> if not
153 	 *    applicable
154 	 *
155 	 * @since org.eclipse.equinox.common 3.3
156 	 */
Status(int severity, String pluginId, String message, Throwable exception)157 	public Status(int severity, String pluginId, String message, Throwable exception) {
158 		setSeverity(severity);
159 		setPlugin(pluginId);
160 		setMessage(message);
161 		setException(exception);
162 		setCode(OK);
163 	}
164 
165 	/**
166 	 * Simplified constructor of a new status object; assumes that code is <code>OK</code> and
167 	 * exception is <code>null</code>. The created status has no children.
168 	 *
169 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
170 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
171 	 * @param caller the relevant class to build unique identifier from
172 	 * @param message a human-readable message, localized to the
173 	 *    current locale
174 	 *
175 	 * @since 3.12
176 	 */
Status(int severity, Class<?> caller, String message)177 	public Status(int severity, Class<?> caller, String message) {
178 		setSeverity(severity);
179 		setPlugin(identifier(caller));
180 		setMessage(message);
181 		setCode(OK);
182 		setException(null);
183 	}
184 
185 	/**
186 	 * Simplified constructor of a new status object; assumes that code is <code>OK</code> and
187 	 * exception is <code>null</code>. The created status has no children.
188 	 *
189 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
190 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
191 	 * @param pluginId the unique identifier of the relevant plug-in
192 	 * @param message a human-readable message, localized to the
193 	 *    current locale
194 	 *
195 	 * @since org.eclipse.equinox.common 3.3
196 	 */
Status(int severity, String pluginId, String message)197 	public Status(int severity, String pluginId, String message) {
198 		setSeverity(severity);
199 		setPlugin(pluginId);
200 		setMessage(message);
201 		setCode(OK);
202 		setException(null);
203 	}
204 
205 	/**
206 	 * Extracts an identifier from the given class: either bundle symbolic name or class name, never returns <code>null</code>
207 	 *
208 	 * @param caller the relevant class to build unique identifier from
209 	 * @return identifier extracted for the given class
210 	 */
identifier(Class<?> caller)211 	private String identifier(Class<?> caller) {
212 		return Optional.ofNullable(caller)//
213 				.flatMap(c -> Optional.ofNullable(FrameworkUtil.getBundle(c)))//
214 				.map(b -> b.getSymbolicName())//
215 				.orElseGet(() -> Optional.ofNullable(caller)//
216 						.map(c -> c.getName())//
217 						.orElse(getClass().getName()));
218 	}
219 
220 	@Override
getChildren()221 	public IStatus[] getChildren() {
222 		return theEmptyStatusArray;
223 	}
224 
225 	@Override
getCode()226 	public int getCode() {
227 		return code;
228 	}
229 
230 	@Override
getException()231 	public Throwable getException() {
232 		return exception;
233 	}
234 
235 	@Override
getMessage()236 	public String getMessage() {
237 		return message;
238 	}
239 
240 	@Override
getPlugin()241 	public String getPlugin() {
242 		return pluginId;
243 	}
244 
245 	@Override
getSeverity()246 	public int getSeverity() {
247 		return severity;
248 	}
249 
250 	@Override
isMultiStatus()251 	public boolean isMultiStatus() {
252 		return false;
253 	}
254 
255 	@Override
isOK()256 	public boolean isOK() {
257 		return severity == OK;
258 	}
259 
260 	@Override
matches(int severityMask)261 	public boolean matches(int severityMask) {
262 		return (severity & severityMask) != 0;
263 	}
264 
265 	/**
266 	 * Sets the status code.
267 	 *
268 	 * @param code the plug-in-specific status code, or <code>OK</code>
269 	 */
setCode(int code)270 	protected void setCode(int code) {
271 		this.code = code;
272 	}
273 
274 	/**
275 	 * Sets the exception.
276 	 *
277 	 * @param exception a low-level exception, or <code>null</code> if not
278 	 *    applicable
279 	 */
setException(Throwable exception)280 	protected void setException(Throwable exception) {
281 		this.exception = exception;
282 	}
283 
284 	/**
285 	 * Sets the message. If null is passed, message is set to an empty
286 	 * string.
287 	 *
288 	 * @param message a human-readable message, localized to the
289 	 *    current locale
290 	 */
setMessage(String message)291 	protected void setMessage(String message) {
292 		if (message == null)
293 			this.message = ""; //$NON-NLS-1$
294 		else
295 			this.message = message;
296 	}
297 
298 	/**
299 	 * Sets the plug-in id.
300 	 *
301 	 * @param pluginId the unique identifier of the relevant plug-in
302 	 */
setPlugin(String pluginId)303 	protected void setPlugin(String pluginId) {
304 		Assert.isLegal(pluginId != null && pluginId.length() > 0);
305 		this.pluginId = pluginId;
306 	}
307 
308 	/**
309 	 * Sets the severity.
310 	 *
311 	 * @param severity the severity; one of <code>OK</code>, <code>ERROR</code>,
312 	 * <code>INFO</code>, <code>WARNING</code>,  or <code>CANCEL</code>
313 	 */
setSeverity(int severity)314 	protected void setSeverity(int severity) {
315 		Assert.isLegal(severity == OK || severity == ERROR || severity == WARNING || severity == INFO || severity == CANCEL);
316 		this.severity = severity;
317 	}
318 
319 	/**
320 	 * Returns a string representation of the status, suitable
321 	 * for debugging purposes only.
322 	 */
323 	@Override
toString()324 	public String toString() {
325 		StringBuilder buf = new StringBuilder();
326 		buf.append("Status "); //$NON-NLS-1$
327 		if (severity == OK) {
328 			buf.append("OK"); //$NON-NLS-1$
329 		} else if (severity == ERROR) {
330 			buf.append("ERROR"); //$NON-NLS-1$
331 		} else if (severity == WARNING) {
332 			buf.append("WARNING"); //$NON-NLS-1$
333 		} else if (severity == INFO) {
334 			buf.append("INFO"); //$NON-NLS-1$
335 		} else if (severity == CANCEL) {
336 			buf.append("CANCEL"); //$NON-NLS-1$
337 		} else {
338 			buf.append("severity="); //$NON-NLS-1$
339 			buf.append(severity);
340 		}
341 		buf.append(": "); //$NON-NLS-1$
342 		buf.append(pluginId);
343 		buf.append(" code="); //$NON-NLS-1$
344 		buf.append(code);
345 		buf.append(' ');
346 		buf.append(message);
347 		buf.append(' ');
348 		buf.append(exception);
349 		return buf.toString();
350 	}
351 }
352