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);
}
}
}