package org.sakaiproject.shortenedurl.impl;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.sakaiproject.shortenedurl.api.ShortenedUrlService;
/**
* This implementation of {@link org.sakaiproject.shortenedurl.api.ShortenedUrlService} uses bit.ly to shorten URLs
*
* @author Steve Swinsburg (steve.swinsburg@gmail.com)
*
*/
public class BitlyUrlService implements ShortenedUrlService {
private static Log log = LogFactory.getLog(BitlyUrlService.class);
private String login;
private String apiKey;
private final String BITLY_API_URL = "http://api.bit.ly/v3/shorten";
/**
* Shorten the give URL using the bit.ly service
*/
public String shorten(String url) {
//check auth params are set
checkAuth();
//setup url params
Map<String,String> params = new HashMap<String,String>();
params.put("login", login);
params.put("apiKey", apiKey);
params.put("format", "txt");
params.put("longUrl", url);
//do it
String response = doGet(BITLY_API_URL, params);
//TODO add caching since the bitly API is rate limited and we want to store the key and original URL for future lookups
return response;
}
/**
* Not implemented, simply calls generateShortUrl(String url)
*/
public String shorten(String url, boolean secure) {
return shorten(url);
}
/**
* Not implemented and not needed. The short URL will be a bit.ly URL that will resolve to the original URL.
*/
public String resolve(String key) {
return null;
}
public void init() {
log.debug("Sakai BitlyUrlService init().");
}
/**
* Helper to check auth is set
*/
private void checkAuth() {
if(StringUtils.isBlank(login) || StringUtils.isBlank(apiKey)){
throw new IllegalArgumentException("Missing auth for BitlyUrlService: login=" + login + ", key=" + apiKey);
}
}
/**
* Helper to URL encode a string
* @param s string to encode
* @return
*/
private String encode(String s){
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error(e.getClass() + ":" + e.getMessage());
}
return null;
}
/**
* Makes a GET request to the given address. Any query string should be appended already.
* @param address the fully qualified URL to make the request to
* @return
*/
private String doGet(String address){
try {
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(address);
HttpResponse response = httpclient.execute(httpget);
//check reponse code
StatusLine status = response.getStatusLine();
if(status.getStatusCode() != 200) {
log.error("Error shortening URL. Status: " + status.getStatusCode() + ", reason: " + status.getReasonPhrase());
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toString(entity);
}
} catch (Exception e) {
log.error(e.getClass() + ":" + e.getMessage());
}
return null;
}
/**
* Make a GET request and append the Map of parameters onto the query string.
* @param address the fully qualified URL to make the request to
* @param parameters the Map of parameters, ie key,value pairs
* @return
*/
private String doGet(String address, Map<String, String> parameters){
try {
List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
for (Map.Entry<String,String> entry : parameters.entrySet()) {
queryParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
URI uri = URIUtils.createURI(null, address, -1, null, URLEncodedUtils.format(queryParams, "UTF-8"), null);
log.info(uri.toString());
return doGet(uri.toString());
} catch (URISyntaxException e) {
log.error(e.getClass() + ":" + e.getMessage());
}
return null;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}