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.io.InputStream;
33 import java.io.FileInputStream;
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.TwriteMessage;
43 import uk.ac.rdg.resc.jstyx.messages.RwriteMessage;
44
45 import uk.ac.rdg.resc.jstyx.StyxUtils;
46
47 /***
48 * Callback that is used when uploading a file to the server. Contains
49 * state that needs to persist between message exchanges with the server. See
50 * CStyxFile.uploadAsync()
51 *
52 * @author jdb
53 * $Revision: 475 $
54 * $Date: 2005-11-09 17:39:55 +0000 (Wed, 09 Nov 2005) $
55 * $Log$
56 * Revision 1.5 2005/11/09 17:39:55 jonblower
57 * Fixed bug with omission of response to Ropen/Rcreate message
58 *
59 * Revision 1.4 2005/11/07 22:01:35 jonblower
60 * Added code to close stream when UploadCallback has been created from a File object
61 *
62 * Revision 1.3 2005/11/04 19:25:14 jonblower
63 * Added code to write a zero-byte message to represent EOF
64 *
65 * Revision 1.1 2005/08/05 13:46:40 jonblower
66 * Factored out all callback objects from CStyxFile into separate classes
67 *
68 */
69
70 public class UploadCallback extends MessageCallback
71 {
72 private InputStream in;
73 private byte[] bytes;
74 private long offset;
75 private MessageCallback callback;
76 private CStyxFile file;
77 private StyxConnection conn;
78 private boolean closeStreamWhenComplete;
79
80 public UploadCallback(CStyxFile file, File localFile, MessageCallback callback)
81 {
82 this.init(file, null, callback);
83 this.closeStreamWhenComplete = true;
84 try
85 {
86 this.in = new FileInputStream(localFile);
87 }
88 catch(FileNotFoundException fnfe)
89 {
90 this.error("file does not exist", null);
91 }
92 }
93
94 public UploadCallback(CStyxFile file, InputStream in, MessageCallback callback)
95 {
96 this.init(file, in, callback);
97 }
98
99 private void init(CStyxFile file, InputStream in, MessageCallback callback)
100 {
101 this.file = file;
102 this.conn = this.file.getConnection();
103 this.in = in;
104 this.bytes = null;
105 this.offset = 0;
106 this.callback = callback;
107 this.closeStreamWhenComplete = false;
108 }
109
110 public void nextStage(StyxMessage rMessage, StyxMessage tMessage)
111 {
112 if (this.file.isOpen())
113 {
114
115 try
116 {
117 if (this.bytes == null)
118 {
119 this.bytes = new byte[this.file.getIoUnit()];
120 }
121
122 int n = in.read(this.bytes);
123 if (n > 0)
124 {
125
126 this.file.writeAsync(this.bytes, 0, n, this.offset, true, this);
127 }
128 else
129 {
130
131
132 this.file.writeAsync(new byte[0], this.offset, true, this);
133 }
134 }
135 catch(IOException ioe)
136 {
137 this.error("IOException occurred: " + ioe.getMessage(), null);
138 }
139 }
140 else
141 {
142
143
144 this.file.openOrCreateAsync(false, StyxUtils.OWRITE | StyxUtils.OTRUNC, this);
145 }
146 }
147
148 public void replyArrived(StyxMessage rMessage, StyxMessage tMessage)
149 {
150 if (rMessage instanceof RwriteMessage)
151 {
152 TwriteMessage tWriteMsg = (TwriteMessage)tMessage;
153 RwriteMessage rWriteMsg = (RwriteMessage)rMessage;
154 if (tWriteMsg.getCount() == rWriteMsg.getNumBytesWritten())
155 {
156 if (rWriteMsg.getNumBytesWritten() > 0)
157 {
158 this.offset += rWriteMsg.getNumBytesWritten();
159 this.nextStage(rMessage, tMessage);
160 }
161 else
162 {
163
164
165 this.file.close();
166 if (this.closeStreamWhenComplete)
167 {
168 try
169 {
170 this.in.close();
171 }
172 catch(IOException ioe)
173 {
174
175 }
176 }
177 if (this.callback == null)
178 {
179 this.file.fireUploadComplete();
180 }
181 else
182 {
183 this.callback.replyArrived(rMessage, tMessage);
184 }
185 }
186 }
187 else
188 {
189 this.error("Error writing data: tried to write " + tWriteMsg.getCount()
190 + " bytes, actually wrote " + rWriteMsg.getNumBytesWritten()
191 + " bytes.", tMessage);
192 }
193 }
194 else
195 {
196
197 this.nextStage(rMessage, tMessage);
198 }
199 }
200
201 public void error(String message, StyxMessage tMessage)
202 {
203 if (this.in != null)
204 {
205 try
206 {
207 this.in.close();
208 }
209 catch(IOException ioe)
210 {
211 CStyxFile.getLogger().debug("IOException when closing input stream: "
212 + ioe.getMessage());
213 }
214 }
215 String errMsg = "Error uploading: " + message;
216 if (this.callback == null)
217 {
218 this.file.fireError(errMsg);
219 }
220 else
221 {
222 this.callback.error(errMsg, tMessage);
223 }
224 }
225 }