Skip to content

Commit 2fa2b48

Browse files
author
Karl Rieb
committed
Improve upload and download style routes with convenience methods and documentation.
1 parent ac41059 commit 2fa2b48

File tree

12 files changed

+667
-140
lines changed

12 files changed

+667
-140
lines changed

examples/android/src/main/java/com/dropbox/core/examples/android/DownloadFileTask.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ protected File doInBackground(DbxFiles.FileMetadata... params) {
6464
return null;
6565
}
6666

67-
// Upload the file.
67+
// Download the file.
6868
try (OutputStream outputStream = new FileOutputStream(file)) {
69-
mDbxClient.files.downloadBuilder(metadata.pathLower).
70-
rev(metadata.rev).run(outputStream);
69+
mDbxClient.files.download(metadata.pathLower, metadata.rev)
70+
.download(outputStream);
7171
}
7272

7373
// Tell android about the file

examples/android/src/main/java/com/dropbox/core/examples/android/FileThumbnailRequestHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Result load(Request request, int networkPolicy) throws IOException {
5252
.size(DbxFiles.ThumbnailSize.w1024h768())
5353
.start();
5454

55-
return new Result(downloader.body, Picasso.LoadedFrom.NETWORK);
55+
return new Result(downloader.getInputStream(), Picasso.LoadedFrom.NETWORK);
5656
} catch (DbxException e) {
5757
throw new IOException(e);
5858
}

examples/android/src/main/java/com/dropbox/core/examples/android/UploadFileTask.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ protected DbxFiles.FileMetadata doInBackground(String... params) {
6060
try (InputStream inputStream = new FileInputStream(localFile)) {
6161
return mDbxClient.files.uploadBuilder(remoteFolderPath + "/" + remoteFileName)
6262
.mode(DbxFiles.WriteMode.overwrite())
63-
.run(inputStream);
63+
.uploadAndFinish(inputStream);
6464
} catch (DbxException | IOException e) {
6565
mException = e;
6666
}

examples/upload-file/src/com/dropbox/core/examples/upload_file/Main.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import com.dropbox.core.v2.DbxFiles;
1010
import com.dropbox.core.v2.DbxPathV2;
1111

12+
import java.io.File;
1213
import java.io.FileInputStream;
1314
import java.io.IOException;
1415
import java.io.InputStream;
16+
import java.util.Date;
1517
import java.util.Locale;
1618
import java.util.logging.Level;
1719
import java.util.logging.Logger;
@@ -82,11 +84,15 @@ private static int _main(String[] args)
8284
DbxClientV2 dbxClient = new DbxClientV2(requestConfig, authInfo.accessToken, authInfo.host);
8385

8486
// Make the API call to upload the file.
87+
File localFile = new File(localPath);
8588
DbxFiles.FileMetadata metadata;
8689
try {
87-
InputStream in = new FileInputStream(localPath);
90+
InputStream in = new FileInputStream(localFile);
8891
try {
89-
metadata = dbxClient.files.uploadBuilder(dropboxPath).run(in);
92+
metadata = dbxClient.files.uploadBuilder(dropboxPath)
93+
.mode(DbxFiles.WriteMode.add())
94+
.clientModified(new Date(localFile.lastModified()))
95+
.uploadAndFinish(in);
9096
} finally {
9197
in.close();
9298
}

examples/web-file-browser/src/com/dropbox/core/examples/web_file_browser/DropboxBrowse.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ public void doUpload(HttpServletRequest request, HttpServletResponse response)
262262
String fullTargetPath = targetFolder + "/" + fileName;
263263
DbxFiles.FileMetadata metadata;
264264
try {
265-
metadata = dbxClient.files.uploadBuilder(fullTargetPath).run(filePart.getInputStream());
265+
metadata = dbxClient.files.upload(fullTargetPath)
266+
.uploadAndFinish(filePart.getInputStream());
266267
}
267268
catch (DbxException ex) {
268269
common.handleDbxException(response, user, ex, "upload(" + jq(fullTargetPath) + ", ...)");

generator/java.babelg.py

+35-30
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,6 @@ def parse_field_ref(ref, api_namespace, api_data_type):
161161

162162
def uses_builder_pattern(api_route):
163163
if is_struct_type(api_route.request_data_type):
164-
style = api_route.attrs.get('style', 'rpc')
165-
if style in ('upload', 'download'):
166-
return True
167-
168164
n_optional = len(api_route.request_data_type.all_optional_fields)
169165
return n_optional > 1
170166
else:
@@ -178,20 +174,26 @@ def format_route_ref(api, namespace, route):
178174
return format_route(api_namespace, api_route)
179175

180176

181-
def format_route(api_namespace, api_route):
177+
def format_route(api_namespace, api_route, allow_builder=True):
178+
required_fields_only = False
182179
if uses_builder_pattern(api_route):
183-
return '%s#%s' % (namespace_ref(api_namespace), builder_method_name(api_route))
184-
elif is_void_type(api_route.request_data_type) or is_union_type(api_route.request_data_type):
180+
if allow_builder:
181+
return '%s#%s' % (namespace_ref(api_namespace), builder_method_name(api_route))
182+
else:
183+
required_fields_only = True
184+
185+
if is_void_type(api_route.request_data_type) or is_union_type(api_route.request_data_type):
185186
return '%s#%s' % (namespace_ref(api_namespace), routename(api_route.name))
186-
else:
187-
# by default, all doc refs should point to the method that
188-
# accepts the most arguments
189-
unpacked_types = (
190-
field_type(api_namespace.name, field, boxed=False, generics=False)
191-
for field in api_route.request_data_type.all_fields
192-
)
193-
args = ",".join(unpacked_types)
194-
return '%s#%s(%s)' % (namespace_ref(api_namespace), routename(api_route.name), args)
187+
188+
# by default, all doc refs should point to the method that
189+
# accepts the most arguments
190+
fields = api_route.request_data_type.all_required_fields if required_fields_only else api_route.request_data_type.all_fields
191+
unpacked_types = (
192+
field_type(api_namespace.name, field, boxed=False, generics=False)
193+
for field in fields
194+
)
195+
args = ",".join(unpacked_types)
196+
return '%s#%s(%s)' % (namespace_ref(api_namespace), routename(api_route.name), args)
195197

196198

197199
def format_data_type_ref(data_type):
@@ -709,7 +711,7 @@ def generate_packed_method(self, namespace, route, doc_out):
709711
resname = 'Object' if result_name == 'void' else result_name
710712
errname = 'Object' if error_name == 'void' else error_name
711713
doc_out('The {@link com.dropbox.core.DbxUploader} returned by '
712-
'{@link %s}.' % method_javadoc_name)
714+
'{@link %s}.' % format_route(namespace, route, allow_builder=False))
713715
uploader = classname(route.name + '_uploader')
714716
with self.block('public static class %s '
715717
'extends com.dropbox.core.DbxUploader<%s,%s,%s>' %
@@ -895,7 +897,11 @@ def generate_builder(self, namespace, route, rtype, ret, outer, doc_out):
895897

896898
# Create a start() method to use the builder.
897899
out('')
898-
doc_out('Issues the request.')
900+
if style in ('upload', 'download'):
901+
out('@Override')
902+
# inherit doc from parent
903+
else:
904+
doc_out('Issues the request.')
899905
out('public %s start() throws %s, DbxException' % (rtype, exc_name))
900906
with self.block():
901907
packed_class = maptype(namespace, route.request_data_type)
@@ -923,24 +929,23 @@ def generate_route_stuff(self, namespace, route, outer, doc_out):
923929
if style == 'upload':
924930
rtype = classname(route.name + '_uploader')
925931
ret = 'return '
926-
self.generate_builder(namespace, route, rtype, ret, outer, doc_out)
927932
elif style == 'download':
928933
rtype = 'com.dropbox.core.DbxDownloader<%s>' % result_name
929934
ret = 'return '
930-
self.generate_builder(namespace, route, rtype, ret, outer, doc_out)
931935
else:
932936
rtype = result_name
933937
ret = '' if rtype == 'void' else 'return '
934-
# Generate a shortcut with required args.
935-
self.generate_unpacked_method(namespace, route, rtype, ret, doc_out, required_only=True)
936-
n_optional = len(route.request_data_type.all_optional_fields)
937-
# Generate a builder if there are two or more optional args.
938-
# If there's only 1 optional argument then we might as well
939-
# just offer two overloaded methods.
940-
if n_optional == 1:
941-
self.generate_unpacked_method(namespace, route, rtype, ret, doc_out)
942-
elif n_optional > 1:
943-
self.generate_builder(namespace, route, rtype, ret, outer, doc_out)
938+
939+
# Generate a shortcut with required args.
940+
self.generate_unpacked_method(namespace, route, rtype, ret, doc_out, required_only=True)
941+
n_optional = len(route.request_data_type.all_optional_fields)
942+
# Generate a builder if there are two or more optional args.
943+
# If there's only 1 optional argument then we might as well
944+
# just offer two overloaded methods.
945+
if n_optional == 1:
946+
self.generate_unpacked_method(namespace, route, rtype, ret, doc_out)
947+
elif n_optional > 1:
948+
self.generate_builder(namespace, route, rtype, ret, outer, doc_out)
944949

945950
def generate_field_assignment(self, namespace, field):
946951
out = self.emit

src/com/dropbox/core/DbxDownloader.java

+127-6
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,140 @@
22

33
import com.dropbox.core.util.IOUtil;
44

5+
import java.io.Closeable;
56
import java.io.InputStream;
7+
import java.io.IOException;
8+
import java.io.OutputStream;
69

7-
public class DbxDownloader<R> {
8-
public final R result;
9-
public final InputStream body;
10+
/**
11+
* Class for handling download requests.
12+
*
13+
* This class provides methods for downloading a request body and reading the server response.
14+
*
15+
* Example usage:
16+
*
17+
* <pre><code>
18+
* FileOutputStream out = new FileOutputStream("test.txt");
19+
* try {
20+
* response = downloader.download(out);
21+
* } finally {
22+
* out.close();
23+
* }
24+
*</code></pre>
25+
*
26+
* Example using {@link #getInputStream}:
27+
*
28+
* <pre><code>
29+
* FileOutputStream out = new FileOutputStream("test.txt");
30+
* response = downloader.getResult();
31+
* try {
32+
* InputStream in = downloader.getInputStream();
33+
* // read from in, write to out
34+
* } finally {
35+
* downloader.close();
36+
* }
37+
*</code></pre>
38+
*/
39+
public class DbxDownloader<R> implements Closeable {
40+
private final R result;
41+
private final InputStream body;
42+
43+
private boolean closed;
1044

1145
public DbxDownloader(R result, InputStream body) {
1246
this.result = result;
1347
this.body = body;
48+
49+
this.closed = false;
50+
}
51+
52+
/**
53+
* Returns the server response.
54+
*
55+
* Returns the response from the server that is separate from the response body (data to be
56+
* downloaded).
57+
*
58+
* @return Response from server
59+
*/
60+
public R getResult() {
61+
return result;
62+
}
63+
64+
/**
65+
* Returns the {@link InputStream} containing the response body bytes. Remember to call {@link
66+
* #close} after reading the stream to properly free up resources.
67+
*
68+
* @return Response body input stream.
69+
*
70+
* @see #download(OutputStream)
71+
*
72+
* @throws IllegalStateException if this downloader has already been closed (see {@link #close})
73+
*/
74+
public InputStream getInputStream() {
75+
assertOpen();
76+
return body;
77+
}
78+
79+
/**
80+
* Downloads the response body to the given {@link OutputStream} and returns the server
81+
* response.
82+
*
83+
* This method manages closing this downloader's resources, so no further calls to {@link
84+
* #close} are necessary. The underlying {@code InputStream} returned by {@link #getInputStream}
85+
* will be closed by this method.
86+
*
87+
* This method is the equivalent of
88+
*
89+
* <pre><code>
90+
* try {
91+
* InputStream in = downloader.getInputStream();
92+
* // read from in, write to out
93+
* return downloader.getResult();
94+
* } finally {
95+
* downloader.close();
96+
* }
97+
* </code></pre>
98+
*
99+
* @param out {@code OutputStream} to write response body to
100+
*
101+
* @return Response from server
102+
*
103+
* @throws DbxException if an error occurs reading the response or response body
104+
* @throws IOException if an error occurs writing the response body to the output stream.
105+
* @throws IllegalStateException if this downloader has already been closed (see {@link #close})
106+
*/
107+
public R download(OutputStream out) throws DbxException, IOException {
108+
try {
109+
IOUtil.copyStreamToStream(getInputStream(), out);
110+
} catch (IOUtil.WriteException ex) {
111+
// write exceptions should be IOException
112+
throw ex.getCause();
113+
} catch (IOException ex) {
114+
// everything else is a Network I/O problem
115+
throw new DbxException.NetworkIO(ex);
116+
} finally {
117+
close();
118+
}
119+
120+
return result;
121+
}
122+
123+
/**
124+
* Closes this downloader and releases its underlying resources.
125+
*
126+
* After calling this method, calls to {@link getInputStream} will fail.
127+
*/
128+
@Override
129+
public void close() {
130+
if (!closed) {
131+
IOUtil.closeQuietly(body);
132+
closed = true;
133+
}
14134
}
15135

16-
public void close()
17-
{
18-
IOUtil.closeInput(body);
136+
private void assertOpen() {
137+
if (closed) {
138+
throw new IllegalStateException("This downloader is already closed.");
139+
}
19140
}
20141
}

0 commit comments

Comments
 (0)