| /******************************************************************************* |
| * Copyright (c) 2007, 2008 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; |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.FactoryConfigurationError; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.ISaveContext; |
| import org.eclipse.core.resources.ISaveParticipant; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jdt.core.ElementChangedEvent; |
| import org.eclipse.jdt.core.IElementChangedListener; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaElementDelta; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.pde.api.tools.internal.builder.ApiAnalysisBuilder; |
| import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
| import org.eclipse.pde.api.tools.internal.provisional.Factory; |
| import org.eclipse.pde.api.tools.internal.provisional.IApiComponent; |
| import org.eclipse.pde.api.tools.internal.provisional.IApiProfile; |
| import org.eclipse.pde.api.tools.internal.provisional.IApiProfileManager; |
| import org.eclipse.pde.api.tools.internal.util.Util; |
| import org.eclipse.pde.core.plugin.IPluginModelBase; |
| import org.eclipse.pde.core.plugin.ModelEntry; |
| import org.eclipse.pde.core.plugin.PluginRegistry; |
| import org.eclipse.pde.internal.core.IPluginModelListener; |
| import org.eclipse.pde.internal.core.PDECore; |
| import org.eclipse.pde.internal.core.PluginModelDelta; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| /** |
| * This manager is used to maintain (persist, restore, access, update) Api profiles. |
| * This manager is lazy, in that caches are built and maintained when requests |
| * are made for information, nothing is pre-loaded when the manager is initialized. |
| * |
| * @since 1.0.0 |
| */ |
| public final class ApiProfileManager implements IApiProfileManager, ISaveParticipant, IElementChangedListener, IPluginModelListener, IResourceChangeListener { |
| |
| /** |
| * Constant used for controlling tracing in the API tool builder |
| */ |
| private static boolean DEBUG = Util.DEBUG; |
| |
| /** |
| * Method used for initializing tracing in the API tool builder |
| */ |
| public static void setDebug(boolean debugValue) { |
| DEBUG = debugValue || Util.DEBUG; |
| } |
| |
| /** |
| * Constant for the default API profile. |
| * Value is: <code>default_api_profile</code> |
| */ |
| private static final String DEFAULT_PROFILE = "default_api_profile"; //$NON-NLS-1$ |
| |
| /** |
| * The main cache for the manager. |
| * The form of the cache is: |
| * <pre> |
| * HashMap<String(profileid), ApiProfile> |
| * </pre> |
| */ |
| private HashMap profilecache = null; |
| |
| /** |
| * The current default {@link IApiProfile} |
| */ |
| private String defaultprofile = null; |
| |
| /** |
| * The current workspace profile |
| */ |
| private IApiProfile workspaceprofile = null; |
| |
| /** |
| * The default save location for persisting the cache from this manager. |
| */ |
| private IPath savelocation = ApiPlugin.getDefault().getStateLocation().append(".api_profiles").addTrailingSeparator(); //$NON-NLS-1$ |
| |
| /** |
| * If the cache of profiles needs to be saved or not. |
| */ |
| private boolean fNeedsSaving = false; |
| |
| /** |
| * Constructor |
| */ |
| public ApiProfileManager() { |
| ApiPlugin.getDefault().addSaveParticipant(this); |
| JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE); |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_BUILD); |
| PDECore.getDefault().getModelManager().addPluginModelListener(this); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#getApiProfile(java.lang.String) |
| */ |
| public synchronized IApiProfile getApiProfile(String name) { |
| initializeStateCache(); |
| return (ApiProfile) profilecache.get(name); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#getApiProfiles() |
| */ |
| public synchronized IApiProfile[] getApiProfiles() { |
| initializeStateCache(); |
| return (IApiProfile[]) profilecache.values().toArray(new IApiProfile[profilecache.size()]); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#addApiProfile(org.eclipse.pde.api.tools.model.component.IApiProfile) |
| */ |
| public synchronized void addApiProfile(IApiProfile newprofile) { |
| if(newprofile != null) { |
| initializeStateCache(); |
| profilecache.put(newprofile.getName(), newprofile); |
| fNeedsSaving = true; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#removeApiProfile(java.lang.String) |
| */ |
| public synchronized boolean removeApiProfile(String name) { |
| if(name != null) { |
| initializeStateCache(); |
| IApiProfile profile = (IApiProfile) profilecache.remove(name); |
| if(profile != null) { |
| profile.dispose(); |
| boolean success = true; |
| //remove from filesystem |
| File file = savelocation.append(name+".profile").toFile(); //$NON-NLS-1$ |
| if(file.exists()) { |
| success &= file.delete(); |
| } |
| fNeedsSaving = true; |
| return success; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Initializes the profile cache lazily. Only performs work |
| * if the current cache has not been created yet |
| * @throws FactoryConfigurationError |
| * @throws ParserConfigurationException |
| */ |
| private synchronized void initializeStateCache() { |
| long time = System.currentTimeMillis(); |
| if(profilecache == null) { |
| profilecache = new HashMap(); |
| File[] profiles = savelocation.toFile().listFiles(new FileFilter() { |
| public boolean accept(File pathname) { |
| return pathname.getName().endsWith(".profile"); //$NON-NLS-1$ |
| } |
| }); |
| if(profiles != null) { |
| InputStream fin = null; |
| IApiProfile newprofile = null; |
| for(int i = 0; i < profiles.length; i++) { |
| File profile = profiles[i]; |
| if(profile.exists()) { |
| try { |
| fin = new FileInputStream(profile); |
| newprofile = restoreProfile(fin); |
| profilecache.put(newprofile.getName(), newprofile); |
| } |
| catch (IOException e) { |
| ApiPlugin.log(e); |
| } |
| catch(CoreException e) { |
| ApiPlugin.log(e.getStatus()); |
| } |
| } |
| } |
| } |
| String def = ApiPlugin.getDefault().getPluginPreferences().getString(DEFAULT_PROFILE); |
| IApiProfile profile = (IApiProfile) profilecache.get(def); |
| defaultprofile = (profile != null ? def : null); |
| if(DEBUG) { |
| System.out.println("Time to initialize state cache: " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| |
| /** |
| * Persists all of the cached elements to individual xml files named |
| * with the id of the API profile |
| * @throws IOException |
| */ |
| private void persistStateCache() throws CoreException, IOException { |
| if(defaultprofile != null) { |
| ApiPlugin.getDefault().getPluginPreferences().setValue(DEFAULT_PROFILE, defaultprofile); |
| } |
| if(profilecache != null) { |
| File dir = new File(savelocation.toOSString()); |
| if(!dir.exists()) { |
| dir.mkdirs(); |
| } |
| String id = null; |
| File file = null; |
| FileOutputStream fout = null; |
| IApiProfile profile = null; |
| for(Iterator iter = profilecache.keySet().iterator(); iter.hasNext();) { |
| id = (String) iter.next(); |
| profile = (IApiProfile) profilecache.get(id); |
| file = savelocation.append(id+".profile").toFile(); //$NON-NLS-1$ |
| if(!file.exists()) { |
| file.createNewFile(); |
| } |
| try { |
| fout = new FileOutputStream(file); |
| profile.writeProfileDescription(fout); |
| fout.flush(); |
| } |
| finally { |
| fout.close(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Throws a core exception with the given message and underlying exception, |
| * if any. |
| * |
| * @param message error message |
| * @param e underlying exception or <code>null</code> |
| * @throws CoreException |
| */ |
| private static void abort(String message, Throwable e) throws CoreException { |
| throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, e)); |
| } |
| |
| /** |
| * Constructs and returns a profile from the given input stream (persisted profile). |
| * |
| * @param stream input stream |
| * @return API profile |
| * @throws CoreException if unable to restore the profile |
| */ |
| public static IApiProfile restoreProfile(InputStream stream) throws CoreException { |
| long start = System.currentTimeMillis(); |
| DocumentBuilder parser = null; |
| try { |
| parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| parser.setErrorHandler(new DefaultHandler()); |
| } catch (ParserConfigurationException e) { |
| abort("Error restoring API profile", e); //$NON-NLS-1$ |
| } catch (FactoryConfigurationError e) { |
| abort("Error restoring API profile", e); //$NON-NLS-1$ |
| } |
| IApiProfile profile = null; |
| try { |
| Document document = parser.parse(stream); |
| Element root = document.getDocumentElement(); |
| if(root.getNodeName().equals(IApiXmlConstants.ELEMENT_APIPROFILE)) { |
| profile = new ApiProfile(root.getAttribute(IApiXmlConstants.ATTR_NAME)); |
| // un-pooled components |
| NodeList children = root.getElementsByTagName(IApiXmlConstants.ELEMENT_APICOMPONENT); |
| List components = new ArrayList(); |
| for(int j = 0; j < children.getLength(); j++) { |
| Element componentNode = (Element) children.item(j); |
| // this also contains components in pools, so don't process them |
| if (componentNode.getParentNode().equals(root)) { |
| String location = componentNode.getAttribute(IApiXmlConstants.ATTR_LOCATION); |
| IApiComponent component = profile.newApiComponent(Path.fromPortableString(location).toOSString()); |
| if(component != null) { |
| components.add(component); |
| } |
| } |
| } |
| // pooled components |
| children = root.getElementsByTagName(IApiXmlConstants.ELEMENT_POOL); |
| for(int j = 0; j < children.getLength(); j++) { |
| String location = ((Element) children.item(j)).getAttribute(IApiXmlConstants.ATTR_LOCATION); |
| IPath poolPath = Path.fromPortableString(location); |
| NodeList componentNodes = root.getElementsByTagName(IApiXmlConstants.ELEMENT_APICOMPONENT); |
| for (int i = 0; i < componentNodes.getLength(); i++) { |
| Element compElement = (Element) componentNodes.item(i); |
| String id = compElement.getAttribute(IApiXmlConstants.ATTR_ID); |
| String ver = compElement.getAttribute(IApiXmlConstants.ATTR_VERSION); |
| StringBuffer name = new StringBuffer(); |
| name.append(id); |
| name.append('_'); |
| name.append(ver); |
| File file = poolPath.append(name.toString()).toFile(); |
| if (!file.exists()) { |
| name.append(".jar"); //$NON-NLS-1$ |
| file = poolPath.append(name.toString()).toFile(); |
| } |
| IApiComponent component = profile.newApiComponent(file.getAbsolutePath()); |
| if(component != null) { |
| components.add(component); |
| } |
| } |
| |
| } |
| profile.addApiComponents((IApiComponent[]) components.toArray(new IApiComponent[components.size()])); |
| } |
| } catch (IOException e) { |
| abort("Error restoring API profile", e); //$NON-NLS-1$ |
| } catch(SAXException e) { |
| abort("Error restoring API profile", e); //$NON-NLS-1$ |
| } finally { |
| try { |
| stream.close(); |
| } catch (IOException io) { |
| ApiPlugin.log(io); |
| } |
| } |
| if (profile == null) { |
| abort("Invalid profile description", null); //$NON-NLS-1$ |
| } |
| if(DEBUG) { |
| System.out.println("Time to restore a persisted profile : " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return profile; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.ISaveParticipant#saving(org.eclipse.core.resources.ISaveContext) |
| */ |
| public void saving(ISaveContext context) throws CoreException { |
| if(!fNeedsSaving) { |
| return; |
| } |
| try { |
| persistStateCache(); |
| fNeedsSaving = false; |
| } catch (IOException e) { |
| ApiPlugin.log(e); |
| } |
| } |
| |
| /** |
| * Returns if the given name is an existing profile name |
| * @param name |
| * @return true if the given name is an existing profile name, false otherwise |
| */ |
| public boolean isExistingProfileName(String name) { |
| if(profilecache == null) { |
| return false; |
| } |
| return profilecache.keySet().contains(name); |
| } |
| |
| /** |
| * Cleans up the manager and persists any unsaved API profiles |
| */ |
| public void stop() { |
| try { |
| // we should first dispose all existing profiles |
| for (Iterator iterator = this.profilecache.values().iterator(); iterator.hasNext();) { |
| IApiProfile profile = (IApiProfile) iterator.next(); |
| profile.dispose(); |
| } |
| this.profilecache.clear(); |
| if(this.workspaceprofile != null) { |
| this.workspaceprofile.dispose(); |
| } |
| } |
| finally { |
| ApiPlugin.getDefault().removeSaveParticipant(this); |
| JavaCore.removeElementChangedListener(this); |
| PDECore.getDefault().getModelManager().removePluginModelListener(this); |
| ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.ISaveParticipant#doneSaving(org.eclipse.core.resources.ISaveContext) |
| */ |
| public void doneSaving(ISaveContext context) {} |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.ISaveParticipant#prepareToSave(org.eclipse.core.resources.ISaveContext) |
| */ |
| public void prepareToSave(ISaveContext context) throws CoreException { } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.ISaveParticipant#rollback(org.eclipse.core.resources.ISaveContext) |
| */ |
| public void rollback(ISaveContext context) {} |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#getDefaultApiProfile() |
| */ |
| public synchronized IApiProfile getDefaultApiProfile() { |
| initializeStateCache(); |
| return (IApiProfile) profilecache.get(defaultprofile); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.IApiProfileManager#setDefaultApiProfile(java.lang.String) |
| */ |
| public void setDefaultApiProfile(String name) { |
| fNeedsSaving = true; |
| defaultprofile = name; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.pde.api.tools.internal.provisional.IApiProfileManager#getWorkspaceProfile() |
| */ |
| public synchronized IApiProfile getWorkspaceProfile() { |
| if(ApiPlugin.isRunningInFramework()) { |
| if(this.workspaceprofile == null) { |
| this.workspaceprofile = createWorkspaceProfile(); |
| } |
| return this.workspaceprofile; |
| } |
| return null; |
| } |
| |
| /** |
| * Disposes the workspace profile such that a new one will be created |
| * on the next request. |
| */ |
| private synchronized void disposeWorkspaceProfile() { |
| if (workspaceprofile != null) { |
| workspaceprofile.dispose(); |
| workspaceprofile = null; |
| } |
| } |
| |
| /** |
| * Creates a workspace {@link IApiProfile} |
| * @return a new workspace {@link IApiProfile} or <code>null</code> |
| */ |
| private IApiProfile createWorkspaceProfile() { |
| long time = System.currentTimeMillis(); |
| IApiProfile profile = null; |
| try { |
| profile = Factory.newApiProfile(ApiPlugin.WORKSPACE_API_PROFILE_ID); |
| // populate it with only projects that are API aware |
| IPluginModelBase[] models = PluginRegistry.getActiveModels(); |
| List componentsList = new ArrayList(models.length); |
| IApiComponent apiComponent = null; |
| for (int i = 0, length = models.length; i < length; i++) { |
| try { |
| apiComponent = profile.newApiComponent(models[i]); |
| if (apiComponent != null) { |
| componentsList.add(apiComponent); |
| } |
| } catch (CoreException e) { |
| ApiPlugin.log(e); |
| } |
| } |
| profile.addApiComponents((IApiComponent[]) componentsList.toArray(new IApiComponent[componentsList.size()])); |
| } finally { |
| if (DEBUG) { |
| System.out.println("Time to create a workspace profile : " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| return profile; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.core.IElementChangedListener#elementChanged(org.eclipse.jdt.core.ElementChangedEvent) |
| */ |
| public void elementChanged(ElementChangedEvent event) { |
| Object obj = event.getSource(); |
| if(obj instanceof IJavaElementDelta) { |
| processJavaElementDeltas(((IJavaElementDelta)obj).getAffectedChildren(), null); |
| } |
| } |
| |
| /** |
| * Processes the java element deltas of interest |
| * @param deltas |
| */ |
| private synchronized void processJavaElementDeltas(IJavaElementDelta[] deltas, IJavaProject project) { |
| try { |
| IJavaElementDelta delta = null; |
| for(int i = 0; i < deltas.length; i++) { |
| delta = deltas[i]; |
| switch(delta.getElement().getElementType()) { |
| case IJavaElement.JAVA_PROJECT: { |
| IJavaProject proj = (IJavaProject) delta.getElement(); |
| IProject pj = proj.getProject(); |
| if (acceptProject(pj)) { |
| switch (delta.getKind()) { |
| //process the project changed only if the project is API aware |
| case IJavaElementDelta.CHANGED: |
| int flags = delta.getFlags(); |
| if( (flags & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0 || |
| (flags & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0 || |
| (flags & IJavaElementDelta.F_CLOSED) != 0 || |
| (flags & IJavaElementDelta.F_OPENED) != 0) { |
| if(DEBUG) { |
| System.out.println("--> processing CLASSPATH CHANGE/CLOSE/OPEN project: ["+proj.getElementName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| disposeWorkspaceProfile(); |
| } else if((flags & IJavaElementDelta.F_CHILDREN) != 0) { |
| if(DEBUG) { |
| System.out.println("--> processing child deltas of project: ["+proj.getElementName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| processJavaElementDeltas(delta.getAffectedChildren(), proj); |
| } |
| break; |
| } |
| } |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: { |
| IPackageFragmentRoot root = (IPackageFragmentRoot) delta.getElement(); |
| if(DEBUG) { |
| System.out.println("processed package fragment root delta: ["+root.getElementName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| switch(delta.getKind()) { |
| case IJavaElementDelta.CHANGED: { |
| if(DEBUG) { |
| System.out.println("processed children of CHANGED package fragment root: ["+root.getElementName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| processJavaElementDeltas(delta.getAffectedChildren(), project); |
| break; |
| } |
| } |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| IPackageFragment fragment = (IPackageFragment) delta.getElement(); |
| if(delta.getKind() == IJavaElementDelta.REMOVED) { |
| handlePackageRemoval(project.getProject(), fragment); |
| } |
| break; |
| } |
| } |
| } |
| } catch (CoreException e) { |
| ApiPlugin.log(e); |
| } |
| } |
| |
| /** |
| * Handles the specified {@link IPackageFragment} being removed. |
| * When a packaged is removed, we: |
| * <ol> |
| * <li>Remove the package from the cache of resolved providers |
| * of that package (in the API profile)</li> |
| * </ol> |
| * @param project |
| * @param fragment |
| * @throws CoreException |
| */ |
| private void handlePackageRemoval(IProject project, IPackageFragment fragment) throws CoreException { |
| if(DEBUG) { |
| System.out.println("processed package fragment REMOVE delta: ["+fragment.getElementName()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| ((ApiProfile)getWorkspaceProfile()).clearPackage(fragment.getElementName()); |
| } |
| |
| /** |
| * Returns if we should care about the specified project |
| * @param project |
| * @return true if the project is an 'API aware' project, false otherwise |
| */ |
| private boolean acceptProject(IProject project) { |
| try { |
| if (!project.isOpen()) { |
| return true; |
| } |
| return project.exists() && project.hasNature(ApiPlugin.NATURE_ID); |
| } |
| catch(CoreException e) { |
| return false; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * |
| * Whenever a bundle definition changes (add/removed/changed), the |
| * workspace profile becomes potentially invalid as the bundle description |
| * may have changed in some way to invalidate our underlying OSGi state. |
| * |
| * @see org.eclipse.pde.internal.core.IPluginModelListener#modelsChanged(org.eclipse.pde.internal.core.PluginModelDelta) |
| */ |
| public void modelsChanged(PluginModelDelta delta) { |
| ModelEntry[] entries = null; |
| switch(delta.getKind()) { |
| case PluginModelDelta.ADDED: { |
| entries = delta.getAddedEntries(); |
| break; |
| } |
| case PluginModelDelta.REMOVED: { |
| entries = delta.getRemovedEntries(); |
| break; |
| } |
| case PluginModelDelta.CHANGED: { |
| entries = delta.getChangedEntries(); |
| break; |
| } |
| } |
| if(entries != null) { |
| IPluginModelBase model = null; |
| for(int i = 0; i < entries.length; i++) { |
| model = entries[i].getModel(); |
| if(model != null) { |
| disposeWorkspaceProfile(); |
| } |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) |
| */ |
| public void resourceChanged(IResourceChangeEvent event) { |
| // clean all API errors when a project description changes |
| IResourceDelta delta = event.getDelta(); |
| if (delta != null) { |
| IResourceDelta[] children = delta.getAffectedChildren(IResourceDelta.CHANGED); |
| for (int i = 0; i < children.length; i++) { |
| IResourceDelta d = children[i]; |
| IResource resource = d.getResource(); |
| if (resource.getType() == IResource.PROJECT) { |
| if ((d.getFlags() & IResourceDelta.DESCRIPTION) != 0) { |
| IProject project = (IProject)resource; |
| if (project.isAccessible()) { |
| try { |
| if (!project.getDescription().hasNature(ApiPlugin.NATURE_ID)) { |
| IJavaProject jp = JavaCore.create(project); |
| if (jp.exists()) { |
| ApiDescriptionManager.getDefault().clean(jp, true, true); |
| ApiAnalysisBuilder.cleanupMarkers(resource); |
| } |
| } |
| } catch (CoreException e) { |
| ApiPlugin.log(e.getStatus()); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| } |