/******************************************************************************* * Copyright (c) 2016 Red Hat Inc. 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: * Mickael Istria (Red Hat Inc.) - initial API and implementation *******************************************************************************/ package org.eclipse.epp.internal.mpc.ui.discovery; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.core.runtime.jobs.JobGroup; import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin; import org.eclipse.epp.internal.mpc.ui.Messages; import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.ui.IStartup; public class MissingNatureDetector implements IStartup, IPropertyChangeListener { public static final String ENABLEMENT_PROPERTY = "org.eclipse.epp.mpc.naturelookup"; //$NON-NLS-1$ private final JobGroup allJobs = new JobGroup(Messages.MissingNatureDetector_Title, 3, 0); private final Set<String> detectedNatures = new HashSet<String>(); private final Set<LookupByNatureJob> lookupJobs = new HashSet<LookupByNatureJob>(); private final IResourceChangeListener projectOpenListener = new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { if (event.getDelta() == null) { return; } try { CollectMissingNaturesVisitor visitor = new CollectMissingNaturesVisitor(); event.getDelta().accept(visitor); for (String natureId : visitor.getMissingNatures()) { triggerNatureLookup(natureId); } if (!visitor.getMissingNatures().isEmpty()) { showProposalsIfReady(); } } catch (CoreException e) { MarketplaceClientUiPlugin.getInstance().getLog().log( new Status(IStatus.ERROR, MarketplaceClientUiPlugin.getInstance().getBundle().getSymbolicName(), e.getLocalizedMessage(), e)); } } }; private void triggerNatureLookup(final String natureId) { synchronized (lookupJobs) { if (detectedNatures.contains(natureId)) { return; } else { LookupByNatureJob mpcJob = new LookupByNatureJob(natureId); mpcJob.setSystem(false); mpcJob.setUser(false); mpcJob.setJobGroup(allJobs); mpcJob.addJobChangeListener(new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { showProposalsIfReady(); } }); lookupJobs.add(mpcJob); //schedule() needs to happen inside synchronized(...). //Otherwise it's not guaranteed that allJobs.getActiveJobs() will consider it, //and we might end up with processing unfinished jobs in showProposalsIfReady() mpcJob.schedule(); } } } private void showProposalsIfReady() { Map<String, Collection<INode>> candidates; synchronized (lookupJobs) { if (!allJobs.getActiveJobs().isEmpty()) { return; } candidates = new HashMap<String, Collection<INode>>(); for (LookupByNatureJob lookupJob : lookupJobs) { Collection<INode> entryCandidates = lookupJob.getCandidates(); if (entryCandidates != null && !entryCandidates.isEmpty()) { candidates.put(lookupJob.getNatureId(), entryCandidates); } } lookupJobs.clear(); } if (!candidates.isEmpty()) { new ShowNatureProposalsJob(candidates).schedule(); } } public void earlyStartup() { IPreferenceStore preferenceStore = MarketplaceClientUiPlugin.getInstance().getPreferenceStore(); preferenceStore.addPropertyChangeListener(this); boolean preferenceValue = preferenceStore.getBoolean(ENABLEMENT_PROPERTY); if (preferenceValue) { ResourcesPlugin.getWorkspace().addResourceChangeListener(projectOpenListener); } } public void propertyChange(PropertyChangeEvent event) { if (ENABLEMENT_PROPERTY.equals(event.getProperty())) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); if ((Boolean) event.getNewValue()) { workspace.addResourceChangeListener(this.projectOpenListener); } else { workspace.removeResourceChangeListener(this.projectOpenListener); } } } }