1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.client.callbacks;
30
31 import java.io.File;
32 import java.nio.channels.FileChannel;
33 import java.io.RandomAccessFile;
34 import java.io.FileNotFoundException;
35 import java.io.IOException;
36
37 import uk.ac.rdg.resc.jstyx.client.StyxConnection;
38 import uk.ac.rdg.resc.jstyx.client.CStyxFile;
39 import uk.ac.rdg.resc.jstyx.client.MessageCallback;
40
41 import uk.ac.rdg.resc.jstyx.messages.StyxMessage;
42 import uk.ac.rdg.resc.jstyx.messages.RopenMessage;
43 import uk.ac.rdg.resc.jstyx.messages.TreadMessage;
44 import uk.ac.rdg.resc.jstyx.messages.RreadMessage;
45
46 import uk.ac.rdg.resc.jstyx.StyxUtils;
47
48 /***
49 * Callback that is used when downloading a file from the server. Contains
50 * state that needs to persist between message exchanges with the server. See
51 * CStyxFile.downloadAsync()
52 *
53 * @author jdb
54 * $Revision: 442 $
55 * $Date: 2005-11-03 07:39:45 +0000 (Thu, 03 Nov 2005) $
56 * $Log$
57 * Revision 1.2 2005/11/03 07:39:45 jonblower
58 * Bug fixes
59 *
60 * Revision 1.1 2005/08/05 13:46:40 jonblower
61 * Factored out all callback objects from CStyxFile into separate classes
62 *
63 */
64
65 public class DownloadCallback extends MessageCallback
66 {
67 private MessageCallback callback;
68 private File localFile;
69 private int numRequests;
70 private FileChannel fout;
71 private long offset;
72 private boolean eof;
73 private int numOutstandingMessages;
74 private long bytesDownloaded;
75 private CStyxFile file;
76 private StyxConnection conn;
77
78 public DownloadCallback(CStyxFile file, File localFile, int numRequests,
79 MessageCallback callback)
80 {
81 this.file = file;
82 this.conn = this.file.getConnection();
83 this.callback = callback;
84 this.localFile = localFile;
85 this.numRequests = numRequests;
86 this.fout = null;
87 this.offset = 0;
88 this.eof = false;
89 this.numOutstandingMessages = 0;
90 this.bytesDownloaded = 0;
91 }
92
93 public void nextStage()
94 {
95 if (this.file.isOpen())
96 {
97 try
98 {
99
100 if (this.fout == null)
101 {
102 if (this.localFile != null)
103 {
104 this.fout = new RandomAccessFile(this.localFile, "rw").getChannel();
105
106
107 this.fout.truncate(0);
108 }
109 }
110
111 for (int i = 0; i < this.numRequests; i++)
112 {
113 this.readNextChunk();
114 }
115 }
116 catch (FileNotFoundException fnfe)
117 {
118 this.error("cannot open " + this.localFile + " for writing", null);
119 }
120 catch (IOException ioe)
121 {
122 this.error("cannot truncate " + this.localFile + ": " +
123 ioe.getMessage(), null);
124 }
125 }
126 else
127 {
128
129 this.file.openAsync(StyxUtils.OREAD, this);
130 }
131 }
132
133 private synchronized void readNextChunk()
134 {
135 if (!this.eof)
136 {
137
138
139 this.file.readAsync(this.offset, this);
140 this.offset += this.file.getIoUnit();
141 this.numOutstandingMessages++;
142 }
143 }
144
145 public void replyArrived(StyxMessage rMessage, StyxMessage tMessage)
146 {
147 if (rMessage instanceof RopenMessage)
148 {
149
150 this.nextStage();
151 }
152 else if (rMessage instanceof RreadMessage)
153 {
154 this.numOutstandingMessages--;
155 RreadMessage rReadMsg = (RreadMessage)rMessage;
156 TreadMessage tReadMsg = (TreadMessage)tMessage;
157 if (rReadMsg.getCount() != 0)
158 {
159 this.bytesDownloaded += rReadMsg.getCount();
160 try
161 {
162 if (rReadMsg.getCount() == tReadMsg.getCount())
163 {
164
165
166 this.readNextChunk();
167 }
168 else
169 {
170
171
172
173 long pos = tReadMsg.getOffset().asLong() + rReadMsg.getCount();
174 int bytesRequired = tReadMsg.getCount() - rReadMsg.getCount();
175 synchronized (this)
176 {
177 this.file.readAsync(pos, bytesRequired, this);
178 this.numOutstandingMessages++;
179 }
180 }
181 if (this.fout != null)
182 {
183
184 fout.write(rReadMsg.getData().buf(), tReadMsg.getOffset().asLong());
185 }
186 }
187 catch(IOException ioe)
188 {
189 this.error("error writing to " + this.file + ": " +
190 ioe.getMessage(), null);
191 }
192 }
193 else
194 {
195
196
197 this.eof = true;
198 }
199 if (this.eof && this.numOutstandingMessages == 0)
200 {
201
202
203 this.closeFile();
204 if (this.callback == null)
205 {
206 this.file.fireDownloadComplete();
207 }
208 else
209 {
210 callback.replyArrived(rMessage, tMessage);
211 }
212 }
213 }
214 }
215
216 private void closeFile()
217 {
218 if (this.fout != null)
219 {
220 try
221 {
222 this.fout.close();
223 }
224 catch(IOException ioe)
225 {
226 CStyxFile.getLogger().debug("IOException when closing " +
227 this.file.getPath() + ": " + ioe.getMessage());
228 }
229 }
230 }
231
232 public void error(String message, StyxMessage tMessage)
233 {
234
235 this.closeFile();
236 String errMsg = "Error downloading from " + this.file.getPath() + ": " + message;
237 if (this.callback == null)
238 {
239 this.file.fireError(errMsg);
240 }
241 else
242 {
243 this.callback.error(errMsg, tMessage);
244 }
245 }
246 }