Taming a throttled API with Dynamic Proxies in Java

Recently, at CleverTap, we’ve begun migrating some of our largest clusters to a new protocol (for starters, think ~115 instances at a time). One of the most fun things I’ve had my hands on during this migration was the AWS Systems Manager API.

When we scaled up our migrations gradually from a 10 node cluster, we were challenged with dealing with API throttling exceptions (because sure, who wouldn’t throttle their APIs?). There were two immediate solutions that hit our mind:

  1. Review every usage of the SSM client and handle the throttling exception gracefully
  2. Wrap the SSM client and handle the throttling exception transparently

Naturally, we settled for option 2. I am a big fan of hidden abstractions. So what did we do? We implemented the AWS interface in question, only to discover that we’d have to handle a ton of methods individually (obviously copy/paste). There had to be a better solution!

And then, Google did it’s thing. We discovered Dynamic Proxies. And viola! We were able to transparently handle and implement an auto retry strategy within just 14 lines!

Here’s what it looked like:

MyStubbornAPIInterface actualInstance = … // Create it however you'd create your original instance.
MyStubbornAPIInterface proxiedInstance = (MyStubbornAPIInterface) Proxy.newProxyInstance(actualInstance.getClass().getClassLoader(),
new Class[]{MyStubbornAPIInterface.class}, (proxy, method, args) -> {
while (true) {
try {
return method.invoke(actualInstance, args);
} catch (MyThrottlingException e) {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1, 5) * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
});

The code above can be easily adapted to various SDKs (in our case, it was the AWS SDK).

Now, all we had to do was pass around this proxied instance, and viola, the consumers of this API had no clue that the API implemented an auto retry mechanism!

Cheers!

How to get a File object of an Android raw resource using reflection

Context:

You have a URI to a resource which is placed in the raw directory inside the Android resources directory, res. Say you want to take that raw resource(let’s say it’s an image) and add it to an attachment using FIleBody to a MultiPartEntity. Both these classes are available in the Apache HTTP Components library. FileBody will only allow you to give it a File object in it’s constructor. Certainly, you are stuck as you have the URI to an Android raw resource, and CANNOT create a File object out of it.

 

So what’s the solution? Reflection.

    private File getFileFromRawResource(Uri rUri) {
        String uri = rUri.toString();
        String fn;
        // I've only tested this with raw resources
        if (uri.contains("/raw/")) {
            // Try to get the resource name
            String[] parts = uri.split("/");
            fn = parts[parts.length - 1];
        } else {
            return null;
        }
        // Notice that I've hard-coded the file extension to .jpg
        // I was working with getting a File object of a JPEG image from my raw resources
        String dest = Environment.getExternalStorageDirectory() + "/image.jpg";
        try {
            // Use reflection to get resource ID of the raw resource
            // as we need to get an InputStream to it
            // getResources(),openRawResource() takes only a resource ID
            R.raw r = new R.raw();
            Field frame = R.raw.class.getDeclaredField(fn);
            frame.setAccessible(true);
            int id = (Integer) frame.get(r);
            // Get the InputStream
            InputStream inputStream = getResources().openRawResource(id);
            FileOutputStream fileOutputStream = new FileOutputStream(dest);
            // IOUtils is a class from Apache Commons IO
            // It writes an InputStream to an OutputStream
            IOUtils.copy(inputStream, fileOutputStream);
            fileOutputStream.close();
            return new File(dest);
        } catch (NoSuchFieldException e) {
            Log.e("MyApp", "NoSuchFieldException in getFileFromRawResource()");
        } catch (IllegalAccessException e) {
            Log.e("MyApp", "IllegalAccessException in getFileFromRawResource()");
        } catch (FileNotFoundException e) {
            Log.e("MyApp", "FileNotFoundException in getFileFromRawResource()");
        } catch (IOException e) {
            Log.e("MyApp", "IOException in getFileFromRawResource()");
        }
        return null;
    }    

The code is pretty much self-explanatory. Drop a comment if you have any questions/doubts.