/*
* Copyright 2012 GitHub Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.mobile.gauges.core;
import static com.github.mobile.gauges.core.GaugesConstants.URL_CLIENTS;
import static com.github.mobile.gauges.core.GaugesConstants.URL_EMBEDDED;
import static com.github.mobile.gauges.core.GaugesConstants.URL_GAUGES;
import static com.github.mobile.gauges.core.GaugesConstants.URL_PUSHER_AUTH;
import static com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES;
import com.github.kevinsawicki.http.HttpRequest;
import com.github.kevinsawicki.http.HttpRequest.HttpRequestException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
import java.util.List;
/**
* Gauges API service
*/
public class GaugesService {
/**
* GSON instance to use for all request
*/
public static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd")
.setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
/**
* Read and connect timeout in milliseconds
*/
private static final int TIMEOUT = 30 * 1000;
private static class ClientWrapper {
private Client client;
}
private static class ClientsWrapper {
private List<Client> clients;
}
private static class GaugesWrapper {
private List<Gauge> gauges;
}
private static class ContentWrapper {
private List<PageContent> content;
}
private static class ReferrersWrapper {
private List<Referrer> referrers;
}
private static class GaugeWrapper {
private Gauge gauge;
}
private static class AuthWrapper {
private String auth;
}
private static class JsonException extends IOException {
private static final long serialVersionUID = 3774706606129390273L;
/**
* Create exception from {@link JsonParseException}
*
* @param cause
*/
public JsonException(JsonParseException cause) {
super(cause.getMessage());
initCause(cause);
}
}
private final String apiKey;
private final String username;
private final String password;
/**
* Create gauges service
*
* @param username
* @param password
*/
public GaugesService(final String username, final String password) {
this.username = username;
this.password = password;
this.apiKey = null;
}
/**
* Create gauges service
*
* @param apiKey
*/
public GaugesService(final String apiKey) {
this.apiKey = apiKey;
this.username = null;
this.password = null;
}
/**
* Execute request
*
* @param request
* @return request
* @throws IOException
*/
protected HttpRequest execute(HttpRequest request) throws IOException {
if (!configure(request).ok())
throw new IOException("Unexpected response code: " + request.code());
return request;
}
private HttpRequest configure(final HttpRequest request) {
request.connectTimeout(TIMEOUT).readTimeout(TIMEOUT);
request.userAgent("GaugesAndroid/1.0");
return addCredentialsTo(request);
}
private HttpRequest addCredentialsTo(HttpRequest request) {
if (apiKey != null)
return request.header("X-Gauges-Token", apiKey);
else
return request.basic(username, password);
}
private <V> V fromJson(HttpRequest request, Class<V> target) throws IOException {
Reader reader = request.bufferedReader();
try {
return GSON.fromJson(reader, target);
} catch (JsonParseException e) {
throw new JsonException(e);
} finally {
try {
reader.close();
} catch (IOException ignored) {
// Ignored
}
}
}
/**
* Get all gauges
*
* @return non-null but possibly empty list of gauges
* @throws IOException
*/
public List<Gauge> getGauges() throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_EMBEDDED));
GaugesWrapper response = fromJson(request, GaugesWrapper.class);
if (response != null && response.gauges != null)
return response.gauges;
return Collections.emptyList();
} catch (HttpRequestException e) {
throw e.getCause();
}
}
/**
* Get content for gauge id
*
* @param gaugeId
* @return non-null but possibly empty list of page content information
* @throws IOException
*/
public List<PageContent> getContent(String gaugeId) throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_GAUGES + gaugeId + "/content"));
ContentWrapper response = fromJson(request, ContentWrapper.class);
if (response != null && response.content != null)
return response.content;
return Collections.emptyList();
} catch (HttpRequestException e) {
throw e.getCause();
}
}
/**
* Get referrers for gauge id
*
* @param gaugeId
* @return non-null but possibly empty list of referrers
* @throws IOException
*/
public List<Referrer> getReferrers(String gaugeId) throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_GAUGES + gaugeId + "/referrers"));
ReferrersWrapper response = fromJson(request, ReferrersWrapper.class);
if (response != null && response.referrers != null)
return response.referrers;
return Collections.emptyList();
} catch (HttpRequestException e) {
throw e.getCause();
}
}
/**
* Create API client with description
*
* @param description
* @return created client
* @throws IOException
*/
public Client createClient(String description) throws IOException {
try {
HttpRequest request = configure(HttpRequest.post(URL_CLIENTS));
request.form("description", description);
if (!request.created())
throw new IOException("Unexpected response code: " + request.code());
ClientWrapper response = fromJson(request, ClientWrapper.class);
return response != null ? response.client : null;
} catch (HttpRequestException e) {
throw e.getCause();
}
}
/**
* Get client with description
*
* @param description
* @return client or null if none found matching description
* @throws IOException
*/
public Client getClient(String description) throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_CLIENTS));
ClientsWrapper response = fromJson(request, ClientsWrapper.class);
if (response != null && response.clients != null)
for (Client client : response.clients)
if (description.equals(client.getDescription()))
return client;
} catch (HttpRequestException e) {
throw e.getCause();
}
return null;
}
/**
* Get gauge with id
*
* @param gaugeId
* @return gauge
* @throws IOException
*/
public Gauge getGauge(String gaugeId) throws IOException {
try {
HttpRequest request = execute(HttpRequest.get(URL_GAUGES + gaugeId));
GaugeWrapper response = fromJson(request, GaugeWrapper.class);
return response != null ? response.gauge : null;
} catch (HttpRequestException e) {
throw e.getCause();
}
}
/**
* Get authentication credentials for pusher subscription to socket and channel
*
* @param socketId
* @param channelName
* @return authentication credentials
* @throws IOException
*/
public String getPusherAuth(final String socketId, final String channelName) throws IOException {
try {
HttpRequest request = configure(HttpRequest.post(URL_PUSHER_AUTH));
request.form("socket_id", socketId);
request.form("channel_name", channelName);
if (!request.ok())
throw new IOException("Unexpected response code: " + request.code());
AuthWrapper response = fromJson(request, AuthWrapper.class);
return response != null ? response.auth : null;
} catch (HttpRequestException e) {
throw e.getCause();
}
}
}