blob: f2b19873e0583aa9dd98e26742021b8526d05c5a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2016 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.api.tools.internal.provisional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.ISaveContext;
import org.eclipse.core.resources.ISaveParticipant;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.osgi.service.debug.DebugOptions;
import org.eclipse.osgi.service.debug.DebugOptionsListener;
import org.eclipse.pde.api.tools.internal.ApiBaselineManager;
import org.eclipse.pde.api.tools.internal.ApiDescriptionManager;
import org.eclipse.pde.api.tools.internal.JavadocTagManager;
import org.eclipse.pde.api.tools.internal.SessionManager;
import org.eclipse.pde.api.tools.internal.WorkspaceDeltaProcessor;
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes;
import org.eclipse.pde.api.tools.internal.util.FileManager;
import org.eclipse.pde.api.tools.internal.util.Util;
import org.eclipse.pde.core.target.NameVersionDescriptor;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.prefs.BackingStoreException;
/**
* API Tools core plug-in. API tools can be run with or without an OSGi
* framework.
*
* @since 1.0.0
*/
public class ApiPlugin extends Plugin implements ISaveParticipant, DebugOptionsListener {
/**
* Constant representing the expected name for an execution environment
* description fragment Value is <code>org.eclipse.pde.api.tools.ee"
*/
private static final String EE_DESCRIPTION_PREFIX = "org.eclipse.pde.api.tools.ee"; //$NON-NLS-1$
/**
* Constant representing the name of the javadoc tag extension point. Value
* is <code>apiJavadocTags</code>
*/
public static final String EXTENSION_JAVADOC_TAGS = "apiJavadocTags"; //$NON-NLS-1$
/**
* The plug-in identifier of the PDE API tool support (value
* <code>"org.eclipse.pde.api.tools"</code>).
*/
public static final String PLUGIN_ID = "org.eclipse.pde.api.tools"; //$NON-NLS-1$
/**
* The API Tools nature id (value
* <code>"org.eclipse.pde.api.tools.apiAnalysisNature"</code>).
*/
public static final String NATURE_ID = PLUGIN_ID + ".apiAnalysisNature"; //$NON-NLS-1$
/**
* Status code indicating an unexpected internal error.
*/
public static final int INTERNAL_ERROR = 120;
/**
* Status code indicating an unexpected error
*/
public static final int ERROR = 121;
/**
* Status code indicating a resolution error
*/
public static final int REPORT_RESOLUTION_ERRORS = 122;
/**
* Status code indicating that a baseline is disposed
*/
public static final int REPORT_BASELINE_IS_DISPOSED = 123;
/**
* Constant representing severity levels for error/warning preferences Value
* is: <code>0</code>
*/
public static final int SEVERITY_IGNORE = 0;
/**
* Constant representing severity levels for error/warning preferences Value
* is: <code>1</code>
*/
public static final int SEVERITY_WARNING = 1;
/**
* Constant representing severity levels for error/warning preferences Value
* is: <code>2</code>
*/
public static final int SEVERITY_ERROR = 2;
/**
* Constant representing the preference value 'ignore'. Value is:
* <code>Ignore</code>
*/
public static final String VALUE_IGNORE = "Ignore"; //$NON-NLS-1$
/**
* Constant representing the preference value 'warning'. Value is:
* <code>Warning</code>
*/
public static final String VALUE_WARNING = "Warning"; //$NON-NLS-1$
/**
* Constant representing the preference value 'error'. Value is:
* <code>Error</code>
*/
public static final String VALUE_ERROR = "Error"; //$NON-NLS-1$
/**
* Constant representing the preference value 'disabled'. Value is:
* <code>Disabled</code>
*/
public static final String VALUE_DISABLED = "Disabled"; //$NON-NLS-1$
/**
* Constant representing the preference value 'enabled'. Value is:
* <code>Enabled</code>
*/
public static final String VALUE_ENABLED = "Enabled"; //$NON-NLS-1$
/**
* The identifier for the API builder Value is:
* <code>"org.eclipse.pde.api.tools.apiAnalysisBuilder"</code>
*/
public static final String BUILDER_ID = PLUGIN_ID + ".apiAnalysisBuilder"; //$NON-NLS-1$
/**
* Preference ID for a knownEEFragments of EE fragments that were previously
* installed, the stored preference string must be a list of name followed
* by version separated by semicolons ';'.
* <p>
* ex: "org.eclipse.one;1.0.0;org.eclipse.two;2.0.0;"
* </p>
* <p>
* Value is: <code>knownEEFragments</code>
* </p>
*/
public static final String KNOWN_EE_FRAGMENTS = "knownEEFragments"; //$NON-NLS-1$
/**
* Singleton instance of the plugin
*/
private static ApiPlugin fgDefault = null;
/**
* Singleton instance of the {@link JavadocTagManager}
*/
private static JavadocTagManager fgTagManager = null;
/**
* Singleton instance of the {@link ISessionManager}
*/
private static ISessionManager fgSessionManager = null;
/**
* This bundle's OSGi context
*/
private BundleContext fBundleContext = null;
private static boolean DEBUG = false;
/**
* Private debug options
*/
private static final String DEBUG_FLAG = PLUGIN_ID + "/debug"; //$NON-NLS-1$
private static final String BUILDER_DEBUG = PLUGIN_ID + "/debug/builder"; //$NON-NLS-1$
private static final String DELTA_DEBUG = PLUGIN_ID + "/debug/delta"; //$NON-NLS-1$
private static final String SEARCH_DEBUG = PLUGIN_ID + "/debug/search"; //$NON-NLS-1$
private static final String CLASSFILE_VISITOR_DEBUG = PLUGIN_ID + "/debug/classfilevisitor"; //$NON-NLS-1$
private static final String DESCRIPTOR_FRAMEWORK_DEBUG = PLUGIN_ID + "/debug/descriptor/framework"; //$NON-NLS-1$
private static final String TAG_SCANNER_DEBUG = PLUGIN_ID + "/debug/tagscanner"; //$NON-NLS-1$
private static final String PLUGIN_WORKSPACE_COMPONENT_DEBUG = PLUGIN_ID + "/debug/pluginworkspacecomponent"; //$NON-NLS-1$
private static final String API_PROFILE_MANAGER_DEBUG = PLUGIN_ID + "/debug/profilemanager"; //$NON-NLS-1$
private static final String API_FILTER_STORE_DEBUG = PLUGIN_ID + "/debug/apifilterstore"; //$NON-NLS-1$
private static final String API_REFERENCE_ANALYZER_DEBUG = PLUGIN_ID + "/debug/refanalyzer"; //$NON-NLS-1$
private static final String PROBLEM_DETECTOR_DEBUG = PLUGIN_ID + "/debug/problemdetector"; //$NON-NLS-1$
private static final String REFERENCE_RESOLVER_DEBUG = PLUGIN_ID + "/debug/refresolver"; //$NON-NLS-1$
private static final String API_DESCRIPTION = PLUGIN_ID + "/debug/apidescription"; //$NON-NLS-1$
private static final String WORKSPACE_DELTA_PROCESSOR = PLUGIN_ID + "/debug/workspacedeltaprocessor"; //$NON-NLS-1$
private static final String API_ANALYZER_DEBUG = PLUGIN_ID + "/debug/apianalyzer"; //$NON-NLS-1$
private static final String USE_REPORT_CONVERTER_DEBUG = PLUGIN_ID + "/debug/usereportconverter"; //$NON-NLS-1$
/**
* Constant used for controlling tracing in the report converter
*/
public static boolean DEBUG_USE_REPORT_CONVERTER = false;
/**
* Constant used for controlling tracing in the search engine
*/
public static boolean DEBUG_SEARCH_ENGINE = false;
/**
* Constant used for controlling tracing in the scanner
*/
public static boolean DEBUG_TAG_SCANNER = false;
/**
* Constant used for controlling tracing in the API comparator
*/
public static boolean DEBUG_API_COMPARATOR = false;
/**
* Constant used for controlling tracing in the plug-in workspace component
*/
public static boolean DEBUG_PROJECT_COMPONENT = false;
/**
* Constant used for controlling tracing in the descriptor framework
*/
public static boolean DEBUG_ELEMENT_DESCRIPTOR_FRAMEWORK = false;
/**
* Constant used for controlling tracing in the class file comparator
*/
public static boolean DEBUG_CLASSFILE_COMPARATOR = false;
/**
* Constant used for controlling tracing in the search engine
*/
public static boolean DEBUG_REFERENCE_RESOLVER = false;
/**
* Constant used for controlling tracing in the visitor
*/
public static boolean DEBUG_REFERENCE_EXTRACTOR = false;
/**
* Constant used for controlling tracing in the search engine
*/
public static boolean DEBUG_REFERENCE_ANALYZER = false;
/**
* Constant used for controlling tracing in the API tool builder
*/
public static boolean DEBUG_API_ANALYZER = false;
/**
* Constant used for controlling tracing in the problem detectors
*/
public static boolean DEBUG_PROBLEM_DETECTOR = false;
/**
* Constant used for controlling tracing in the API tool builder
*/
public static boolean DEBUG_WORKSPACE_DELTA_PROCESSOR = false;
/**
* Constant used for controlling tracing in the plug-in workspace component
*/
public static boolean DEBUG_FILTER_STORE = false;
/**
* Constant used for controlling tracing in the API descriptions
*/
public static boolean DEBUG_API_DESCRIPTION = false;
/**
* Constant used for controlling tracing in the API tool builder
*/
public static boolean DEBUG_BASELINE_MANAGER = false;
/**
* Constant used for controlling tracing in the API tool builder
*/
public static boolean DEBUG_BUILDER = false;
public static String[] AllCompatibilityKeys = new String[] {
IApiProblemTypes.API_COMPONENT_REMOVED_TYPE,
IApiProblemTypes.API_COMPONENT_REMOVED_API_TYPE,
IApiProblemTypes.API_COMPONENT_REMOVED_REEXPORTED_TYPE,
IApiProblemTypes.API_COMPONENT_REMOVED_REEXPORTED_API_TYPE,
IApiProblemTypes.ANNOTATION_REMOVED_FIELD,
IApiProblemTypes.ANNOTATION_REMOVED_METHOD,
IApiProblemTypes.ANNOTATION_REMOVED_TYPE_MEMBER,
IApiProblemTypes.ANNOTATION_CHANGED_TYPE_CONVERSION,
IApiProblemTypes.ANNOTATION_ADDED_METHOD_NO_DEFAULT_VALUE,
IApiProblemTypes.INTERFACE_ADDED_FIELD,
IApiProblemTypes.INTERFACE_ADDED_METHOD,
IApiProblemTypes.INTERFACE_ADDED_DEFAULT_METHOD,
IApiProblemTypes.INTERFACE_ADDED_RESTRICTIONS,
IApiProblemTypes.INTERFACE_ADDED_SUPER_INTERFACE_WITH_METHODS,
IApiProblemTypes.INTERFACE_ADDED_TYPE_PARAMETER,
IApiProblemTypes.INTERFACE_REMOVED_TYPE_PARAMETER,
IApiProblemTypes.INTERFACE_REMOVED_FIELD,
IApiProblemTypes.INTERFACE_REMOVED_METHOD,
IApiProblemTypes.INTERFACE_REMOVED_TYPE_MEMBER,
IApiProblemTypes.INTERFACE_CHANGED_TYPE_CONVERSION,
IApiProblemTypes.INTERFACE_CHANGED_CONTRACTED_SUPERINTERFACES_SET,
IApiProblemTypes.ENUM_CHANGED_CONTRACTED_SUPERINTERFACES_SET,
IApiProblemTypes.ENUM_CHANGED_TYPE_CONVERSION,
IApiProblemTypes.ENUM_REMOVED_FIELD,
IApiProblemTypes.ENUM_REMOVED_ENUM_CONSTANT,
IApiProblemTypes.ENUM_REMOVED_METHOD,
IApiProblemTypes.ENUM_REMOVED_TYPE_MEMBER,
IApiProblemTypes.CLASS_ADDED_METHOD,
IApiProblemTypes.CLASS_ADDED_RESTRICTIONS,
IApiProblemTypes.CLASS_ADDED_TYPE_PARAMETER,
IApiProblemTypes.CLASS_CHANGED_CONTRACTED_SUPERINTERFACES_SET,
IApiProblemTypes.CLASS_CHANGED_NON_ABSTRACT_TO_ABSTRACT,
IApiProblemTypes.CLASS_CHANGED_NON_FINAL_TO_FINAL,
IApiProblemTypes.CLASS_CHANGED_TYPE_CONVERSION,
IApiProblemTypes.CLASS_CHANGED_DECREASE_ACCESS,
IApiProblemTypes.CLASS_REMOVED_FIELD,
IApiProblemTypes.CLASS_REMOVED_METHOD,
IApiProblemTypes.CLASS_REMOVED_CONSTRUCTOR,
IApiProblemTypes.CLASS_REMOVED_SUPERCLASS,
IApiProblemTypes.CLASS_REMOVED_TYPE_MEMBER,
IApiProblemTypes.CLASS_REMOVED_TYPE_PARAMETER,
IApiProblemTypes.FIELD_ADDED_VALUE,
IApiProblemTypes.FIELD_CHANGED_TYPE,
IApiProblemTypes.FIELD_CHANGED_VALUE,
IApiProblemTypes.FIELD_CHANGED_DECREASE_ACCESS,
IApiProblemTypes.FIELD_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT,
IApiProblemTypes.FIELD_CHANGED_NON_FINAL_TO_FINAL,
IApiProblemTypes.FIELD_CHANGED_STATIC_TO_NON_STATIC,
IApiProblemTypes.FIELD_CHANGED_NON_STATIC_TO_STATIC,
IApiProblemTypes.FIELD_REMOVED_VALUE,
IApiProblemTypes.FIELD_REMOVED_TYPE_ARGUMENT,
IApiProblemTypes.METHOD_ADDED_RESTRICTIONS,
IApiProblemTypes.METHOD_ADDED_TYPE_PARAMETER,
IApiProblemTypes.METHOD_CHANGED_VARARGS_TO_ARRAY,
IApiProblemTypes.METHOD_CHANGED_DECREASE_ACCESS,
IApiProblemTypes.METHOD_CHANGED_NON_ABSTRACT_TO_ABSTRACT,
IApiProblemTypes.METHOD_CHANGED_NON_STATIC_TO_STATIC,
IApiProblemTypes.METHOD_CHANGED_STATIC_TO_NON_STATIC,
IApiProblemTypes.METHOD_CHANGED_NON_FINAL_TO_FINAL,
IApiProblemTypes.METHOD_REMOVED_ANNOTATION_DEFAULT_VALUE,
IApiProblemTypes.METHOD_REMOVED_TYPE_PARAMETER,
IApiProblemTypes.CONSTRUCTOR_ADDED_TYPE_PARAMETER,
IApiProblemTypes.CONSTRUCTOR_CHANGED_VARARGS_TO_ARRAY,
IApiProblemTypes.CONSTRUCTOR_CHANGED_DECREASE_ACCESS,
IApiProblemTypes.CONSTRUCTOR_REMOVED_TYPE_PARAMETER,
IApiProblemTypes.TYPE_PARAMETER_ADDED_CLASS_BOUND,
IApiProblemTypes.TYPE_PARAMETER_CHANGED_CLASS_BOUND,
IApiProblemTypes.TYPE_PARAMETER_REMOVED_CLASS_BOUND,
IApiProblemTypes.TYPE_PARAMETER_ADDED_INTERFACE_BOUND,
IApiProblemTypes.TYPE_PARAMETER_CHANGED_INTERFACE_BOUND,
IApiProblemTypes.TYPE_PARAMETER_REMOVED_INTERFACE_BOUND,
IApiProblemTypes.TYPE_PARAMETER_REMOVED_INTERFACE_BOUND,
IApiProblemTypes.REPORT_API_BREAKAGE_WHEN_MAJOR_VERSION_INCREMENTED,
// IApiProblemTypes.REPORT_API_CHANGE_WHEN_MINOR_VERSION_INCREMENTED,
};
/**
* A set of listeners that want to participate in the saving life-cycle of
* the workbench via this plug-in
*/
private HashSet<ISaveParticipant> savelisteners = new HashSet<>();
/**
* This is used to log resolution errors only once per session
*/
private int logBits = 0;
/**
* This is used to log resolution errors only once per session. This is used
* outside the workbench.
*/
private static int LogBits = 0;
/**
* Standard delta processor for Java element changes
*/
private WorkspaceDeltaProcessor deltaProcessor = null;
private static final int RESOLUTION_LOG_BIT = 1;
private static final int BASELINE_DISPOSED_LOG_BIT = 2;
/**
* Constructor
*/
public ApiPlugin() {
super();
fgDefault = this;
}
/**
* @return The singleton instance of the plugin
*/
public static ApiPlugin getDefault() {
return fgDefault;
}
/**
* Logs the specified status with this plug-in's log.
*
* @param status status to log
*/
public static void log(IStatus status) {
ApiPlugin getDefault = getDefault();
if (getDefault == null) {
switch (status.getCode()) {
case REPORT_RESOLUTION_ERRORS:
if ((LogBits & RESOLUTION_LOG_BIT) == 0) {
Throwable exception = status.getException();
if (exception != null) {
exception.printStackTrace();
}
LogBits |= RESOLUTION_LOG_BIT;
}
break;
case REPORT_BASELINE_IS_DISPOSED:
if ((LogBits & BASELINE_DISPOSED_LOG_BIT) == 0) {
Throwable exception = status.getException();
if (exception != null) {
exception.printStackTrace();
}
LogBits |= BASELINE_DISPOSED_LOG_BIT;
}
break;
default:
Throwable exception = status.getException();
if (exception != null) {
exception.printStackTrace();
}
}
} else {
switch (status.getCode()) {
case REPORT_RESOLUTION_ERRORS:
if ((getDefault.logBits & RESOLUTION_LOG_BIT) == 0) {
getDefault.getLog().log(status);
getDefault.logBits |= RESOLUTION_LOG_BIT;
}
break;
case REPORT_BASELINE_IS_DISPOSED:
if ((getDefault.logBits & BASELINE_DISPOSED_LOG_BIT) == 0) {
getDefault.getLog().log(status);
getDefault.logBits |= BASELINE_DISPOSED_LOG_BIT;
}
break;
default:
getDefault.getLog().log(status);
}
}
}
/**
* Logs the specified throwable with this plug-in's log.
*
* @param t throwable to log
*/
public static void log(Throwable t) {
log(newErrorStatus("Error logged from API Tools Core: ", t)); //$NON-NLS-1$
}
/**
* Logs an internal error with the specified message.
*
* @param message the error message to log
*/
public static void logErrorMessage(String message) {
// this message is intentionally not internationalized, as an exception
// may
// be due to the resource bundle itself
log(newErrorStatus("Internal message logged from API Tools Core: " + message, null)); //$NON-NLS-1$
}
/**
* Returns a new error status for this plug-in with the given message
*
* @param message the message to be included in the status
* @param exception the exception to be included in the status or
* <code>null</code> if none
* @return a new error status
*/
public static IStatus newErrorStatus(String message, Throwable exception) {
return new Status(IStatus.ERROR, PLUGIN_ID, INTERNAL_ERROR, message, exception);
}
/**
* Returns whether the API tools bundle is running inside an OSGi framework.
*
* @return whether the API tools bundle is running inside an OSGi framework
*/
public static boolean isRunningInFramework() {
return fgDefault != null;
}
/**
* Returns the {@link IApiBaselineManager}, allowing clients to add/remove
* and search for
* {@link org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline}
* s stored in the manager.
*
* @return the singleton instance of the {@link IApiProfileManager}
*/
public IApiBaselineManager getApiBaselineManager() {
return ApiBaselineManager.getManager();
}
/**
* @return The singleton instance of the {@link JavadocTagManager}
*/
public static JavadocTagManager getJavadocTagManager() {
if (fgTagManager == null) {
fgTagManager = new JavadocTagManager();
}
return fgTagManager;
}
/**
* Adds the given save participant to the listing of participants to be
* notified when the workbench saving life-cycle occurs. If the specified
* participant is <code>null</code> no changes are made.
*
* @param participant
*/
public void addSaveParticipant(ISaveParticipant participant) {
if (participant != null) {
savelisteners.add(participant);
}
}
/**
* Removes the given save participant from the current listing. If the
* specified participant is <code>null</code> no changes are made.
*
* @param participant
*/
public void removeSaveParticipant(ISaveParticipant participant) {
if (participant != null) {
savelisteners.remove(participant);
}
}
@Override
public void doneSaving(ISaveContext context) {
for (ISaveParticipant sp : savelisteners) {
sp.doneSaving(context);
}
}
@Override
public void prepareToSave(ISaveContext context) throws CoreException {
for (ISaveParticipant sp : savelisteners) {
sp.prepareToSave(context);
}
}
@Override
public void rollback(ISaveContext context) {
for (ISaveParticipant sp : savelisteners) {
sp.rollback(context);
}
}
@Override
public void saving(ISaveContext context) throws CoreException {
for (ISaveParticipant sp : savelisteners) {
sp.saving(context);
}
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(PLUGIN_ID);
if (node != null) {
try {
node.flush();
} catch (BackingStoreException e) {
log(e);
}
}
}
@Override
public void start(BundleContext context) throws Exception {
try {
super.start(context);
Hashtable<String, String> props = new Hashtable<>(2);
props.put(org.eclipse.osgi.service.debug.DebugOptions.LISTENER_SYMBOLICNAME, PLUGIN_ID);
context.registerService(DebugOptionsListener.class.getName(), this, props);
} finally {
ResourcesPlugin.getWorkspace().addSaveParticipant(PLUGIN_ID, this);
fBundleContext = context;
deltaProcessor = new WorkspaceDeltaProcessor();
JavaCore.addElementChangedListener(deltaProcessor, ElementChangedEvent.POST_CHANGE);
ResourcesPlugin.getWorkspace().addResourceChangeListener(deltaProcessor, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_BUILD);
checkForEEDescriptionChanges();
}
}
/**
* Checks if the current set of installed execution environment description
* fragments differs from the last time this workspace was started. If so, a
* full api analysis build is run.
*/
private void checkForEEDescriptionChanges() {
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(PLUGIN_ID);
if (node == null) {
return;
}
String knownFragmentsList = node.get(KNOWN_EE_FRAGMENTS, null);
Bundle[] allFragments = Platform.getFragments(fBundleContext.getBundle());
if (allFragments == null) {
allFragments = new Bundle[0];
}
// No preference stored yet, set the preference for future startup
if (knownFragmentsList == null) {
String list = getListOfEEFragments(allFragments);
node.put(KNOWN_EE_FRAGMENTS, list);
try {
node.flush();
} catch (BackingStoreException e) {
log(e);
}
return;
}
// Break the list into a set we can search
Set<NameVersionDescriptor> knownFragments = new HashSet<>();
StringTokenizer tokenizer = new StringTokenizer(knownFragmentsList, ";"); //$NON-NLS-1$
String name = null;
while (tokenizer.hasMoreTokens()) {
name = tokenizer.nextToken().trim();
if (name.length() > 0 && tokenizer.hasMoreTokens()) {
knownFragments.add(new NameVersionDescriptor(name, tokenizer.nextToken()));
}
}
// Figure out if we need to rebuild (fragments added or removed
boolean mustRebuild = false;
for (Bundle allFragment : allFragments) {
// We only care about
if (allFragment.getSymbolicName().indexOf(EE_DESCRIPTION_PREFIX) >= 0) {
NameVersionDescriptor current = new NameVersionDescriptor(allFragment.getSymbolicName(), allFragment.getVersion().toString());
if (knownFragments.contains(current)) {
knownFragments.remove(current);
} else {
// New EE fragment installed
mustRebuild = true;
break;
}
}
}
if (knownFragments.size() > 0) {
// EE fragment removed
mustRebuild = true;
}
// Run a full api analysis build and update the preference
if (mustRebuild) {
IProject[] projects = Util.getApiProjects();
if (projects != null) {
for (IProject project : projects) {
try {
project.build(IncrementalProjectBuilder.FULL_BUILD, ApiPlugin.BUILDER_ID, null, null);
} catch (CoreException e) {
log(e.getStatus());
}
}
}
// Write out the preferences so we don't rebuild on next startup
String list = getListOfEEFragments(allFragments);
node.put(KNOWN_EE_FRAGMENTS, list);
try {
node.flush();
} catch (BackingStoreException e) {
log(e);
}
}
}
/**
* @return a list of fragments that consider this bundle their host and
* symbolic names contain {@link #EE_DESCRIPTION_PREFIX}
*/
private String getListOfEEFragments(Bundle[] allFragments) {
StringBuffer result = new StringBuffer();
for (Bundle allFragment : allFragments) {
if (allFragment.getSymbolicName().indexOf(EE_DESCRIPTION_PREFIX) >= 0) {
result.append(allFragment.getSymbolicName());
result.append(';');
result.append(allFragment.getVersion().toString());
result.append(';');
}
}
return result.toString();
}
@Override
public void stop(BundleContext context) throws Exception {
try {
ApiDescriptionManager.shutdown();
ApiBaselineManager.getManager().stop();
ResourcesPlugin.getWorkspace().removeSaveParticipant(PLUGIN_ID);
FileManager.getManager().deleteFiles();
fBundleContext = null;
if (deltaProcessor != null) {
JavaCore.removeElementChangedListener(deltaProcessor);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(deltaProcessor);
}
} finally {
super.stop(context);
}
}
/**
* Returns the severity for the specific key from the given {@link IProject}
* . If the project does not have project specific settings, the workspace
* preference is returned. If <code>null</code> is passed in as the project
* the workspace preferences are consulted.
*
* @param prefkey the given preference key
* @param project the given project or <code>null</code>
* @return the severity level for the given pref key
*/
public int getSeverityLevel(String prefkey, IProject project) {
IPreferencesService service = Platform.getPreferencesService();
IScopeContext[] context = null;
if (hasProjectSettings(project)) {
context = new IScopeContext[] {
new ProjectScope(project), InstanceScope.INSTANCE,
DefaultScope.INSTANCE };
} else {
context = new IScopeContext[] {
InstanceScope.INSTANCE, DefaultScope.INSTANCE };
}
String value = service.get(prefkey, null, getPreferences(context));
if (VALUE_ERROR.equals(value)) {
return SEVERITY_ERROR;
}
if (VALUE_WARNING.equals(value)) {
return SEVERITY_WARNING;
}
return SEVERITY_IGNORE;
}
/**
* Returns the array of {@link IEclipsePreferences} nodes to look in to
* determine the value of a given preference. This method will return
* <code>null</code> iff:
* <ul>
* <li>the given array of contexts are <code>null</code></li>
* <li>if no nodes could be determined from the given contexts</li>
* </ul>
*
* @param context
* @return the array of {@link IEclipsePreferences} to look in or
* <code>null</code>.
* @since 1.1
*/
IEclipsePreferences[] getPreferences(IScopeContext[] context) {
if (context != null) {
ArrayList<IEclipsePreferences> nodes = new ArrayList<>(context.length);
IEclipsePreferences node = null;
for (IScopeContext element : context) {
node = element.getNode(PLUGIN_ID);
if (node != null) {
nodes.add(node);
}
}
if (nodes.size() > 0) {
return nodes.toArray(new IEclipsePreferences[nodes.size()]);
}
}
return null;
}
/**
* Returns if the given project has project-specific settings.
*
* @param project
* @return true if the project has specific settings, false otherwise
* @since 1.1
*/
boolean hasProjectSettings(IProject project) {
if (project != null) {
ProjectScope scope = new ProjectScope(project);
IEclipsePreferences node = scope.getNode(PLUGIN_ID);
try {
return node != null && node.keys().length > 0;
} catch (BackingStoreException bse) {
log(bse);
}
}
return false;
}
public ISessionManager getSessionManager() {
if (fgSessionManager == null) {
fgSessionManager = new SessionManager();
}
return fgSessionManager;
}
/**
* Returns the enable state for the specific key from the given
* {@link IProject}. If the project does not have project specific settings,
* the workspace preference is returned. If <code>null</code> is passed in
* as the project the workspace preferences are consulted.
*
* @param prefkey the given preference key
* @param project the given project or <code>null</code>
* @return the enable state
*/
public boolean getEnableState(String prefkey, IProject project) {
IPreferencesService service = Platform.getPreferencesService();
IScopeContext[] context = null;
if (hasProjectSettings(project)) {
context = new IScopeContext[] {
new ProjectScope(project), InstanceScope.INSTANCE,
DefaultScope.INSTANCE };
} else {
context = new IScopeContext[] {
InstanceScope.INSTANCE, DefaultScope.INSTANCE };
}
String value = service.get(prefkey, null, getPreferences(context));
return VALUE_ENABLED.equals(value);
}
/**
* Returns a service with the specified name or <code>null</code> if none.
*
* @param serviceName name of service
* @return service object or <code>null</code> if none
*/
public Object acquireService(String serviceName) {
ServiceReference<?> reference = fBundleContext.getServiceReference(serviceName);
if (reference == null) {
return null;
}
return fBundleContext.getService(reference);
}
@Override
public void optionsChanged(DebugOptions options) {
DEBUG = options.getBooleanOption(DEBUG_FLAG, false);
boolean option = options.getBooleanOption(DELTA_DEBUG, false);
DEBUG_CLASSFILE_COMPARATOR = DEBUG && option;
DEBUG_API_COMPARATOR = DEBUG_CLASSFILE_COMPARATOR;
DEBUG_BUILDER = DEBUG && options.getBooleanOption(BUILDER_DEBUG, false);
DEBUG_SEARCH_ENGINE = DEBUG && options.getBooleanOption(SEARCH_DEBUG, false);
DEBUG_REFERENCE_EXTRACTOR = DEBUG && options.getBooleanOption(CLASSFILE_VISITOR_DEBUG, false);
DEBUG_ELEMENT_DESCRIPTOR_FRAMEWORK = DEBUG && options.getBooleanOption(DESCRIPTOR_FRAMEWORK_DEBUG, false);
DEBUG_TAG_SCANNER = DEBUG && options.getBooleanOption(TAG_SCANNER_DEBUG, false);
DEBUG_PROJECT_COMPONENT = DEBUG && options.getBooleanOption(PLUGIN_WORKSPACE_COMPONENT_DEBUG, false);
DEBUG_BASELINE_MANAGER = DEBUG && options.getBooleanOption(API_PROFILE_MANAGER_DEBUG, false);
DEBUG_FILTER_STORE = DEBUG && options.getBooleanOption(API_FILTER_STORE_DEBUG, false);
DEBUG_REFERENCE_ANALYZER = DEBUG && options.getBooleanOption(API_REFERENCE_ANALYZER_DEBUG, false);
DEBUG_REFERENCE_RESOLVER = DEBUG && options.getBooleanOption(REFERENCE_RESOLVER_DEBUG, false);
DEBUG_PROBLEM_DETECTOR = DEBUG && options.getBooleanOption(PROBLEM_DETECTOR_DEBUG, false);
DEBUG_API_DESCRIPTION = DEBUG && options.getBooleanOption(API_DESCRIPTION, false);
DEBUG_WORKSPACE_DELTA_PROCESSOR = DEBUG && options.getBooleanOption(WORKSPACE_DELTA_PROCESSOR, false);
DEBUG_API_ANALYZER = DEBUG && options.getBooleanOption(API_ANALYZER_DEBUG, false);
DEBUG_USE_REPORT_CONVERTER = DEBUG && options.getBooleanOption(USE_REPORT_CONVERTER_DEBUG, false);
}
}