source: trunk/src_apollo/org/apollo/util/ODFrameHeirarchyFetcher.java@ 315

Last change on this file since 315 was 315, checked in by bjn8, 16 years ago

Apollo spin-off added

File size: 5.8 KB
Line 
1package org.apollo.util;
2
3import java.util.LinkedList;
4import java.util.Queue;
5
6import javax.swing.SwingUtilities;
7
8import org.apollo.audio.structure.OverdubbedFrame;
9import org.apollo.audio.structure.TrackGraphLoopException;
10import org.apollo.audio.structure.AudioStructureModel;
11import org.expeditee.gui.FrameIO;
12
13/**
14 * Fetches overdubbed frame heirarchies on a dedicated thread.
15 *
16 * @author Brook Novak
17 *
18 */
19public class ODFrameHeirarchyFetcher {
20
21 private FetchWorker fetcher = null;
22
23 /** Using a FIFO queue implementation */
24 private Queue<FetchRequest> fetchRequestQueue = new LinkedList<FetchRequest>(); // SHARED RESOURCE
25
26 /** Singleton design pattern */
27 private static ODFrameHeirarchyFetcher instance = new ODFrameHeirarchyFetcher();
28 private ODFrameHeirarchyFetcher() { }
29 public static ODFrameHeirarchyFetcher getInstance() {
30 return instance;
31 }
32
33 /**
34 * Asynchronously (non-blocking) performs a fetch for a given frame name. Once the fetch is
35 * complete the odRec's {@link ODFrameReceiver#receiveResult(OverdubbedFrame, TrackGraphLoopException)}
36 * is invoked.
37 *
38 * If there is a request for the given ODFrameReceiver that is already pending, the old request is replaced
39 * if the rootFrameName differs, otherwise the old fetch remains and the new fetch is ignored.
40 *
41 * @see {@link ODFrameReceiver)}
42 *
43 * @param rootFrameName
44 * The frame name to get the heirarchy for. Must be a valid framename
45 *
46 * @param odRec
47 * The ODFrameReceiver to receive the result.
48 *
49 * @throws NullPointerException
50 * If rootFrameName or odRec is null.
51 *
52 * @throws IllegalArgumentException
53 * If rootFrameName is not a valid framename.
54 */
55 public void doFetch(String rootFrameName, ODFrameReceiver odRec) {
56 if (rootFrameName == null) throw new NullPointerException("rootFrameName");
57 if (!FrameIO.isValidFrameName(rootFrameName))
58 throw new IllegalArgumentException("rootFrameName is an invalid framename");
59
60 if (odRec == null) throw new NullPointerException("odRec");
61
62
63 FetchRequest newfr = new FetchRequest(rootFrameName, odRec);
64
65 synchronized(fetchRequestQueue) {
66
67 // See if a fetch for the receiver already exists
68 FetchRequest match = null;
69 for (FetchRequest existingfr : fetchRequestQueue) {
70 if (newfr.equals(existingfr)) {
71 match = existingfr;
72 break;
73 }
74 }
75
76 // If a request already exists
77 if (match != null) {
78 // Check if the new fetch request is for a different odframe
79 if (!match.getRootFrameName().equals(rootFrameName)) {
80 fetchRequestQueue.remove(match); // replace redundant request
81 fetchRequestQueue.add(newfr);
82 }
83 } else {
84 fetchRequestQueue.add(newfr);
85 }
86
87 // Ensure that the fetch thread is running
88 if (fetcher == null || !fetcher.isAlive()) {
89 fetcher = new FetchWorker();
90 fetcher.start();
91 }
92 }
93
94 }
95
96
97 private class FetchWorker extends Thread {
98
99 FetchWorker() {
100 super("FetchWorker");
101 }
102
103 public void run() {
104
105 while (true) {
106
107 FetchRequest request = null;
108
109 synchronized(fetchRequestQueue) {
110
111 if (!fetchRequestQueue.isEmpty())
112 request = fetchRequestQueue.remove();
113
114 if (request == null) return;
115 }
116
117 boolean hasUpdated = false;
118 do {
119 try {
120 AudioStructureModel.getInstance().waitOnUpdates();
121 hasUpdated = true;
122 } catch (InterruptedException e) {
123 e.printStackTrace();
124 continue;
125 }
126 } while (!hasUpdated);
127
128 while (true) {
129 try {
130 request.odFrameResult = AudioStructureModel.getInstance().fetchGraph(request.getRootFrameName());
131 break;
132 } catch (InterruptedException e) { // cancelled, retry
133 /* Consume */
134
135 } catch (TrackGraphLoopException e) { // contains loop
136 request.loopExResult = e;
137 break;
138 }
139 }
140
141 // Run result notiofaction for this request on swing thread
142 SwingUtilities.invokeLater(request);
143
144 }
145
146
147
148 }
149 }
150
151 /**
152 * Immutable two-tuple for storing fetch requests.
153 *
154 * @author Brook Novak
155 */
156 private class FetchRequest implements Runnable {
157
158 private String rootFrameName;
159 private ODFrameReceiver receiver;
160
161 OverdubbedFrame odFrameResult = null;
162 TrackGraphLoopException loopExResult = null;
163
164 /**
165 *
166 * @param rootFrameName
167 * Must be a valid framename.
168 *
169 * @param receiver
170 */
171 public FetchRequest(String rootFrameName, ODFrameReceiver receiver) {
172 this.rootFrameName = rootFrameName;
173 this.receiver = receiver;
174 assert(rootFrameName != null);
175 assert(FrameIO.isValidFrameName(rootFrameName)) ;
176 assert(receiver != null);
177 }
178
179 @Override
180 public boolean equals(Object obj) {
181 return receiver.equals(obj);
182 }
183
184 @Override
185 public int hashCode() {
186 return receiver.hashCode();
187 }
188
189 public ODFrameReceiver getReceiver() {
190 return receiver;
191 }
192
193 public String getRootFrameName() {
194 return rootFrameName;
195 }
196
197 /**
198 * To be invoked on swing thread
199 */
200 public void run() {
201 receiver.receiveResult(odFrameResult, loopExResult);
202 }
203
204 }
205
206 /**
207 * A frame receive can request for fetches and have their
208 * {@link #receiveResult(OverdubbedFrame, TrackGraphLoopException)}
209 * method invoked once a result has occured.
210 *
211 * @author Brook Novak
212 */
213 public interface ODFrameReceiver {
214
215 /**
216 * Invoked once a request has been proccessed. <b>This is invoked on the swing thread.</b>
217 *
218 * @see ODFrameHeirarchyFetcher#doFetch(String, org.apollo.util.ODFrameHeirarchyFetcher.ODFrameReceiver)
219 *
220 * @param odFrame
221 * The overdubbed frame. Null if the frame does not exist - or if it does exist but there are no track widgets on it.
222 * Or Null if there was a loop.
223 *
224 * @param loopEx
225 * If there was a loop, then this will be set containing the loop info.
226 */
227 public void receiveResult(OverdubbedFrame odFrame, TrackGraphLoopException loopEx);
228
229 }
230
231}
Note: See TracBrowser for help on using the repository browser.