Skip to content

Commit 0871828

Browse files
author
Karl Rieb
committed
Rename exception classes, parse Retry-After header, and add support for automatic retries in clients.
1 parent 703a83f commit 0871828

28 files changed

+2221
-1264
lines changed

ChangeLog.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
- Fix bug that hid certain routes containing union request arguments.
21
- Use getter methods instead of public final fields.
2+
- Rename exception classes to be consistent with Java practices (e.g. end in "Exception").
3+
- Move DbxException inner classes out into their own files.
4+
- Expose Retry-After backoff for rate limiting exceptions.
5+
- Add configuration setting for automatically retrying failed requests.
6+
- Fix bug that hid certain routes containing union request arguments.
37
- Add Java packages that map to endpoint namespaces.
48
- Break out nested classes into their own files in the appropriate packages.
59
- Change format of builder methods.
@@ -12,6 +16,7 @@
1216
- Fix deserialization bug with Union containing tags with optional values.
1317
- Make read timeouts more easily configurable for StandardHttpRequestor.
1418
- Add longpoll example.
19+
- Separate integration tests from unit tests and enable unit tests by default.
1520
- Fix android example bugs and linter warnings
1621
- Fix compilation error
1722
- Fix upload failure bug

generator/java.babelg.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2996,8 +2996,8 @@ def generate_data_type_struct(self, data_type):
29962996
out('super(%s);' % parent_args)
29972997

29982998
for field in data_type.fields:
2999-
self.generate_field_assignment(field, allow_default=False)
30002999
self.generate_field_validation(field, allow_default=False)
3000+
self.generate_field_assignment(field, allow_default=False)
30013001

30023002
# required-only constructor
30033003
if data_type.has_optional_fields:
@@ -3362,6 +3362,14 @@ def generate_field_assignment(self, field, lhs=None, rhs=None, allow_default=Tru
33623362
lhs = lhs or ('this.%s' % field.java_name)
33633363
rhs = rhs or field.java_name
33643364

3365+
# our timestamp format only allows for second-level granularity (no millis).
3366+
# enforce this.
3367+
#
3368+
# TODO: gotta be a better way than this...
3369+
if is_timestamp_type(field.data_type.as_babel) and rhs != 'null':
3370+
rhs = 'new %s(%s.getTime() - (%s.getTime() %% 1000))' % (
3371+
JavaClass(self.ctx, "java.util.Date"), rhs, rhs)
3372+
33653373
if allow_default and field.has_default:
33663374
if rhs == 'null':
33673375
out('%s = %s;' % (lhs, field.default_value))

pom.xml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343

4444
<properties>
4545
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
46-
<skipTests>true</skipTests>
4746
<osgi.bnd.noee>false</osgi.bnd.noee>
4847
<!-- BEGIN PRIVATE REPO ONLY -->
4948
<specDir>${project.basedir}/spec</specDir>
@@ -87,6 +86,12 @@
8786
<version>6.9.10</version>
8887
<scope>test</scope>
8988
</dependency>
89+
<dependency>
90+
<groupId>org.mockito</groupId>
91+
<artifactId>mockito-core</artifactId>
92+
<version>1.10.19</version>
93+
<scope>test</scope>
94+
</dependency>
9095
<dependency>
9196
<groupId>com.google.caliper</groupId>
9297
<artifactId>caliper</artifactId>
@@ -192,8 +197,13 @@
192197
<groupId>org.apache.maven.plugins</groupId>
193198
<artifactId>maven-surefire-plugin</artifactId>
194199
<version>2.19.1</version>
200+
</plugin>
201+
<plugin>
202+
<groupId>org.apache.maven.plugins</groupId>
203+
<artifactId>maven-failsafe-plugin</artifactId>
204+
<version>2.19.1</version>
195205
<configuration>
196-
<skipTests>${skipTests}</skipTests>
206+
<trimStackTrace>false</trimStackTrace>
197207
</configuration>
198208
</plugin>
199209
<plugin>

run-tests renamed to run-integration-tests

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ else
4545
exit 1
4646
fi
4747

48-
exec mvn test -DskipTests=false "${args[@]}"
48+
exec mvn integration-test "${args[@]}"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.dropbox.core;
2+
3+
/**
4+
* This is what is thrown when the Dropbox server tells us that it didn't like something about our
5+
* request. This corresponds to the HTTP 400 status code.
6+
*/
7+
public class BadRequestException extends ProtocolException {
8+
private static final long serialVersionUID = 0;
9+
10+
public BadRequestException(String requestId, String message) {
11+
super(requestId, message);
12+
}
13+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.dropbox.core;
2+
3+
/**
4+
* Thrown when the Dropbox server responds with an HTTP status code we didn't expect.
5+
*/
6+
public class BadResponseCodeException extends BadResponseException {
7+
private static final long serialVersionUID = 0L;
8+
9+
private final int statusCode;
10+
11+
public BadResponseCodeException(String requestId, String message, int statusCode) {
12+
super(requestId, message);
13+
this.statusCode = statusCode;
14+
}
15+
16+
public BadResponseCodeException(String requestId, String message, int statusCode, Throwable cause) {
17+
super(requestId, message, cause);
18+
this.statusCode = statusCode;
19+
}
20+
21+
/**
22+
* Returns HTTP status code received from the Dropbox server.
23+
*
24+
* @return HTTP status code returned by Dropbox server
25+
*/
26+
public int getStatusCode() {
27+
return statusCode;
28+
}
29+
}
30+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.dropbox.core;
2+
3+
/**
4+
* Thrown when we the response from the Dropbox server isn't something we expect.
5+
* For example, if the JSON returned by the server is malformed or missing fields.
6+
*/
7+
public class BadResponseException extends ProtocolException {
8+
private static final long serialVersionUID = 0;
9+
10+
public BadResponseException(String requestId, String message) {
11+
super(requestId, message);
12+
}
13+
14+
public BadResponseException(String requestId, String message, Throwable cause) {
15+
super(requestId, message, cause);
16+
}
17+
}
18+

src/main/java/com/dropbox/core/DbxDownloader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public R download(OutputStream out) throws DbxException, IOException {
112112
throw ex.getCause();
113113
} catch (IOException ex) {
114114
// everything else is a Network I/O problem
115-
throw new DbxException.NetworkIO(ex);
115+
throw new NetworkIOException(ex);
116116
} finally {
117117
close();
118118
}

src/main/java/com/dropbox/core/DbxException.java

Lines changed: 15 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import java.io.IOException;
44

55
/**
6-
* The base exception thrown by Dropbox API calls. Normally, you'll need to
7-
* do something specific for {@link InvalidAccessToken} and possibly for
8-
* {@link RetryLater}. The rest you should probably just log and investigate
9-
* manually.
6+
* The base exception thrown by Dropbox API calls. Normally, you'll need to do something specific
7+
* for {@link InvalidAccessTokenException} and possibly for {@link RetryException}. The rest you
8+
* should probably just log and investigate manually.
109
*/
11-
public class DbxException extends Exception
12-
{
13-
public final String requestId;
10+
public class DbxException extends Exception {
11+
private static final long serialVersionUID = 0L;
12+
13+
private final String requestId;
1414

1515
public DbxException(String message) {
1616
this(null, message);
@@ -30,147 +30,18 @@ public DbxException(String requestId, String message, Throwable cause) {
3030
this.requestId = requestId;
3131
}
3232

33-
public static final long serialVersionUID = 0;
34-
3533
/**
36-
* The server said that something went wrong on its end (HTTP 500 error code).
37-
* This indicates bug on the Dropbox server, but there are multiple potential causes.
34+
* Return the unique ID associated with the request that triggered this exception.
3835
*
39-
* <ul>
40-
* <li>Sometimes it's just a bug and there's nothing you can
41-
* do about it until its fixed. Report it on the Dropbox API forums.
42-
* </li>
43-
* <li>Sometimes you're actually making an invalid request, but for some reason
44-
* the server's validation logic isn't catching the problem and it's
45-
* causing the server to error-out somewhere down the line. You may be able to
46-
* fix your request and get things working. This is still a bug on Dropbox's end,
47-
* so you should still report it on the Dropbox API forums.</li>
48-
* <li>Sometimes the error is intermittent. It may only happen once every few
49-
* requests, in which case you can temporarily work around the issue by
50-
* retrying the request. Again, this still counts as a bug so report it on
51-
* the forums.</li>
52-
* <li>Sometimes the error is temporary. For example, Dropbox might be experiencing
53-
* a temporary network or hardware issue. If you wait a few minutes, the error
54-
* might stop happening. You might want to check the forums to see if other
55-
* people are seeing the same thing.</li>
56-
* </ul>
57-
*/
58-
public static final class ServerError extends DbxException
59-
{
60-
public ServerError(String requestId, String message) { super(requestId, message); }
61-
public static final long serialVersionUID = 0;
62-
}
63-
64-
/**
65-
* The server is overloaded, or you have hit a rate limit. Try again later.
66-
*/
67-
public static final class RetryLater extends DbxException
68-
{
69-
// TODO: Maybe parse out the server's recommended delay
70-
public RetryLater(String requestId, String message)
71-
{
72-
super(requestId, message);
73-
}
74-
public static final long serialVersionUID = 0;
75-
}
76-
77-
/**
78-
* Something unexpected happened with either the request or the response.
79-
* This can happen if there's a bug in the client code (including this
80-
* library), if there's a bug in on the Dropbox server, or if Dropbox
81-
* made a change to the API that changed the behavior of something and
82-
* we haven't upgraded our SDK yet.
83-
*
84-
* <p>
85-
* Typically, these kinds of exceptions should be logged, so you can
86-
* investigate later.
87-
* </p>
88-
*/
89-
public static abstract class ProtocolError extends DbxException
90-
{
91-
public ProtocolError(String requestId, String message) { super(requestId, message); }
92-
public ProtocolError(String requestId, String message, Throwable cause) { super(requestId, message, cause); }
93-
public static final long serialVersionUID = 0;
94-
}
95-
96-
/**
97-
* This is what is thrown when the Dropbox server tells us that it didn't
98-
* like something about our request. This corresponds to the HTTP 400 status code.
99-
*/
100-
public static final class BadRequest extends ProtocolError
101-
{
102-
public BadRequest(String requestId, String message) { super(requestId, message); }
103-
public static final long serialVersionUID = 0;
104-
}
105-
106-
/**
107-
* Thrown when we the response from the Dropbox server isn't something we expect.
108-
* For example, if the JSON returned by the server is malformed or missing fields.
109-
*/
110-
public static class BadResponse extends ProtocolError
111-
{
112-
public BadResponse(String requestId, String message) { super(requestId, message); }
113-
public BadResponse(String requestId, String message, Throwable cause) { super(requestId, message, cause); }
114-
public static final long serialVersionUID = 0;
115-
}
116-
117-
/**
118-
* Thrown when the Dropbox server responds with an HTTP status code we didn't expect.
119-
*/
120-
public static class BadResponseCode extends BadResponse
121-
{
122-
public final int statusCode;
123-
124-
public BadResponseCode(String requestId, String message, int statusCode)
125-
{
126-
super(requestId, message);
127-
this.statusCode = statusCode;
128-
}
129-
130-
public BadResponseCode(String requestId, String message, int statusCode, Throwable cause)
131-
{
132-
super(requestId, message, cause);
133-
this.statusCode = statusCode;
134-
}
135-
136-
public static final long serialVersionUID = 0;
137-
}
138-
139-
/**
140-
* This is what gets thrown when there's an IOException when reading or writing
141-
* to the network (when communicating with the Dropbox API servers).
36+
* <p> The ID may be {@code null} if we could not receive a response from the Dropbox servers
37+
* (e.g. from a {@link NetworkIOException}).
14238
*
143-
* <p>
144-
* We use a separate exception class (instead of just relaying IOException) to
145-
* make it easier for you to distinguish between I/O errors communicating with
146-
* Dropbox and I/O errors from your own code.
147-
* </p>
148-
*/
149-
public static final class NetworkIO extends DbxException
150-
{
151-
public final IOException underlying;
152-
public NetworkIO(IOException underlying)
153-
{
154-
super(underlying.toString(), underlying);
155-
this.underlying = underlying;
156-
}
157-
public static final long serialVersionUID = 0;
158-
}
159-
160-
/**
161-
* Gets thrown when the access token you're using to make API calls is invalid.
39+
* <p> Please use this ID when filing bug reports.
16240
*
163-
* <p>
164-
* A more typical situation is that your access token <em>was</em> valid, but the
165-
* user has since "unlinked" your application via the Dropbox website
166-
* (<a href="http://www.dropbox.com/account#applications">http://www.dropbox.com/account#applications</a>).
167-
* When a user unlinks your application, your access tokens for that user become
168-
* invalid. You can re-run the authorization process to obtain a new access token.
169-
* </p>
41+
* @return unique ID associated with the request that caused this exception, or {@code null} if
42+
* one is not available.
17043
*/
171-
public static final class InvalidAccessToken extends DbxException
172-
{
173-
public InvalidAccessToken(String requestId, String message) { super(requestId, message); }
174-
public static final long serialVersionUID = 0;
44+
public String getRequestId() {
45+
return requestId;
17546
}
17647
}

0 commit comments

Comments
 (0)