Skip to content

Commit f7a378a

Browse files
committed
Merge pull request #3 from john-morales/master
Support for a listener to be notified of upload progress
2 parents 68b13df + c328614 commit f7a378a

6 files changed

Lines changed: 107 additions & 16 deletions

File tree

src/main/java/com/cloudapp/api/CloudApp.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.cloudapp.api.model.CloudAppAccount;
77
import com.cloudapp.api.model.CloudAppAccountStats;
88
import com.cloudapp.api.model.CloudAppItem;
9+
import com.cloudapp.api.model.CloudAppProgressListener;
910

1011
public interface CloudApp {
1112

@@ -58,7 +59,7 @@ public CloudAppAccount setPassword(String newPassword, String currentPassword)
5859
throws CloudAppException;
5960

6061
/**
61-
* Dispatch an email containing a link to reset the accountÕs password.
62+
* Dispatch an email containing a link to reset the account�s password.
6263
*
6364
* @see http://developer.getcloudapp.com/forgot-password
6465
* @param email
@@ -94,7 +95,7 @@ public CloudAppAccount createAccount(String email, String password, boolean acce
9495

9596
/**
9697
* Add or change the domain used for all links. Optionally, a URL may be provided to
97-
* redirect visitors to the custom domainÕs root. <b>Pro users only</b>
98+
* redirect visitors to the custom domain�s root. <b>Pro users only</b>
9899
*
99100
* @see http://developer.getcloudapp.com/set-custom-domain
100101
* @param domain
@@ -209,6 +210,18 @@ public List<CloudAppItem> getItems(int page, int perPage, CloudAppItem.Type type
209210
*/
210211
public CloudAppItem upload(File file) throws CloudAppException;
211212

213+
/**
214+
*
215+
* @see http://developer.getcloudapp.com/upload-file
216+
* @param file
217+
* The file you wish to upload.
218+
* @param listener
219+
* To receive progress updates during upload
220+
* @throws CloudAppException
221+
* @return
222+
*/
223+
public CloudAppItem upload(File file, CloudAppProgressListener listener) throws CloudAppException;
224+
212225
/**
213226
* Deletes an item
214227
*
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.cloudapp.api.model;
2+
3+
/**
4+
* Listener to receive notification as data's written to the output stream during upload.
5+
*/
6+
public interface CloudAppProgressListener {
7+
void transferred(long written, long length);
8+
9+
public static CloudAppProgressListener NO_OP = new CloudAppProgressListener() {
10+
public void transferred(long written, long length) {}
11+
};
12+
}

src/main/java/com/cloudapp/impl/CloudAppImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.File;
44
import java.util.List;
55

6+
import com.cloudapp.api.model.CloudAppProgressListener;
67
import org.apache.http.auth.AuthScope;
78
import org.apache.http.auth.UsernamePasswordCredentials;
89
import org.apache.http.impl.DefaultConnectionReuseStrategy;
@@ -186,6 +187,16 @@ public CloudAppItem upload(File file) throws CloudAppException {
186187
return items.upload(file);
187188
}
188189

190+
/**
191+
*
192+
* {@inheritDoc}
193+
*
194+
* @see com.cloudapp.api.CloudAppItems#upload(java.io.File, com.cloudapp.api.model.CloudAppProgressListener)
195+
*/
196+
public CloudAppItem upload(File file, CloudAppProgressListener listener) throws CloudAppException {
197+
return items.upload(file, listener);
198+
}
199+
189200
/**
190201
*
191202
* {@inheritDoc}

src/main/java/com/cloudapp/impl/CloudAppInputStream.java

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,64 @@
2323

2424
package com.cloudapp.impl;
2525

26-
import java.io.File;
27-
import java.io.FileInputStream;
28-
import java.io.FileNotFoundException;
29-
import java.io.InputStream;
26+
import java.io.*;
3027

28+
import com.cloudapp.api.model.CloudAppProgressListener;
3129
import org.apache.http.entity.mime.content.InputStreamBody;
3230

3331
public class CloudAppInputStream extends InputStreamBody {
3432

35-
private long length;
33+
private final long length;
34+
private final CloudAppProgressListener listener;
3635

37-
public CloudAppInputStream(InputStream in, String filename, long length) {
36+
public CloudAppInputStream(InputStream in, String filename, long length, CloudAppProgressListener listener) {
3837
super(in, filename);
3938
this.length = length;
39+
this.listener = (listener == null) ? CloudAppProgressListener.NO_OP : listener;
4040
}
4141

42-
protected CloudAppInputStream(File file) throws FileNotFoundException {
43-
this(new FileInputStream(file), file.getName(), file.length());
42+
protected CloudAppInputStream(File file, CloudAppProgressListener listener) throws FileNotFoundException {
43+
this(new FileInputStream(file), file.getName(), file.length(), listener);
44+
}
45+
46+
@Override
47+
public void writeTo(OutputStream out) throws IOException {
48+
super.writeTo( new ListeningOutputStream(out) );
4449
}
4550

4651
@Override
4752
public long getContentLength() {
4853
return length;
4954
}
5055

56+
private class ListeningOutputStream extends FilterOutputStream {
57+
58+
private long bytesWritten;
59+
60+
public ListeningOutputStream(OutputStream out) {
61+
super(out);
62+
bytesWritten = 0L;
63+
}
64+
65+
@Override
66+
public void write(int b) throws IOException {
67+
out.write(b);
68+
listener.transferred(++bytesWritten, length);
69+
}
70+
71+
@Override
72+
public void write(byte[] b) throws IOException {
73+
out.write(b);
74+
bytesWritten += b.length;
75+
listener.transferred(bytesWritten, length);
76+
}
77+
78+
@Override
79+
public void write(byte[] b, int off, int len) throws IOException {
80+
out.write(b, off, len);
81+
bytesWritten += (len - off);
82+
listener.transferred(bytesWritten, length);
83+
}
84+
}
85+
5186
}

src/main/java/com/cloudapp/impl/CloudAppItemsImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.slf4j.LoggerFactory;
2828

2929
import com.cloudapp.api.CloudAppException;
30+
import com.cloudapp.api.model.CloudAppProgressListener;
3031
import com.cloudapp.api.model.CloudAppItem;
3132
import com.cloudapp.impl.model.CloudAppItemImpl;
3233

@@ -162,6 +163,10 @@ public List<CloudAppItem> getItems(int page, int perPage, CloudAppItem.Type type
162163
* @see com.cloudapp.api.CloudAppItems#upload(java.io.File)
163164
*/
164165
public CloudAppItem upload(File file) throws CloudAppException {
166+
return upload( file, CloudAppProgressListener.NO_OP );
167+
}
168+
169+
public CloudAppItem upload(File file, CloudAppProgressListener listener) throws CloudAppException {
165170
try {
166171
// Do a GET request so we have the S3 endpoint
167172
HttpGet req = new HttpGet(NEW_ITEM_URL);
@@ -182,7 +187,7 @@ public CloudAppItem upload(File file) throws CloudAppException {
182187
null);
183188
}
184189

185-
return uploadToAmazon(json, file);
190+
return uploadToAmazon(json, file, listener);
186191

187192
} catch (ClientProtocolException e) {
188193
LOGGER.error("Something went wrong trying to contact the CloudApp API.", e);
@@ -209,7 +214,7 @@ public CloudAppItem upload(File file) throws CloudAppException {
209214
* @throws ParseException
210215
* @throws IOException
211216
*/
212-
private CloudAppItem uploadToAmazon(JSONObject json, File file) throws JSONException,
217+
private CloudAppItem uploadToAmazon(JSONObject json, File file, CloudAppProgressListener listener) throws JSONException,
213218
CloudAppException, ParseException, IOException {
214219
JSONObject params = json.getJSONObject("params");
215220
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
@@ -223,7 +228,7 @@ private CloudAppItem uploadToAmazon(JSONObject json, File file) throws JSONExcep
223228

224229
// Add the actual file.
225230
// We have to use the 'file' parameter for the S3 storage.
226-
InputStreamBody stream = new CloudAppInputStream(file);
231+
InputStreamBody stream = new CloudAppInputStream(file, listener);
227232
entity.addPart("file", stream);
228233

229234
HttpPost uploadRequest = new HttpPost(json.getString("url"));

src/test/java/com/cloudapp/impl/CloudAppItemsImplTest.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.io.File;
66
import java.net.URL;
77
import java.util.List;
8+
import java.util.concurrent.atomic.AtomicLong;
89

10+
import com.cloudapp.api.model.CloudAppProgressListener;
911
import org.json.JSONException;
1012
import org.junit.Assert;
1113
import org.junit.Before;
@@ -16,12 +18,13 @@
1618

1719
public class CloudAppItemsImplTest extends BaseTestCase {
1820

19-
private File file;
21+
private static final String TEST_FILE_NAME = "test_file.txt";
22+
private File file;
2023

2124
@Before
2225
public void setUp() {
2326
super.setUp();
24-
URL fileurl = getClass().getResource("/test_file.txt");
27+
URL fileurl = getClass().getResource( "/" + TEST_FILE_NAME );
2528
file = new File(fileurl.getPath());
2629
}
2730

@@ -50,7 +53,7 @@ public void testDelete() throws JSONException, CloudAppException {
5053
public void testUpload() throws CloudAppException, JSONException {
5154
CloudAppItem o = api.upload(file);
5255
Assert.assertNotNull(o);
53-
assertEquals("test_file.txt", o.getName());
56+
assertEquals(TEST_FILE_NAME, o.getName());
5457
Assert.assertNotNull(o.getCreatedAt());
5558
}
5659

@@ -59,4 +62,16 @@ public void simpleGetItemsTest() throws CloudAppException {
5962
List<CloudAppItem> l = api.getItems(1, 5, null, false, null);
6063
Assert.assertNotNull(l);
6164
}
65+
66+
@Test
67+
public void testUploadListener() throws CloudAppException, JSONException {
68+
final AtomicLong calledCount = new AtomicLong();
69+
CloudAppItem o = api.upload(file, new CloudAppProgressListener() {
70+
public void transferred(long written, long length) {
71+
calledCount.incrementAndGet();
72+
}
73+
});
74+
assertEquals( TEST_FILE_NAME, o.getName() );
75+
assertEquals( 1, calledCount.get() );
76+
}
6277
}

0 commit comments

Comments
 (0)