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()} & {@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