blob: ad9708d7b656c545834903be693a5bf75ad5011d [file] [log] [blame]
package aQute.bnd.concurrent;
import java.io.*;
import java.util.*;
import aQute.bnd.build.*;
import aQute.lib.osgi.*;
import aQute.libg.forker.*;
/**
* This class implements a concurrent builder. It manages the build process in
* an environment where many threads can initiate builds. Users should call
* changed(Project,boolean)
*
*/
public class MultiBuilder {
Workspace workspace;
Forker<Project> forker;
boolean building = false;
final Set<File> filesChanged = Collections.synchronizedSet(new HashSet<File>());
/**
* Constructor
*
* @param workspace
* the workspace this MultiBuilder works for.
*
*/
public MultiBuilder(Workspace workspace) {
this.workspace = workspace;
}
/**
* Return the build result of a project.
*
* @param p
* the project
* @return the files build by the project
*
* @throws Exception
*/
public File[] build(Project p) throws Exception {
if (p.isStale()) {
startBuild();
}
syncBuild();
return p.build();
}
/**
* Indicate that the project has changed. This will start a build.
*
* @param p
* the project that is changed
* @throws Exception
*/
public void changed(Project p) throws Exception {
p.setChanged();
cancel();
startBuild();
}
/**
* Cancel the current build or do nothing if no build is active.
*
* @throws InterruptedException
*/
public synchronized void cancel() throws InterruptedException {
if (building) {
forker.cancel();
}
}
/**
* Synchronize with a current build or return immediately.
*
* @throws InterruptedException
*/
public synchronized void syncBuild() throws InterruptedException {
if (building) {
forker.join();
}
}
/**
* Schedule a new build if no build is running otherwise return.
*
* @throws Exception
*/
public void startBuild() throws Exception {
synchronized (this) {
if (building)
return;
forker = new Forker<Project>(Processor.getExecutor());
building = true;
}
Processor.getExecutor().execute(new Runnable() {
public void run() {
try {
build();
synchronized (MultiBuilder.this) {
building = false;
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Do the whole build using a forker.
*
* @throws Exception
*/
private void build() throws Exception {
// handle multiple requests
Thread.sleep(100);
workspace.bracket(true);
try {
for (final Project p : workspace.getAllProjects()) {
forker.doWhen(p.getDependson(), p, new Runnable() {
public void run() {
try {
p.build();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
forker.join();
} finally {
workspace.bracket(false);
}
}
}