blob: ad9708d7b656c545834903be693a5bf75ad5011d [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.bnd.concurrent;
2
3import java.io.*;
4import java.util.*;
5
6import aQute.bnd.build.*;
7import aQute.lib.osgi.*;
8import aQute.libg.forker.*;
9
10/**
11 * This class implements a concurrent builder. It manages the build process in
12 * an environment where many threads can initiate builds. Users should call
13 * changed(Project,boolean)
14 *
15 */
16public class MultiBuilder {
17 Workspace workspace;
18 Forker<Project> forker;
19 boolean building = false;
20 final Set<File> filesChanged = Collections.synchronizedSet(new HashSet<File>());
21
22 /**
23 * Constructor
24 *
25 * @param workspace
26 * the workspace this MultiBuilder works for.
27 *
28 */
29 public MultiBuilder(Workspace workspace) {
30 this.workspace = workspace;
31 }
32
33 /**
34 * Return the build result of a project.
35 *
36 * @param p
37 * the project
38 * @return the files build by the project
39 *
40 * @throws Exception
41 */
42 public File[] build(Project p) throws Exception {
43 if (p.isStale()) {
44 startBuild();
45 }
46 syncBuild();
47 return p.build();
48 }
49
50 /**
51 * Indicate that the project has changed. This will start a build.
52 *
53 * @param p
54 * the project that is changed
55 * @throws Exception
56 */
57 public void changed(Project p) throws Exception {
58 p.setChanged();
59 cancel();
60 startBuild();
61 }
62
63 /**
64 * Cancel the current build or do nothing if no build is active.
65 *
66 * @throws InterruptedException
67 */
68 public synchronized void cancel() throws InterruptedException {
69 if (building) {
70 forker.cancel();
71 }
72 }
73
74 /**
75 * Synchronize with a current build or return immediately.
76 *
77 * @throws InterruptedException
78 */
79 public synchronized void syncBuild() throws InterruptedException {
80 if (building) {
81 forker.join();
82 }
83 }
84
85 /**
86 * Schedule a new build if no build is running otherwise return.
87 *
88 * @throws Exception
89 */
90 public void startBuild() throws Exception {
91 synchronized (this) {
92 if (building)
93 return;
94
95 forker = new Forker<Project>(Processor.getExecutor());
96 building = true;
97 }
98
99 Processor.getExecutor().execute(new Runnable() {
100 public void run() {
101 try {
102 build();
103 synchronized (MultiBuilder.this) {
104 building = false;
105 }
106 } catch (Exception e) {
107 e.printStackTrace();
108 }
109 }
110 });
111 }
112
113 /**
114 * Do the whole build using a forker.
115 *
116 * @throws Exception
117 */
118 private void build() throws Exception {
119 // handle multiple requests
120 Thread.sleep(100);
121 workspace.bracket(true);
122 try {
123 for (final Project p : workspace.getAllProjects()) {
124 forker.doWhen(p.getDependson(), p, new Runnable() {
125
126 public void run() {
127 try {
128 p.build();
129 } catch (Exception e) {
130 e.printStackTrace();
131 }
132 }
133 });
134 }
135 forker.join();
136 } finally {
137 workspace.bracket(false);
138 }
139 }
140
141}