package org.bndtools.builder; import java.io.File; import java.util.ArrayList; import java.util.List; import org.bndtools.api.BndtoolsConstants; import org.bndtools.api.ILogger; import org.bndtools.api.Logger; import org.bndtools.build.api.BuildListener; import org.bndtools.build.api.BuildListener.BuildState; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Platform; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.util.function.Function; import org.osgi.util.tracker.ServiceTracker; import bndtools.central.Central; public class BuildListeners { private static final ILogger logger = Logger.getLogger(BuildListeners.class); private final BuildListener.BuildState state = BuildState.released; private final List<BuildListener> listeners; private final ServiceTracker<BuildListener,BuildListener> listenerTracker; private IProject project; private IPath[] paths; public BuildListeners() { IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(BndtoolsConstants.CORE_PLUGIN_ID, "buildListeners"); listeners = new ArrayList<BuildListener>(elements.length); for (IConfigurationElement elem : elements) { try { BuildListener listener = (BuildListener) elem.createExecutableExtension("class"); listeners.add(listener); } catch (Exception e) { logger.logError("Unable to instantiate build listener: " + elem.getAttribute("name"), e); } } BundleContext context = FrameworkUtil.getBundle(BuildListeners.class).getBundleContext(); listenerTracker = new ServiceTracker<BuildListener,BuildListener>(context, BuildListener.class, null) { @Override public BuildListener addingService(ServiceReference<BuildListener> reference) { BuildListener listener = super.addingService(reference); synchronized (listeners) { switch (state) { case starting : listener.buildStarting(project); //$FALL-THROUGH$ case built : listener.builtBundles(project, paths); //$FALL-THROUGH$ case released : default : break; } listeners.add(listener); } return listener; } @Override public void removedService(ServiceReference<BuildListener> reference, BuildListener service) { listeners.remove(service); super.removedService(reference, service); } }; listenerTracker.open(); } public void fireBuildStarting(final IProject project) { this.project = project; forEachListener(new Function<BuildListener,Void>() { @Override public Void apply(BuildListener listener) { listener.buildStarting(project); return null; } }); } public void fireBuiltBundles(final IProject project, final IPath[] paths) { this.project = project; this.paths = paths; forEachListener(new Function<BuildListener,Void>() { @Override public Void apply(BuildListener listener) { listener.builtBundles(project, paths); return null; } }); } public void fireReleased(final IProject project) { forEachListener(new Function<BuildListener,Void>() { @Override public Void apply(BuildListener listener) { listener.released(project); return null; } }); } private void forEachListener(Function<BuildListener,Void> function) { synchronized (listeners) { for (BuildListener listener : listeners) { try { function.apply(listener); } catch (Exception e) { logger.logError("BuildListener error", e); } } } } /** * Call this to make sure that any references to the listeners are no longer held. */ public void release(IProject project) { fireReleased(project); listeners.clear(); listenerTracker.close(); } public void updateListeners(File[] buildFiles, IProject project) throws Exception { // Notify the build listeners if (buildFiles.length > 0) { IPath[] paths = new IPath[buildFiles.length]; for (int i = 0; i < buildFiles.length; i++) paths[i] = Central.toPath(buildFiles[i]); fireBuiltBundles(project, paths); } } }