package org.limewire.rest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.nio.entity.NStringEntity;
import org.json.JSONException;
import org.json.JSONObject;
import org.limewire.core.api.Category;
import org.limewire.core.api.FilePropertyKey;
import org.limewire.core.api.library.LibraryFileList;
import org.limewire.core.api.library.LocalFileItem;
import org.limewire.core.api.search.GroupedSearchResult;
import org.limewire.core.api.search.SearchResult;
import org.limewire.core.api.search.SearchResultList;
import org.limewire.http.HttpCoreUtils;
import org.limewire.io.IOUtils;
import org.limewire.util.CommonUtils;
import org.limewire.util.FileUtils;
import org.limewire.util.StringUtils;
/**
* Static constants and utility methods to support REST functions.
*/
public abstract class RestUtils {
public static final String GET = "GET";
public static final String PUT = "PUT";
public static final String POST = "POST";
public static final String DELETE = "DELETE";
private static final String ENCODING = "UTF-8";
private static final String ACCESS_FILE = "restaccess.txt";
/** Symbols used for random string generator. */
private static final char[] SYMBOLS = new char[62];
static {
for (int i = 0; i < 10; i++) {
SYMBOLS[i] = (char) ('0' + i);
}
for (int i = 0; i < 26; i++) {
SYMBOLS[i + 10] = (char) ('A' + i);
}
for (int i = 0; i < 26; i++) {
SYMBOLS[i + 36] = (char) ('a' + i);
}
}
/**
* Generates a random alphanumeric string with the specified length.
*/
public static String createRandomString(int length) {
char[] buf = new char[length];
Random random = new Random();
for (int i = 0; i < length; i++) {
buf[i] = SYMBOLS[random.nextInt(SYMBOLS.length)];
}
return new String(buf);
}
/**
* Returns a new HttpEntity containing the specified content string.
*/
public static HttpEntity createStringEntity(String content) throws IOException {
return new NStringEntity(content, ENCODING);
}
/**
* Performs percent decoding on the specified string according to the
* OAuth 1.0a specification.
*/
public static String percentDecode(String s) {
try {
// Decode string. Plus sign should remain unchanged instead of
// decoded into space char.
return URLDecoder.decode(s.replace("+", "%2B"), ENCODING);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
/**
* Performs percent encoding on the specified string according to the
* OAuth 1.0a specification.
*/
public static String percentEncode(String s) {
try {
// Encode string. For OAuth, unreserved characters like tilde
// must not be encoded. Also, space char should be percent encoded
// instead of changed to plus sign.
return URLEncoder.encode(s, ENCODING).replace("+", "%20").replace("%7E", "~");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
/**
* Returns the base URI by stripping off the query parameters from the
* specified URI string.
*/
public static String getBaseUri(String uriStr) {
// Strip off query parameters.
int pos = uriStr.indexOf("?");
return (pos < 0) ? uriStr : uriStr.substring(0, pos);
}
/**
* Parses the URI in the specified request, and returns URI target. The
* target is the piece between the prefix and the query parameters. For
* example, if the URI is "http://localhost/remote/library/files?type=audio"
* and the prefix is "/library", then the target is "/files".
*/
public static String getUriTarget(HttpRequest request, String uriPrefix) throws IOException {
// Get uri string.
String uriStr = request.getRequestLine().getUri();
// Strip off uri prefix.
int pos = uriStr.indexOf(uriPrefix);
if (pos < 0) throw new IOException("Invalid URI");
String uriTarget = uriStr.substring(pos + uriPrefix.length());
// Strip off query parameters.
pos = uriTarget.indexOf("?");
return (pos < 0) ? uriTarget : uriTarget.substring(0, pos);
}
/**
* Returns a map of name/value pairs corresponding to the query parameters
* in the specified request.
*/
public static Map<String, String> getQueryParams(HttpRequest request) throws IOException {
// Get uri string.
String uriStr = request.getRequestLine().getUri();
return getQueryParams(uriStr);
}
/**
* Returns a map of name/value pairs corresponding to the query parameters
* in the specified URI string.
*/
public static Map<String, String> getQueryParams(String uriStr) throws IOException {
try {
// Get query parameters.
URI uri = new URI(uriStr);
return HttpCoreUtils.parseQuery(uri, null);
} catch (URISyntaxException e) {
throw new IOException(e);
}
}
/**
* Returns the REST access secret.
*/
public static String getAccessSecret() throws IOException {
// Read access secret from file.
File accessFile = new File(CommonUtils.getUserSettingsDir(), ACCESS_FILE);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(accessFile));
return reader.readLine();
} finally {
IOUtils.close(reader);
}
}
/**
* Updates the REST access secret if necessary.
*/
public static void updateAccessSecret() {
// Update access secret only if not already saved.
File accessFile = new File(CommonUtils.getUserSettingsDir(), ACCESS_FILE);
if (!accessFile.exists()) {
String secret = RestUtils.createRandomString(32);
byte[] bytes = StringUtils.toUTF8Bytes(secret);
FileUtils.verySafeSave(CommonUtils.getUserSettingsDir(), ACCESS_FILE, bytes);
}
}
/**
* Creates the JSON description object for the specified local file item.
*/
public static JSONObject createFileItemJson(LocalFileItem fileItem) throws JSONException {
String filename = fileItem.getFileName();
Category category = fileItem.getCategory();
String artist = (String) fileItem.getProperty(FilePropertyKey.AUTHOR);
String album = (String) fileItem.getProperty(FilePropertyKey.ALBUM);
String genre = (String) fileItem.getProperty(FilePropertyKey.GENRE);
String title = (String) fileItem.getProperty(FilePropertyKey.TITLE);
JSONObject jsonObj = new JSONObject();
jsonObj.put("filename", filename);
jsonObj.put("category", category.getSchemaName());
jsonObj.put("size", fileItem.getSize());
jsonObj.put("id", fileItem.getUrn());
jsonObj.put("artist", (category == Category.AUDIO && artist != null) ? artist : "");
jsonObj.put("album", (category == Category.AUDIO && album != null) ? album : "");
jsonObj.put("genre", (category == Category.AUDIO && genre != null) ? genre : "");
jsonObj.put("title", (category == Category.AUDIO && title != null) ? title : filename);
return jsonObj;
}
/**
* Creates the JSON description object for the specified library file list.
*/
public static JSONObject createLibraryJson(LibraryFileList fileList) throws JSONException {
JSONObject jsonObj = new JSONObject();
jsonObj.put("name", "Library");
jsonObj.put("size", fileList.size());
jsonObj.put("id", "library");
return jsonObj;
}
/**
* Creates the JSON description object for the specified search list.
*/
public static JSONObject createSearchJson(SearchResultList searchList) throws JSONException {
JSONObject jsonObj = new JSONObject();
jsonObj.put("name", searchList.getSearchQuery());
jsonObj.put("size", searchList.getGroupedResults().size());
jsonObj.put("id", searchList.getGuid());
return jsonObj;
}
/**
* Creates the JSON description object for the specified grouped search
* result.
*/
public static JSONObject createSearchResultJson(GroupedSearchResult result) throws JSONException {
String filename = result.getFileName();
SearchResult searchResult = result.getSearchResults().get(0);
Category category = searchResult.getCategory();
String artist = (String) searchResult.getProperty(FilePropertyKey.AUTHOR);
String album = (String) searchResult.getProperty(FilePropertyKey.ALBUM);
String genre = (String) searchResult.getProperty(FilePropertyKey.GENRE);
String title = (String) searchResult.getProperty(FilePropertyKey.TITLE);
JSONObject jsonObj = new JSONObject();
jsonObj.put("filename", filename);
jsonObj.put("category", category.getSchemaName());
jsonObj.put("size", searchResult.getSize());
jsonObj.put("id", result.getUrn());
jsonObj.put("magnetUrl", searchResult.getMagnetURL());
jsonObj.put("sources", result.getSources().size());
jsonObj.put("spam", searchResult.isSpam());
jsonObj.put("artist", (category == Category.AUDIO && artist != null) ? artist : "");
jsonObj.put("album", (category == Category.AUDIO && album != null) ? album : "");
jsonObj.put("genre", (category == Category.AUDIO && genre != null) ? genre : "");
jsonObj.put("title", (category == Category.AUDIO && title != null) ? title : filename);
return jsonObj;
}
}