source: trunk/src/org/apollo/util/ODFrameHeirarchyFetcher.java@ 1102

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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