| 1 | /******************************************************************************* | 
| 2 |  * Copyright (c) 2007, 2009 IBM Corporation and others. | 
| 3 |  * All rights reserved. This program and the accompanying materials | 
| 4 |  * are made available under the terms of the Eclipse Public License v1.0 | 
| 5 |  * which accompanies this distribution, and is available at | 
| 6 |  * http://www.eclipse.org/legal/epl-v10.html | 
| 7 |  * | 
| 8 |  * Contributors: | 
| 9 |  *     IBM Corporation - initial API and implementation | 
| 10 |  *******************************************************************************/ | 
| 11 | package org.eclipse.pde.api.tools.internal.provisional; | 
| 12 |   | 
| 13 | import java.util.ArrayList; | 
| 14 | import java.util.HashSet; | 
| 15 | import java.util.Iterator; | 
| 16 | import java.util.List; | 
| 17 |   | 
| 18 | import org.eclipse.core.resources.IProject; | 
| 19 | import org.eclipse.core.resources.ISaveContext; | 
| 20 | import org.eclipse.core.resources.ISaveParticipant; | 
| 21 | import org.eclipse.core.resources.ProjectScope; | 
| 22 | import org.eclipse.core.resources.ResourcesPlugin; | 
| 23 | import org.eclipse.core.runtime.CoreException; | 
| 24 | import org.eclipse.core.runtime.IStatus; | 
| 25 | import org.eclipse.core.runtime.Platform; | 
| 26 | import org.eclipse.core.runtime.Plugin; | 
| 27 | import org.eclipse.core.runtime.Status; | 
| 28 | import org.eclipse.core.runtime.preferences.DefaultScope; | 
| 29 | import org.eclipse.core.runtime.preferences.IEclipsePreferences; | 
| 30 | import org.eclipse.core.runtime.preferences.IPreferencesService; | 
| 31 | import org.eclipse.core.runtime.preferences.IScopeContext; | 
| 32 | import org.eclipse.core.runtime.preferences.InstanceScope; | 
| 33 | import org.eclipse.pde.api.tools.internal.ApiBaselineManager; | 
| 34 | import org.eclipse.pde.api.tools.internal.ApiDescription; | 
| 35 | import org.eclipse.pde.api.tools.internal.ApiDescriptionManager; | 
| 36 | import org.eclipse.pde.api.tools.internal.ApiFilterStore; | 
| 37 | import org.eclipse.pde.api.tools.internal.JavadocTagManager; | 
| 38 | import org.eclipse.pde.api.tools.internal.SessionManager; | 
| 39 | import org.eclipse.pde.api.tools.internal.builder.AbstractProblemDetector; | 
| 40 | import org.eclipse.pde.api.tools.internal.builder.ApiAnalysisBuilder; | 
| 41 | import org.eclipse.pde.api.tools.internal.builder.ReferenceAnalyzer; | 
| 42 | import org.eclipse.pde.api.tools.internal.builder.ReferenceExtractor; | 
| 43 | import org.eclipse.pde.api.tools.internal.builder.ReferenceResolver; | 
| 44 | import org.eclipse.pde.api.tools.internal.comparator.ClassFileComparator; | 
| 45 | import org.eclipse.pde.api.tools.internal.descriptors.ElementDescriptorImpl; | 
| 46 | import org.eclipse.pde.api.tools.internal.model.PluginProjectApiComponent; | 
| 47 | import org.eclipse.pde.api.tools.internal.provisional.comparator.ApiComparator; | 
| 48 | import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes; | 
| 49 | import org.eclipse.pde.api.tools.internal.provisional.scanner.TagScanner; | 
| 50 | import org.eclipse.pde.api.tools.internal.util.FileManager; | 
| 51 | import org.osgi.framework.BundleContext; | 
| 52 | import org.osgi.service.prefs.BackingStoreException; | 
| 53 |   | 
| 54 | /** | 
| 55 |  * API Tools core plug-in. | 
| 56 |  * API tools can be run with or without an OSGi framework. | 
| 57 |  *  | 
| 58 |  * @since 1.0.0 | 
| 59 |  */ | 
| 60 | public class ApiPlugin extends Plugin implements ISaveParticipant { | 
| 61 |          | 
| 62 |         /** | 
| 63 |          * Constant representing the name of the javadoc tag extension point. | 
| 64 |          * Value is <code>apiJavadocTags</code> | 
| 65 |          */ | 
| 66 |         public static final String EXTENSION_JAVADOC_TAGS = "apiJavadocTags"; //$NON-NLS-1$ | 
| 67 |         /** | 
| 68 |          * The plug-in identifier of the PDE API tool support | 
| 69 |          * (value <code>"org.eclipse.pde.api.tools"</code>). | 
| 70 |          */ | 
| 71 |         public static final String PLUGIN_ID = "org.eclipse.pde.api.tools" ; //$NON-NLS-1$ | 
| 72 |         /** | 
| 73 |          * The API tooling nature id | 
| 74 |          * (value <code>"org.eclipse.pde.api.tools.apiAnalysisNature"</code>). | 
| 75 |          */ | 
| 76 |         public static final String NATURE_ID = PLUGIN_ID + ".apiAnalysisNature" ; //$NON-NLS-1$ | 
| 77 |         /** | 
| 78 |          * Status code indicating an unexpected internal error. | 
| 79 |          */ | 
| 80 |         public static final int INTERNAL_ERROR = 120; | 
| 81 |         /** | 
| 82 |          * Status code indicating an unexpected error | 
| 83 |          */ | 
| 84 |         public static final int ERROR = 121; | 
| 85 |          | 
| 86 |         /** | 
| 87 |          * Status code indicating a resolution error | 
| 88 |          */ | 
| 89 |         public static final int REPORT_RESOLUTION_ERRORS = 122; | 
| 90 |   | 
| 91 |         /** | 
| 92 |          * Status code indicating that a baseline is disposed | 
| 93 |          */ | 
| 94 |         public static final int REPORT_BASELINE_IS_DISPOSED = 123; | 
| 95 |   | 
| 96 |         /** | 
| 97 |          * Constant representing severity levels for error/warning preferences | 
| 98 |          * Value is: <code>0</code> | 
| 99 |          */ | 
| 100 |         public static final int SEVERITY_IGNORE = 0; | 
| 101 |         /** | 
| 102 |          * Constant representing severity levels for error/warning preferences | 
| 103 |          * Value is: <code>1</code> | 
| 104 |          */ | 
| 105 |         public static final int SEVERITY_WARNING = 1; | 
| 106 |         /** | 
| 107 |          * Constant representing severity levels for error/warning preferences | 
| 108 |          * Value is: <code>2</code> | 
| 109 |          */ | 
| 110 |         public static final int SEVERITY_ERROR = 2; | 
| 111 |          | 
| 112 |         /** | 
| 113 |          * Constant representing the preference value 'ignore'. | 
| 114 |          * Value is: <code>Ignore</code> | 
| 115 |          */ | 
| 116 |         public static final String VALUE_IGNORE = "Ignore"; //$NON-NLS-1$ | 
| 117 |         /** | 
| 118 |          * Constant representing the preference value 'warning'. | 
| 119 |          * Value is: <code>Warning</code> | 
| 120 |          */ | 
| 121 |         public static final String VALUE_WARNING = "Warning"; //$NON-NLS-1$ | 
| 122 |         /** | 
| 123 |          * Constant representing the preference value 'error'. | 
| 124 |          * Value is: <code>Error</code> | 
| 125 |          */ | 
| 126 |         public static final String VALUE_ERROR = "Error"; //$NON-NLS-1$ | 
| 127 |         /** | 
| 128 |          * Constant representing the preference value 'disabled'. | 
| 129 |          * Value is: <code>Disabled</code> | 
| 130 |          */ | 
| 131 |         public static final String VALUE_DISABLED = "Disabled"; //$NON-NLS-1$ | 
| 132 |         /** | 
| 133 |          * Constant representing the preference value 'enabled'. | 
| 134 |          * Value is: <code>Enabled</code> | 
| 135 |          */ | 
| 136 |         public static final String VALUE_ENABLED = "Enabled"; //$NON-NLS-1$ | 
| 137 |         /** | 
| 138 |          * The identifier for the Api builder | 
| 139 |          * Value is: <code>"org.eclipse.pde.api.tools.apiAnalysisBuilder"</code> | 
| 140 |          */ | 
| 141 |         public static final String BUILDER_ID = PLUGIN_ID + ".apiAnalysisBuilder" ; //$NON-NLS-1$ | 
| 142 |          | 
| 143 |         public static final String BASELINE_IS_DISPOSED = "baseline is disposed"; //$NON-NLS-1$ | 
| 144 |         /** | 
| 145 |          * Singleton instance of the plugin | 
| 146 |          */ | 
| 147 |         private static ApiPlugin fgDefault = null; | 
| 148 |         /** | 
| 149 |          * Singleton instance of the {@link JavadocTagManager} | 
| 150 |          */ | 
| 151 |         private static JavadocTagManager fgTagManager = null; | 
| 152 |         /** | 
| 153 |          * Singleton instance of the {@link ISessionManager} | 
| 154 |          */ | 
| 155 |         private static ISessionManager fgSessionManager = null; | 
| 156 |         /** | 
| 157 |          * Private debug options | 
| 158 |          */ | 
| 159 |         private static final String BUILDER_DEBUG = PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$ | 
| 160 |         private static final String DELTA_DEBUG = PLUGIN_ID + "/debug/delta" ; //$NON-NLS-1$ | 
| 161 |         private static final String CLASSFILE_VISITOR_DEBUG = PLUGIN_ID + "/debug/classfilevisitor" ; //$NON-NLS-1$ | 
| 162 |         private static final String DESCRIPTOR_FRAMEWORK_DEBUG = PLUGIN_ID + "/debug/descriptor/framework" ; //$NON-NLS-1$ | 
| 163 |         private static final String TAG_SCANNER_DEBUG = PLUGIN_ID + "/debug/tagscanner" ; //$NON-NLS-1$ | 
| 164 |         private static final String PLUGIN_WORKSPACE_COMPONENT_DEBUG = PLUGIN_ID + "/debug/pluginworkspacecomponent"; //$NON-NLS-1$ | 
| 165 |         private static final String API_PROFILE_MANAGER_DEBUG = PLUGIN_ID + "/debug/profilemanager"; //$NON-NLS-1$ | 
| 166 |         private static final String API_FILTER_STORE_DEBUG = PLUGIN_ID + "/debug/apifilterstore"; //$NON-NLS-1$ | 
| 167 |         private static final String API_REFERENCE_ANALYZER_DEBUG = PLUGIN_ID + "/debug/refanalyzer"; //$NON-NLS-1$ | 
| 168 |         private static final String PROBLEM_DETECTOR_DEBUG = PLUGIN_ID + "/debug/problemdetector"; //$NON-NLS-1$ | 
| 169 |         private static final String REFERENCE_RESOLVER_DEBUG = PLUGIN_ID + "/debug/refresolver"; //$NON-NLS-1$ | 
| 170 |         private static final String API_DESCRIPTION = PLUGIN_ID + "/debug/apidescription"; //$NON-NLS-1$ | 
| 171 |   | 
| 172 |         public final static String TRUE = "true"; //$NON-NLS-1$ | 
| 173 |   | 
| 174 |         public static String[] AllCompatibilityKeys = new String[] { | 
| 175 |                 IApiProblemTypes.API_COMPONENT_REMOVED_TYPE, | 
| 176 |                 IApiProblemTypes.API_COMPONENT_REMOVED_API_TYPE, | 
| 177 |                 IApiProblemTypes.API_COMPONENT_REMOVED_REEXPORTED_TYPE, | 
| 178 |                 IApiProblemTypes.API_COMPONENT_REMOVED_REEXPORTED_API_TYPE, | 
| 179 |                 IApiProblemTypes.ANNOTATION_REMOVED_FIELD, | 
| 180 |                 IApiProblemTypes.ANNOTATION_REMOVED_METHOD, | 
| 181 |                 IApiProblemTypes.ANNOTATION_REMOVED_TYPE_MEMBER, | 
| 182 |                 IApiProblemTypes.ANNOTATION_CHANGED_TYPE_CONVERSION, | 
| 183 |                 IApiProblemTypes.ANNOTATION_ADDED_METHOD_NO_DEFAULT_VALUE, | 
| 184 |                 IApiProblemTypes.INTERFACE_ADDED_FIELD, | 
| 185 |                 IApiProblemTypes.INTERFACE_ADDED_METHOD, | 
| 186 |                 IApiProblemTypes.INTERFACE_ADDED_RESTRICTIONS, | 
| 187 |                 IApiProblemTypes.INTERFACE_ADDED_SUPER_INTERFACE_WITH_METHODS, | 
| 188 |                 IApiProblemTypes.INTERFACE_ADDED_TYPE_PARAMETER, | 
| 189 |                 IApiProblemTypes.INTERFACE_REMOVED_TYPE_PARAMETER, | 
| 190 |                 IApiProblemTypes.INTERFACE_REMOVED_FIELD, | 
| 191 |                 IApiProblemTypes.INTERFACE_REMOVED_METHOD, | 
| 192 |                 IApiProblemTypes.INTERFACE_REMOVED_TYPE_MEMBER, | 
| 193 |                 IApiProblemTypes.INTERFACE_CHANGED_TYPE_CONVERSION, | 
| 194 |                 IApiProblemTypes.INTERFACE_CHANGED_CONTRACTED_SUPERINTERFACES_SET, | 
| 195 |                 IApiProblemTypes.ENUM_CHANGED_CONTRACTED_SUPERINTERFACES_SET, | 
| 196 |                 IApiProblemTypes.ENUM_CHANGED_TYPE_CONVERSION, | 
| 197 |                 IApiProblemTypes.ENUM_REMOVED_FIELD, | 
| 198 |                 IApiProblemTypes.ENUM_REMOVED_ENUM_CONSTANT, | 
| 199 |                 IApiProblemTypes.ENUM_REMOVED_METHOD, | 
| 200 |                 IApiProblemTypes.ENUM_REMOVED_TYPE_MEMBER, | 
| 201 |                 IApiProblemTypes.CLASS_ADDED_METHOD, | 
| 202 |                 IApiProblemTypes.CLASS_ADDED_RESTRICTIONS, | 
| 203 |                 IApiProblemTypes.CLASS_ADDED_TYPE_PARAMETER, | 
| 204 |                 IApiProblemTypes.CLASS_CHANGED_CONTRACTED_SUPERINTERFACES_SET, | 
| 205 |                 IApiProblemTypes.CLASS_CHANGED_NON_ABSTRACT_TO_ABSTRACT, | 
| 206 |                 IApiProblemTypes.CLASS_CHANGED_NON_FINAL_TO_FINAL, | 
| 207 |                 IApiProblemTypes.CLASS_CHANGED_TYPE_CONVERSION, | 
| 208 |                 IApiProblemTypes.CLASS_CHANGED_DECREASE_ACCESS, | 
| 209 |                 IApiProblemTypes.CLASS_REMOVED_FIELD, | 
| 210 |                 IApiProblemTypes.CLASS_REMOVED_METHOD, | 
| 211 |                 IApiProblemTypes.CLASS_REMOVED_CONSTRUCTOR, | 
| 212 |                 IApiProblemTypes.CLASS_REMOVED_SUPERCLASS, | 
| 213 |                 IApiProblemTypes.CLASS_REMOVED_TYPE_MEMBER, | 
| 214 |                 IApiProblemTypes.CLASS_REMOVED_TYPE_PARAMETER, | 
| 215 |                 IApiProblemTypes.FIELD_ADDED_VALUE, | 
| 216 |                 IApiProblemTypes.FIELD_CHANGED_TYPE, | 
| 217 |                 IApiProblemTypes.FIELD_CHANGED_VALUE, | 
| 218 |                 IApiProblemTypes.FIELD_CHANGED_DECREASE_ACCESS, | 
| 219 |                 IApiProblemTypes.FIELD_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT, | 
| 220 |                 IApiProblemTypes.FIELD_CHANGED_NON_FINAL_TO_FINAL, | 
| 221 |                 IApiProblemTypes.FIELD_CHANGED_STATIC_TO_NON_STATIC, | 
| 222 |                 IApiProblemTypes.FIELD_CHANGED_NON_STATIC_TO_STATIC, | 
| 223 |                 IApiProblemTypes.FIELD_REMOVED_VALUE, | 
| 224 |                 IApiProblemTypes.FIELD_REMOVED_TYPE_ARGUMENT, | 
| 225 |                 IApiProblemTypes.METHOD_ADDED_RESTRICTIONS, | 
| 226 |                 IApiProblemTypes.METHOD_ADDED_TYPE_PARAMETER, | 
| 227 |                 IApiProblemTypes.METHOD_CHANGED_VARARGS_TO_ARRAY, | 
| 228 |                 IApiProblemTypes.METHOD_CHANGED_DECREASE_ACCESS, | 
| 229 |                 IApiProblemTypes.METHOD_CHANGED_NON_ABSTRACT_TO_ABSTRACT, | 
| 230 |                 IApiProblemTypes.METHOD_CHANGED_NON_STATIC_TO_STATIC, | 
| 231 |                 IApiProblemTypes.METHOD_CHANGED_STATIC_TO_NON_STATIC, | 
| 232 |                 IApiProblemTypes.METHOD_CHANGED_NON_FINAL_TO_FINAL, | 
| 233 |                 IApiProblemTypes.METHOD_REMOVED_ANNOTATION_DEFAULT_VALUE, | 
| 234 |                 IApiProblemTypes.METHOD_REMOVED_TYPE_PARAMETER, | 
| 235 |                 IApiProblemTypes.CONSTRUCTOR_ADDED_TYPE_PARAMETER, | 
| 236 |                 IApiProblemTypes.CONSTRUCTOR_CHANGED_VARARGS_TO_ARRAY, | 
| 237 |                 IApiProblemTypes.CONSTRUCTOR_CHANGED_DECREASE_ACCESS, | 
| 238 |                 IApiProblemTypes.CONSTRUCTOR_REMOVED_TYPE_PARAMETER, | 
| 239 |                 IApiProblemTypes.TYPE_PARAMETER_ADDED_CLASS_BOUND, | 
| 240 |                 IApiProblemTypes.TYPE_PARAMETER_CHANGED_CLASS_BOUND, | 
| 241 |                 IApiProblemTypes.TYPE_PARAMETER_REMOVED_CLASS_BOUND, | 
| 242 |                 IApiProblemTypes.TYPE_PARAMETER_ADDED_INTERFACE_BOUND, | 
| 243 |                 IApiProblemTypes.TYPE_PARAMETER_CHANGED_INTERFACE_BOUND, | 
| 244 |                 IApiProblemTypes.TYPE_PARAMETER_REMOVED_INTERFACE_BOUND, | 
| 245 |                 IApiProblemTypes.TYPE_PARAMETER_REMOVED_INTERFACE_BOUND, | 
| 246 |                 IApiProblemTypes.REPORT_API_BREAKAGE_WHEN_MAJOR_VERSION_INCREMENTED, | 
| 247 | //                IApiProblemTypes.REPORT_API_CHANGE_WHEN_MINOR_VERSION_INCREMENTED, | 
| 248 |         }; | 
| 249 |         /** | 
| 250 |          * A set of listeners that want to participate in the saving life-cycle of the workbench | 
| 251 |          * via this plugin | 
| 252 |          */ | 
| 253 |         private HashSet savelisteners = new HashSet(); | 
| 254 |          | 
| 255 |         /** | 
| 256 |          * This is used to log resolution errors only once per session | 
| 257 |          */ | 
| 258 |         private int logBits = 0; | 
| 259 |          | 
| 260 |         /** | 
| 261 |          * This is used to log resolution errors only once per session. | 
| 262 |          * This is used outside the workbench. | 
| 263 |          */ | 
| 264 |         private static int LogBits= 0; | 
| 265 |   | 
| 266 |         private static final int RESOLUTION_LOG_BIT = 1; | 
| 267 |         private static final int BASELINE_DISPOSED_LOG_BIT = 2; | 
| 268 |   | 
| 269 |         /** | 
| 270 |          * Constructor | 
| 271 |          */ | 
| 272 |         public ApiPlugin() { | 
| 273 |                 super(); | 
| 274 |                 fgDefault = this; | 
| 275 |         } | 
| 276 |          | 
| 277 |         /** | 
| 278 |          * @return The singleton instance of the plugin | 
| 279 |          */ | 
| 280 |         public static ApiPlugin getDefault() { | 
| 281 |                 return fgDefault; | 
| 282 |         } | 
| 283 |          | 
| 284 |         /** | 
| 285 |          * Logs the specified status with this plug-in's log. | 
| 286 |          *  | 
| 287 |          * @param status status to log | 
| 288 |          */ | 
| 289 |         public static void log(IStatus status) { | 
| 290 |                 ApiPlugin getDefault = getDefault(); | 
| 291 |                 if (getDefault == null) { | 
| 292 |                         switch(status.getCode()) { | 
| 293 |                                 case REPORT_RESOLUTION_ERRORS : | 
| 294 |                                         if ((LogBits & RESOLUTION_LOG_BIT) == 0) { | 
| 295 |                                                 Throwable exception = status.getException(); | 
| 296 |                                                 if (exception != null) { | 
| 297 |                                                         exception.printStackTrace(); | 
| 298 |                                                 } | 
| 299 |                                                 LogBits |= RESOLUTION_LOG_BIT; | 
| 300 |                                         } | 
| 301 |                                         break; | 
| 302 |                                 case REPORT_BASELINE_IS_DISPOSED : | 
| 303 |                                         if ((LogBits & BASELINE_DISPOSED_LOG_BIT) == 0) { | 
| 304 |                                                 Throwable exception = status.getException(); | 
| 305 |                                                 if (exception != null) { | 
| 306 |                                                         exception.printStackTrace(); | 
| 307 |                                                 } | 
| 308 |                                                 LogBits |= BASELINE_DISPOSED_LOG_BIT; | 
| 309 |                                         } | 
| 310 |                                         break; | 
| 311 |                                 default: | 
| 312 |                                         Throwable exception = status.getException(); | 
| 313 |                                         if (exception != null) { | 
| 314 |                                                 exception.printStackTrace(); | 
| 315 |                                         } | 
| 316 |                         } | 
| 317 |                 } else { | 
| 318 |                         switch(status.getCode()) { | 
| 319 |                                 case REPORT_RESOLUTION_ERRORS : | 
| 320 |                                         if ((getDefault.logBits & RESOLUTION_LOG_BIT) == 0) { | 
| 321 |                                                 getDefault.getLog().log(status); | 
| 322 |                                                 getDefault.logBits |= RESOLUTION_LOG_BIT; | 
| 323 |                                         } | 
| 324 |                                         break; | 
| 325 |                                 case REPORT_BASELINE_IS_DISPOSED : | 
| 326 |                                         if ((getDefault.logBits & BASELINE_DISPOSED_LOG_BIT) == 0) { | 
| 327 |                                                 getDefault.getLog().log(status); | 
| 328 |                                                 getDefault.logBits |= BASELINE_DISPOSED_LOG_BIT; | 
| 329 |                                         } | 
| 330 |                                         break; | 
| 331 |                                 default: | 
| 332 |                                         getDefault.getLog().log(status); | 
| 333 |                         } | 
| 334 |                 } | 
| 335 |         } | 
| 336 |   | 
| 337 |         /** | 
| 338 |          * Logs the specified throwable with this plug-in's log. | 
| 339 |          *  | 
| 340 |          * @param t throwable to log  | 
| 341 |          */ | 
| 342 |         public static void log(Throwable t) { | 
| 343 |                 log(newErrorStatus("Error logged from API Tools Core: ", t)); //$NON-NLS-1$ | 
| 344 |         } | 
| 345 |          | 
| 346 |         /** | 
| 347 |          * Logs an internal error with the specified message. | 
| 348 |          *  | 
| 349 |          * @param message the error message to log | 
| 350 |          */ | 
| 351 |         public static void logErrorMessage(String message) { | 
| 352 |                 // this message is intentionally not internationalized, as an exception may | 
| 353 |                 // be due to the resource bundle itself | 
| 354 |                 log(newErrorStatus("Internal message logged from API Tools Core: " + message, null)); //$NON-NLS-1$         | 
| 355 |         } | 
| 356 |          | 
| 357 |         /** | 
| 358 |          * Returns a new error status for this plug-in with the given message | 
| 359 |          * @param message the message to be included in the status | 
| 360 |          * @param exception the exception to be included in the status or <code>null</code> if none | 
| 361 |          * @return a new error status | 
| 362 |          */ | 
| 363 |         public static IStatus newErrorStatus(String message, Throwable exception) { | 
| 364 |                 return new Status(IStatus.ERROR, PLUGIN_ID, INTERNAL_ERROR, message, exception); | 
| 365 |         } | 
| 366 |          | 
| 367 |         /** | 
| 368 |          * Returns whether the API tools bundle is running inside an OSGi framework. | 
| 369 |          *  | 
| 370 |          * @return whether the API tools bundle is running inside an OSGi framework | 
| 371 |          */ | 
| 372 |         public static boolean isRunningInFramework() { | 
| 373 |                 return fgDefault != null; | 
| 374 |         } | 
| 375 |   | 
| 376 |         /** | 
| 377 |          * Returns the {@link IApiBaselineManager}, allowing clients to add/remove and search | 
| 378 |          * for {@link org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline}s stored in the manager. | 
| 379 |          *  | 
| 380 |          * @return the singleton instance of the {@link IApiProfileManager} | 
| 381 |          */ | 
| 382 |         public IApiBaselineManager getApiBaselineManager() { | 
| 383 |                 return ApiBaselineManager.getManager(); | 
| 384 |         } | 
| 385 |          | 
| 386 |         /** | 
| 387 |          * @return The singleton instance of the {@link JavadocTagManager} | 
| 388 |          */ | 
| 389 |         public static JavadocTagManager getJavadocTagManager() { | 
| 390 |                 if(fgTagManager == null) { | 
| 391 |                         fgTagManager = new JavadocTagManager(); | 
| 392 |                 } | 
| 393 |                 return fgTagManager; | 
| 394 |         } | 
| 395 |          | 
| 396 |         /** | 
| 397 |          * Adds the given save participant to the listing of participants to  | 
| 398 |          * be notified when the workbench saving life-cycle occurs. If the specified | 
| 399 |          * participant is <code>null</code> no changes are made. | 
| 400 |          * @param participant | 
| 401 |          */ | 
| 402 |         public void addSaveParticipant(ISaveParticipant participant) { | 
| 403 |                 if(participant != null) { | 
| 404 |                         savelisteners.add(participant); | 
| 405 |                 } | 
| 406 |         } | 
| 407 |          | 
| 408 |         /** | 
| 409 |          * Removes the given save participant from the current listing. | 
| 410 |          * If the specified participant is <code>null</code> no changes are made. | 
| 411 |          * @param participant | 
| 412 |          */ | 
| 413 |         public void removeSaveParticipant(ISaveParticipant participant) { | 
| 414 |                 if(participant != null) { | 
| 415 |                         savelisteners.remove(participant); | 
| 416 |                 } | 
| 417 |         } | 
| 418 |          | 
| 419 |         /* (non-Javadoc) | 
| 420 |          * @see org.eclipse.core.resources.ISaveParticipant#doneSaving(org.eclipse.core.resources.ISaveContext) | 
| 421 |          */ | 
| 422 |         public void doneSaving(ISaveContext context) { | 
| 423 |                 ISaveParticipant sp = null; | 
| 424 |                 for(Iterator iter = savelisteners.iterator(); iter.hasNext();) { | 
| 425 |                         sp = (ISaveParticipant) iter.next(); | 
| 426 |                         sp.doneSaving(context); | 
| 427 |                 } | 
| 428 |         } | 
| 429 |   | 
| 430 |         /* (non-Javadoc) | 
| 431 |          * @see org.eclipse.core.resources.ISaveParticipant#prepareToSave(org.eclipse.core.resources.ISaveContext) | 
| 432 |          */ | 
| 433 |         public void prepareToSave(ISaveContext context) throws CoreException { | 
| 434 |                 ISaveParticipant sp = null; | 
| 435 |                 for(Iterator iter = savelisteners.iterator(); iter.hasNext();) { | 
| 436 |                         sp = (ISaveParticipant) iter.next(); | 
| 437 |                         sp.prepareToSave(context); | 
| 438 |                 } | 
| 439 |         } | 
| 440 |   | 
| 441 |         /* (non-Javadoc) | 
| 442 |          * @see org.eclipse.core.resources.ISaveParticipant#rollback(org.eclipse.core.resources.ISaveContext) | 
| 443 |          */ | 
| 444 |         public void rollback(ISaveContext context) { | 
| 445 |                 ISaveParticipant sp = null; | 
| 446 |                 for(Iterator iter = savelisteners.iterator(); iter.hasNext();) { | 
| 447 |                         sp = (ISaveParticipant) iter.next(); | 
| 448 |                         sp.rollback(context); | 
| 449 |                 } | 
| 450 |         } | 
| 451 |   | 
| 452 |         /* (non-Javadoc) | 
| 453 |          * @see org.eclipse.core.resources.ISaveParticipant#saving(org.eclipse.core.resources.ISaveContext) | 
| 454 |          */ | 
| 455 |         public void saving(ISaveContext context) throws CoreException { | 
| 456 |                 if(context.getKind() == ISaveContext.FULL_SAVE) { | 
| 457 |                         context.needDelta(); | 
| 458 |                 } | 
| 459 |                 ISaveParticipant sp = null; | 
| 460 |                 for(Iterator iter = savelisteners.iterator(); iter.hasNext();) { | 
| 461 |                         sp = (ISaveParticipant) iter.next(); | 
| 462 |                         sp.saving(context); | 
| 463 |                 } | 
| 464 |                 IEclipsePreferences node = new InstanceScope().getNode(PLUGIN_ID); | 
| 465 |                 if(node != null) { | 
| 466 |                         try { | 
| 467 |                                 node.flush(); | 
| 468 |                         } catch (BackingStoreException e) { | 
| 469 |                                 log(e); | 
| 470 |                         } | 
| 471 |                 } | 
| 472 |         } | 
| 473 |          | 
| 474 |         /* (non-Javadoc) | 
| 475 |          * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext) | 
| 476 |          */ | 
| 477 |         public void start(BundleContext context) throws Exception { | 
| 478 |                 try { | 
| 479 |                         super.start(context); | 
| 480 |                 } finally { | 
| 481 |                         ResourcesPlugin.getWorkspace().addSaveParticipant(this, this); | 
| 482 |                         configurePluginDebugOptions(); | 
| 483 |                 } | 
| 484 |         } | 
| 485 |          | 
| 486 |         /* (non-Javadoc) | 
| 487 |          * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) | 
| 488 |          */ | 
| 489 |         public void stop(BundleContext context) throws Exception { | 
| 490 |                 try { | 
| 491 |                         ApiDescriptionManager.shutdown(); | 
| 492 |                         ApiBaselineManager.getManager().stop(); | 
| 493 |                         ResourcesPlugin.getWorkspace().removeSaveParticipant(this); | 
| 494 |                         FileManager.getManager().deleteFiles(); | 
| 495 |                 } | 
| 496 |                 finally { | 
| 497 |                         super.stop(context); | 
| 498 |                 } | 
| 499 |         } | 
| 500 |   | 
| 501 |         /** | 
| 502 |          * Returns the severity for the specific key from the given {@link IProject}. | 
| 503 |          * If the project does not have project specific settings, the workspace preference | 
| 504 |          * is returned. If <code>null</code> is passed in as the project the workspace | 
| 505 |          * preferences are consulted. | 
| 506 |          *  | 
| 507 |          * @param prefkey the given preference key | 
| 508 |          * @param project the given project or <code>null</code> | 
| 509 |          * @return the severity level for the given pref key | 
| 510 |          */ | 
| 511 |         public int getSeverityLevel(String prefkey, IProject project) { | 
| 512 |                 IPreferencesService service = Platform.getPreferencesService(); | 
| 513 |                 List scopes = new ArrayList(); | 
| 514 |                 scopes.add(new InstanceScope()); | 
| 515 |                 if(project != null) { | 
| 516 |                         scopes.add(new ProjectScope(project)); | 
| 517 |                 } | 
| 518 |                 String value = service.getString(PLUGIN_ID, prefkey, null, (IScopeContext[]) scopes.toArray(new IScopeContext[scopes.size()])); | 
| 519 |                 if(value == null) { | 
| 520 |                         value = service.getString(PLUGIN_ID, prefkey, VALUE_IGNORE, new IScopeContext[]{new DefaultScope()}); | 
| 521 |                 } | 
| 522 |                 if(VALUE_ERROR.equals(value)) { | 
| 523 |                         return SEVERITY_ERROR; | 
| 524 |                 } | 
| 525 |                 if(VALUE_WARNING.equals(value)) { | 
| 526 |                         return SEVERITY_WARNING; | 
| 527 |                 } | 
| 528 |                 return SEVERITY_IGNORE; | 
| 529 |         } | 
| 530 |          | 
| 531 |         public ISessionManager getSessionManager() { | 
| 532 |                 if(fgSessionManager == null) { | 
| 533 |                         fgSessionManager = new SessionManager(); | 
| 534 |                 } | 
| 535 |                 return fgSessionManager; | 
| 536 |         } | 
| 537 |   | 
| 538 |         /** | 
| 539 |          * Returns the enable state for the specific key from the given {@link IProject}. | 
| 540 |          * If the project does not have project specific settings, the workspace preference | 
| 541 |          * is returned. If <code>null</code> is passed in as the project the workspace | 
| 542 |          * preferences are consulted. | 
| 543 |          *  | 
| 544 |          * @param prefkey the given preference key | 
| 545 |          * @param project the given project or <code>null</code> | 
| 546 |          * @return the enable state | 
| 547 |          */ | 
| 548 |         public String getEnableState(String prefkey, IProject project) { | 
| 549 |                 IPreferencesService service = Platform.getPreferencesService(); | 
| 550 |                 List scopes = new ArrayList(); | 
| 551 |                 scopes.add(new InstanceScope()); | 
| 552 |                 if(project != null) { | 
| 553 |                         scopes.add(new ProjectScope(project)); | 
| 554 |                 } | 
| 555 |                 String value = service.getString(PLUGIN_ID, prefkey, null, (IScopeContext[]) scopes.toArray(new IScopeContext[scopes.size()])); | 
| 556 |                 if(value == null) { | 
| 557 |                         value = service.getString(PLUGIN_ID, prefkey, VALUE_DISABLED, new IScopeContext[]{new DefaultScope()});  | 
| 558 |                 } | 
| 559 |                 return value; | 
| 560 |         } | 
| 561 |         /** | 
| 562 |          * Method to configure all of the debug options for this plugin | 
| 563 |          */ | 
| 564 |         public void configurePluginDebugOptions(){ | 
| 565 |                 if(ApiPlugin.getDefault().isDebugging()){ | 
| 566 |                         String option = Platform.getDebugOption(BUILDER_DEBUG); | 
| 567 |                         if(option != null) { | 
| 568 |                                 ApiAnalysisBuilder.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 569 |                         } | 
| 570 |                         option = Platform.getDebugOption(DELTA_DEBUG); | 
| 571 |                         if(option != null) { | 
| 572 |                                 boolean debugValue = option.equalsIgnoreCase(TRUE); | 
| 573 |                                 ClassFileComparator.setDebug(debugValue); | 
| 574 |                                 ApiComparator.setDebug(debugValue); | 
| 575 |                         } | 
| 576 |                         option = Platform.getDebugOption(CLASSFILE_VISITOR_DEBUG); | 
| 577 |                         if(option != null) { | 
| 578 |                                 ReferenceExtractor.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 579 |                         } | 
| 580 |                         option = Platform.getDebugOption(DESCRIPTOR_FRAMEWORK_DEBUG); | 
| 581 |                         if(option != null) { | 
| 582 |                                 ElementDescriptorImpl.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 583 |                         } | 
| 584 |                         option = Platform.getDebugOption(TAG_SCANNER_DEBUG); | 
| 585 |                         if(option != null) { | 
| 586 |                                 TagScanner.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 587 |                         } | 
| 588 |                         option = Platform.getDebugOption(PLUGIN_WORKSPACE_COMPONENT_DEBUG); | 
| 589 |                         if(option != null) { | 
| 590 |                                 PluginProjectApiComponent.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 591 |                         } | 
| 592 |                         option = Platform.getDebugOption(API_PROFILE_MANAGER_DEBUG); | 
| 593 |                         if(option != null) { | 
| 594 |                                 ApiBaselineManager.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 595 |                         } | 
| 596 |                         option = Platform.getDebugOption(API_FILTER_STORE_DEBUG); | 
| 597 |                         if(option != null) { | 
| 598 |                                 ApiFilterStore.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 599 |                         } | 
| 600 |                         option = Platform.getDebugOption(API_REFERENCE_ANALYZER_DEBUG); | 
| 601 |                         if(option != null) { | 
| 602 |                                 ReferenceAnalyzer.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 603 |                         } | 
| 604 |                         option = Platform.getDebugOption(REFERENCE_RESOLVER_DEBUG); | 
| 605 |                         if(option != null) { | 
| 606 |                                 ReferenceResolver.setDebug(option.equalsIgnoreCase(TRUE)); | 
| 607 |                         } | 
| 608 |                         option = Platform.getDebugOption(PROBLEM_DETECTOR_DEBUG); | 
| 609 |                         if(option != null) { | 
| 610 |                                 AbstractProblemDetector.setDebug(option.equals(TRUE)); | 
| 611 |                         } | 
| 612 |                         option = Platform.getDebugOption(API_DESCRIPTION); | 
| 613 |                         if(option != null) { | 
| 614 |                                 ApiDescription.setDebug(option.equals(TRUE)); | 
| 615 |                         } | 
| 616 |                 } | 
| 617 |         } | 
| 618 | } |