1 /*******************************************************************************
2  *  Copyright (c) 2000, 2019 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  *     Serge Beauchamp (Freescale Semiconductor) - [252996] add PT_FILTER_PROVIDERS
14  *     Serge Beauchamp (Freescale Semiconductor) - [229633] add PT_VARIABLE_PROVIDERS
15  *     James Blackburn (Broadcom Corp.) - ongoing development
16  *     Tom Hochstein (Freescale) - Bug 409996 - 'Restore Defaults' does not work properly on Project Properties > Resource tab
17  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427
18  *******************************************************************************/
19 package org.eclipse.core.resources;
20 
21 import java.util.*;
22 import org.eclipse.core.internal.preferences.PreferencesService;
23 import org.eclipse.core.internal.resources.*;
24 import org.eclipse.core.internal.utils.Messages;
25 import org.eclipse.core.internal.utils.Policy;
26 import org.eclipse.core.runtime.*;
27 import org.eclipse.core.runtime.jobs.IJobManager;
28 import org.eclipse.core.runtime.jobs.Job;
29 import org.eclipse.core.runtime.preferences.InstanceScope;
30 import org.eclipse.osgi.service.debug.DebugOptions;
31 import org.eclipse.osgi.service.debug.DebugOptionsListener;
32 import org.osgi.framework.*;
33 
34 /**
35  * The plug-in runtime class for the Resources plug-in.  This is
36  * the starting point for all workspace and resource manipulation.
37  * A typical sequence of events would be for a dependent plug-in
38  * to call <code>ResourcesPlugin.getWorkspace()</code>.
39  * Doing so would cause this plug-in to be activated and the workspace
40  * (if any) to be loaded from disk and initialized.
41  *
42  * @noinstantiate This class is not intended to be instantiated by clients.
43  */
44 public final class ResourcesPlugin extends Plugin {
45 	/**
46 	 * Unique identifier constant (value <code>"org.eclipse.core.resources"</code>)
47 	 * for the standard Resources plug-in.
48 	 */
49 	public static final String PI_RESOURCES = "org.eclipse.core.resources"; //$NON-NLS-1$
50 
51 	/*====================================================================
52 	 * Constants defining the ids of the standard workspace extension points:
53 	 *====================================================================*/
54 
55 	/**
56 	 * Simple identifier constant (value <code>"builders"</code>)
57 	 * for the builders extension point.
58 	 */
59 	public static final String PT_BUILDERS = "builders"; //$NON-NLS-1$
60 
61 	/**
62 	 * Simple identifier constant (value <code>"natures"</code>)
63 	 * for the natures extension point.
64 	 */
65 	public static final String PT_NATURES = "natures"; //$NON-NLS-1$
66 
67 	/**
68 	 * Simple identifier constant (value <code>"markers"</code>)
69 	 * for the markers extension point.
70 	 */
71 	public static final String PT_MARKERS = "markers"; //$NON-NLS-1$
72 
73 	/**
74 	 * Simple identifier constant (value <code>"fileModificationValidator"</code>)
75 	 * for the file modification validator extension point.
76 	 */
77 	public static final String PT_FILE_MODIFICATION_VALIDATOR = "fileModificationValidator"; //$NON-NLS-1$
78 
79 	/**
80 	 * Simple identifier constant (value <code>"moveDeleteHook"</code>)
81 	 * for the move/delete hook extension point.
82 	 *
83 	 * @since 2.0
84 	 */
85 	public static final String PT_MOVE_DELETE_HOOK = "moveDeleteHook"; //$NON-NLS-1$
86 
87 	/**
88 	 * Simple identifier constant (value <code>"teamHook"</code>)
89 	 * for the team hook extension point.
90 	 *
91 	 * @since 2.1
92 	 */
93 	public static final String PT_TEAM_HOOK = "teamHook"; //$NON-NLS-1$
94 
95 	/**
96 	 * Simple identifier constant (value <code>"refreshProviders"</code>)
97 	 * for the auto-refresh refresh providers extension point.
98 	 *
99 	 * @since 3.0
100 	 */
101 	public static final String PT_REFRESH_PROVIDERS = "refreshProviders"; //$NON-NLS-1$
102 
103 	/**
104 	 * Simple identifier constant (value <code>"modelProviders"</code>)
105 	 * for the model providers extension point.
106 	 *
107 	 * @since 3.2
108 	 */
109 	public static final String PT_MODEL_PROVIDERS = "modelProviders"; //$NON-NLS-1$
110 
111 	/**
112 	 * Simple identifier constant (value <code>"variableProviders"</code>)
113 	 * for the variable providers extension point.
114 	 *
115 	 * @since 3.6
116 	 */
117 	public static final String PT_VARIABLE_PROVIDERS = "variableResolvers"; //$NON-NLS-1$
118 
119 	/**
120 	 * Simple identifier constant (value <code>"filterMatchers"</code>)
121 	 * for the filter matchers extension point.
122 	 *
123 	 * @since 3.6
124 	 */
125 	public static final String PT_FILTER_MATCHERS = "filterMatchers"; //$NON-NLS-1$
126 
127 	/**
128 	 * Constant identifying the job family identifier for the background autobuild job.
129 	 *
130 	 * @see IJobManager#join(Object, IProgressMonitor)
131 	 * @since 3.0
132 	 */
133 	public static final Object FAMILY_AUTO_BUILD = new Object();
134 
135 	/**
136 	 * Constant identifying the job family identifier for the background auto-refresh job.
137 	 *
138 	 * @see IJobManager#join(Object, IProgressMonitor)
139 	 * @since 3.1
140 	 */
141 	public static final Object FAMILY_AUTO_REFRESH = new Object();
142 
143 	/**
144 	 * Constant identifying the job family identifier for a background build job. All clients
145 	 * that schedule background jobs for performing builds should include this job
146 	 * family in their implementation of <code>belongsTo</code>.
147 	 *
148 	 * @see IJobManager#join(Object, IProgressMonitor)
149 	 * @see Job#belongsTo(Object)
150 	 * @since 3.0
151 	 */
152 	public static final Object FAMILY_MANUAL_BUILD = new Object();
153 
154 	/**
155 	 * Constant identifying the job family identifier for a background refresh job. All clients
156 	 * that schedule background jobs for performing refreshing should include this job
157 	 * family in their implementation of <code>belongsTo</code>.
158 	 *
159 	 * @see IJobManager#join(Object, IProgressMonitor)
160 	 * @see Job#belongsTo(Object)
161 	 * @since 3.4
162 	 */
163 	public static final Object FAMILY_MANUAL_REFRESH = new Object();
164 
165 	/**
166 	 * Name of a preference indicating the encoding to use when reading text
167 	 * files in the workspace.  The value is a string, and may
168 	 * be the default empty string, indicating that the file system encoding should
169 	 * be used instead.  The file system encoding can be retrieved using
170 	 * <code>System.getProperty("file.encoding")</code>.
171 	 * There is also a convenience method <code>getEncoding</code> which returns
172 	 * the value of this preference, or the file system encoding if this
173 	 * preference is not set.
174 	 * <p>
175 	 * Note that there is no guarantee that the value is a supported encoding.
176 	 * Callers should be prepared to handle <code>UnsupportedEncodingException</code>
177 	 * where this encoding is used.
178 	 * </p>
179 	 *
180 	 * @see #getEncoding()
181 	 * @see java.io.UnsupportedEncodingException
182 	 */
183 	public static final String PREF_ENCODING = "encoding"; //$NON-NLS-1$
184 
185 	/**
186 	 * Common prefix for workspace preference names.
187 	 * @since 2.1
188 	 */
189 	private static final String PREF_DESCRIPTION_PREFIX = "description."; //$NON-NLS-1$
190 
191 	/**
192 	 * @deprecated Do not use.
193 	 * @since 3.0
194 	 */
195 	@Deprecated
196 	public static final String PREF_MAX_NOTIFICATION_DELAY = "maxnotifydelay"; //$NON-NLS-1$
197 
198 	/**
199 	 * Name of a preference for configuring whether the workspace performs auto-
200 	 * builds.
201 	 *
202 	 * @see IWorkspaceDescription#isAutoBuilding()
203 	 * @see IWorkspaceDescription#setAutoBuilding(boolean)
204 	 * @since 2.1
205 	 */
206 	public static final String PREF_AUTO_BUILDING = PREF_DESCRIPTION_PREFIX + "autobuilding"; //$NON-NLS-1$
207 
208 	/**
209 	 * Name of a preference for configuring the order projects in the workspace
210 	 * are built.
211 	 *
212 	 * @see IWorkspaceDescription#getBuildOrder()
213 	 * @see IWorkspaceDescription#setBuildOrder(String[])
214 	 * @since 2.1
215 	 */
216 	public static final String PREF_BUILD_ORDER = PREF_DESCRIPTION_PREFIX + "buildorder"; //$NON-NLS-1$
217 
218 	/**
219 	 * Name of a preference for configuring whether to use the workspace's
220 	 * default order for building projects.
221 	 * @since 2.1
222 	 */
223 	public static final String PREF_DEFAULT_BUILD_ORDER = PREF_DESCRIPTION_PREFIX + "defaultbuildorder"; //$NON-NLS-1$
224 
225 	/**
226 	 * Name of a preference for configuring the maximum number of times that the
227 	 * workspace should rebuild when builders affect projects that have already
228 	 * been built.
229 	 *
230 	 * @see IWorkspaceDescription#getMaxBuildIterations()
231 	 * @see IWorkspaceDescription#setMaxBuildIterations(int)
232 	 * @since 2.1
233 	 */
234 	public static final String PREF_MAX_BUILD_ITERATIONS = PREF_DESCRIPTION_PREFIX + "maxbuilditerations"; //$NON-NLS-1$
235 
236 	/**
237 	 * Name of a preference for configuring whether to apply the specified history size policy.
238 	 *
239 	 * @see IWorkspaceDescription#isApplyFileStatePolicy()
240 	 * @see IWorkspaceDescription#setApplyFileStatePolicy(boolean)
241 	 * @since 3.6
242 	 */
243 	public static final String PREF_APPLY_FILE_STATE_POLICY = PREF_DESCRIPTION_PREFIX + "applyfilestatepolicy"; //$NON-NLS-1$
244 
245 	/**
246 	 * Name of a preference for configuring the maximum number of milliseconds a
247 	 * file state should be kept in the local history
248 	 *
249 	 * @see IWorkspaceDescription#getFileStateLongevity()
250 	 * @see IWorkspaceDescription#setFileStateLongevity(long)
251 	 * @since 2.1
252 	 */
253 	public static final String PREF_FILE_STATE_LONGEVITY = PREF_DESCRIPTION_PREFIX + "filestatelongevity"; //$NON-NLS-1$
254 
255 	/**
256 	 * Name of a preference for configuring the maximum permitted size of a file
257 	 * to be stored in the local history
258 	 *
259 	 * @see IWorkspaceDescription#getMaxFileStateSize()
260 	 * @see IWorkspaceDescription#setMaxFileStateSize(long)
261 	 * @since 2.1
262 	 */
263 	public static final String PREF_MAX_FILE_STATE_SIZE = PREF_DESCRIPTION_PREFIX + "maxfilestatesize"; //$NON-NLS-1$
264 
265 	/**
266 	 * Name of a preference for configuring the maximum number of states per
267 	 * file that can be stored in the local history.
268 	 *
269 	 * @see IWorkspaceDescription#getMaxFileStates()
270 	 * @see IWorkspaceDescription#setMaxFileStates(int)
271 	 * @since 2.1
272 	 */
273 	public static final String PREF_MAX_FILE_STATES = PREF_DESCRIPTION_PREFIX + "maxfilestates"; //$NON-NLS-1$
274 	/**
275 	 * Name of a preference for configuring the amount of time in milliseconds
276 	 * between automatic workspace snapshots
277 	 *
278 	 * @see IWorkspaceDescription#getSnapshotInterval()
279 	 * @see IWorkspaceDescription#setSnapshotInterval(long)
280 	 * @since 2.1
281 	 */
282 	public static final String PREF_SNAPSHOT_INTERVAL = PREF_DESCRIPTION_PREFIX + "snapshotinterval"; //$NON-NLS-1$
283 
284 	/**
285 	 * Name of a preference for turning off support for linked resources.  When
286 	 * this preference is set to "true", attempting to create linked resources will fail.
287 	 * @since 2.1
288 	 */
289 	public static final String PREF_DISABLE_LINKING = PREF_DESCRIPTION_PREFIX + "disableLinking";//$NON-NLS-1$
290 
291 	/**
292 	 * Name of a preference for configuring whether the workspace performs auto-
293 	 * refresh.  Auto-refresh installs a file-system listener, or performs
294 	 * periodic file-system polling to actively discover changes in the resource
295 	 * hierarchy.
296 	 * @since 3.0
297 	 */
298 	public static final String PREF_AUTO_REFRESH = "refresh.enabled"; //$NON-NLS-1$
299 
300 	/**
301 	 * Name of a preference for configuring whether out-of-sync resources are automatically
302 	 * asynchronously refreshed, when discovered to be out-of-sync by the workspace.
303 	 * <p>
304 	 * This preference suppresses out-of-sync CoreException for some read methods, including:
305 	 * {@link IFile#getContents()} &amp; {@link IFile#getContentDescription()}.
306 	 * </p>
307 	 * <p>
308 	 * In the future the workspace may enable other lightweight auto-refresh mechanisms when this
309 	 * preference is true. (The existing {@link ResourcesPlugin#PREF_AUTO_REFRESH} will continue
310 	 * to enable filesystem hooks and the existing polling based monitor.)
311 	 * </p>
312 	 * See the discussion: https://bugs.eclipse.org/303517
313 	 * @since 3.7
314 	 */
315 	public static final String PREF_LIGHTWEIGHT_AUTO_REFRESH = "refresh.lightweight.enabled"; //$NON-NLS-1$
316 
317 	/**
318 	 * Name of a preference for configuring whether encodings for derived
319 	 * resources within the project should be stored in a separate derived
320 	 * preference file.
321 	 *
322 	 * @since 3.7
323 	 */
324 	public static final String PREF_SEPARATE_DERIVED_ENCODINGS = "separateDerivedEncodings"; //$NON-NLS-1$
325 
326 	/**
327 	 * Default setting for {@value #PREF_SEPARATE_DERIVED_ENCODINGS}.
328 	 *
329 	 * @since 3.9
330 	 */
331 	public static final boolean DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS = false;
332 
333 	/**
334 	 * Name of a preference for configuring the marker severity in case project
335 	 * description references an unknown nature.
336 	 *
337 	 * @since 3.13
338 	 */
339 	public static final String PREF_MISSING_NATURE_MARKER_SEVERITY = "missingNatureMarkerSeverity"; //$NON-NLS-1$
340 
341 	/**
342 	 * Name of the preference to set max number of concurrent jobs running the workspace build.
343 	 * @since 3.13
344 	 */
345 	public static final String PREF_MAX_CONCURRENT_BUILDS = "maxConcurrentBuilds"; //$NON-NLS-1$
346 
347 	/**
348 	 * The single instance of this plug-in runtime class.
349 	 */
350 	private static ResourcesPlugin plugin;
351 
352 	/**
353 	 * The workspace managed by the single instance of this
354 	 * plug-in runtime class, or <code>null</code> is there is none.
355 	 */
356 	private static Workspace workspace = null;
357 
358 	private ServiceRegistration<IWorkspace> workspaceRegistration;
359 	private ServiceRegistration<DebugOptionsListener> debugRegistration;
360 
361 	private CheckMissingNaturesListener checkMissingNaturesListener;
362 
363 	/**
364 	 * Constructs an instance of this plug-in runtime class.
365 	 * <p>
366 	 * An instance of this plug-in runtime class is automatically created
367 	 * when the facilities provided by the Resources plug-in are required.
368 	 * <b>Clients must never explicitly instantiate a plug-in runtime class.</b>
369 	 * </p>
370 	 */
ResourcesPlugin()371 	public ResourcesPlugin() {
372 		plugin = this;
373 	}
374 
375 	/**
376 	 * Constructs a brand new workspace structure at the location in the local file system
377 	 * identified by the given path and returns a new workspace object.
378 	 *
379 	 * @exception CoreException if the workspace structure could not be constructed.
380 	 * Reasons include:
381 	 * <ul>
382 	 * <li> There is an existing workspace structure on at the given location
383 	 *      in the local file system.
384 	 * <li> A file exists at the given location in the local file system.
385 	 * <li> A directory could not be created at the given location in the
386 	 *      local file system.
387 	 * </ul>
388 	 */
constructWorkspace()389 	private static void constructWorkspace() throws CoreException {
390 		new LocalMetaArea().createMetaArea();
391 	}
392 
393 	/**
394 	 * Returns the encoding to use when reading text files in the workspace.
395 	 * This is the value of the <code>PREF_ENCODING</code> preference, or the
396 	 * file system encoding (<code>System.getProperty("file.encoding")</code>)
397 	 * if the preference is not set.
398 	 * <p>
399 	 * Note that this method does not check whether the result is a supported
400 	 * encoding.  Callers should be prepared to handle
401 	 * <code>UnsupportedEncodingException</code> where this encoding is used.
402 	 *
403 	 * @return  the encoding to use when reading text files in the workspace
404 	 * @see java.io.UnsupportedEncodingException
405 	 */
getEncoding()406 	public static String getEncoding() {
407 		String enc = getPlugin().getPluginPreferences().getString(PREF_ENCODING);
408 		if (enc == null || enc.length() == 0) {
409 			enc = System.getProperty("file.encoding"); //$NON-NLS-1$
410 		}
411 		return enc;
412 	}
413 
414 	/**
415 	 * Returns the Resources plug-in.
416 	 *
417 	 * @return the single instance of this plug-in runtime class
418 	 */
getPlugin()419 	public static ResourcesPlugin getPlugin() {
420 		return plugin;
421 	}
422 
423 	/**
424 	 * Returns the workspace. The workspace is not accessible after the resources
425 	 * plug-in has shutdown.
426 	 *
427 	 * @return the workspace that was created by the single instance of this
428 	 *   plug-in class.
429 	 */
getWorkspace()430 	public static IWorkspace getWorkspace() {
431 		if (workspace == null)
432 			throw new IllegalStateException(Messages.resources_workspaceClosed);
433 		return workspace;
434 	}
435 
436 	/**
437 	 * This implementation of the corresponding {@link BundleActivator} method
438 	 * closes the workspace without saving.
439 	 * @see BundleActivator#stop(BundleContext)
440 	 */
441 	@Override
stop(BundleContext context)442 	public void stop(BundleContext context) throws Exception {
443 		super.stop(context);
444 
445 		// unregister debug options listener
446 		debugRegistration.unregister();
447 		debugRegistration = null;
448 
449 		if (workspace == null) {
450 			return;
451 		}
452 		workspace.removeResourceChangeListener(checkMissingNaturesListener);
453 		InstanceScope.INSTANCE.getNode(PREF_MISSING_NATURE_MARKER_SEVERITY).removePreferenceChangeListener(checkMissingNaturesListener);
454 		if (workspaceRegistration != null) {
455 			workspaceRegistration.unregister();
456 		}
457 		// save the preferences for this plug-in
458 		getPlugin().savePluginPreferences();
459 		workspace.close(null);
460 
461 		// Forget workspace only if successfully closed, to
462 		// make it easier to debug cases where close() is failing.
463 		workspace = null;
464 		workspaceRegistration = null;
465 	}
466 
467 	/**
468 	 * This implementation of the corresponding {@link BundleActivator} method
469 	 * opens the workspace.
470 	 * @see BundleActivator#start(BundleContext)
471 	 */
472 	@Override
start(BundleContext context)473 	public void start(BundleContext context) throws Exception {
474 		super.start(context);
475 
476 		// register debug options listener
477 		Hashtable<String, String> properties = new Hashtable<>(2);
478 		properties.put(DebugOptions.LISTENER_SYMBOLICNAME, PI_RESOURCES);
479 		debugRegistration = context.registerService(DebugOptionsListener.class, Policy.RESOURCES_DEBUG_OPTIONS_LISTENER, properties);
480 
481 		if (!new LocalMetaArea().hasSavedWorkspace()) {
482 			constructWorkspace();
483 		}
484 		// Remember workspace before opening, to
485 		// make it easier to debug cases where open() is failing.
486 		workspace = new Workspace();
487 		PlatformURLResourceConnection.startup(workspace.getRoot().getLocation());
488 		initializePreferenceLookupOrder();
489 		IStatus result = workspace.open(null);
490 		if (!result.isOK())
491 			getLog().log(result);
492 		workspaceRegistration = context.registerService(IWorkspace.class, workspace, null);
493 		checkMissingNaturesListener = new CheckMissingNaturesListener();
494 		workspace.addResourceChangeListener(checkMissingNaturesListener, IResourceChangeEvent.POST_CHANGE);
495 		InstanceScope.INSTANCE.getNode(PI_RESOURCES).addPreferenceChangeListener(checkMissingNaturesListener);
496 	}
497 
498 	/*
499 	 * Add the project scope to the preference service's default look-up order so
500 	 * people get it for free
501 	 */
initializePreferenceLookupOrder()502 	private void initializePreferenceLookupOrder() {
503 		PreferencesService service = PreferencesService.getDefault();
504 		String[] original = service.getDefaultDefaultLookupOrder();
505 		List<String> newOrder = new ArrayList<>();
506 		// put the project scope first on the list
507 		newOrder.add(ProjectScope.SCOPE);
508 		newOrder.addAll(Arrays.asList(original));
509 		service.setDefaultDefaultLookupOrder(newOrder.toArray(new String[newOrder.size()]));
510 	}
511 }
512