1

Please recommend the optimal approach for parsing urlencoded or JSON-encoded responses when using Jetty HttpClient.

For example, I have created the following utility class for sending ADM-messages and use BufferingResponseListener there, with UrlEncoded.decodeUtf8To​ (for parsing bearer token response) and JSON.parse (for parsing message sending response):

private final HttpClient mHttpClient;
private final String mTokenRequest;

private String mAccessToken;
private long mExpiresIn;

public Adm(HttpClient httpClient) {
    mHttpClient = httpClient;

    MultiMap<String> params = new MultiMap<>();
    params.add("grant_type", "client_credentials");
    params.add("scope", "messaging:push");
    params.add("client_id", "amzn1.application-oa2-client.XXXXX");
    params.add("client_secret", "XXXXX");
    mTokenRequest = UrlEncoded.encode(params, null, false);
}

private final BufferingResponseListener mMessageListener = new BufferingResponseListener() {
    @Override
    public void onComplete(Result result) {
        if (!result.isSucceeded()) {
            if (result.getResponse().getStatus() % 100 == 4) {
                String jsonStr = getContentAsString(StandardCharsets.UTF_8);
                Map<String, String> resp = (Map<String, String>) JSON.parse(jsonStr);
                String reason = resp.get("reason");
                if ("AccessTokenExpired".equals(reason)) {
                    postToken();
                } else if ("Unregistered".equals(reason)) {
                    // delete the invalid ADM registration id from the database
                }
            }
            return;
        }

        String jsonStr = getContentAsString(StandardCharsets.UTF_8);
        Map<String, String> resp = (Map<String, String>) JSON.parse(jsonStr);
        String oldRegistrationId = (String) result.getRequest().getAttributes().get("registrationID");
        String newRegistrationId = resp.get("registrationID");
        if (newRegistrationId != null && !newRegistrationId.equals(oldRegistrationId)) {
            // update the changed ADM registration id in the database
        }
    }
};

private final BufferingResponseListener mTokenListener = new BufferingResponseListener() {
    @Override
    public void onComplete(Result result) {
        if (result.isSucceeded()) {
            String urlencodedStr = getContentAsString(StandardCharsets.UTF_8);
            MultiMap<String> params = new MultiMap<>();
            UrlEncoded.decodeUtf8To(urlencodedStr, params);
            long now = System.currentTimeMillis() / 1000;
            mExpiresIn = now + Long.parseLong(params.getString("expires_in"));
            mAccessToken = params.getString("access_token");
        }
    }
};

public void postMessage(String registrationId, int uid, String jsonStr) {
    long now = System.currentTimeMillis() / 1000;
    if (mAccessToken == null || mAccessToken.length() < 32 || mExpiresIn < now) {
        postToken();
        return;
    }

    mHttpClient.POST(String.format("https://api.amazon.com/messaging/registrations/%1$s/messages", registrationId))
        .header(HttpHeader.ACCEPT, "application/json")
        .header(HttpHeader.CONTENT_TYPE, "application/json")
        .header(HttpHeader.AUTHORIZATION, "Bearer " + mAccessToken)
        .header("X-Amzn-Type-Version", "com.amazon.device.messaging.ADMMessage@1.0")
        .header("X-Amzn-Accept-Type", "com.amazon.device.messaging.ADMSendResult@1.0")
        .attribute("registrationID", registrationId)
        .content(new StringContentProvider(jsonStr))
        .send(mMessageListener);
}

private void postToken() {
    mHttpClient.POST("https://api.amazon.com/auth/O2/token")
        .header(HttpHeader.ACCEPT, "application/json")
        .header(HttpHeader.CONTENT_TYPE, "application/x-www-form-urlencoded")
        .content(new StringContentProvider(mTokenRequest))
        .send(mTokenListener);
}

The above class works okay, but seeing that there are Jetty-methods with InputStream in arguments, like

UrlEncoded.decodeTo​(java.io.InputStream in, MultiMap map, java.lang.String charset, int maxLength, int maxKeys)

and

JSON.parse​(java.io.InputStream in)

I wonder if there is a smarter way to fetch and parse... maybe with something more effective than BufferingResponseListener?

In other words my question is please:

How to use the "streaming" version of the above parsing methods with HttpClient?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416

0 Answers0