package com.socrata.datasync.deltaimporter2; import com.socrata.datasync.HttpUtility; import org.apache.http.HttpStatus; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ContentType; import org.codehaus.jackson.map.ObjectMapper; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class DatasyncDirectory { private static HttpUtility http; private static String datasync = "/datasync/id/"; private static String completedFolder = "completed/"; private static String signaturesFolder = "signatures/"; private static ObjectMapper mapper = new ObjectMapper(); private static String baseFolder; private URIBuilder baseUri; /** * Creates a new DatasyncDirectory object for a given dataset * @param http an HttpUtility instance with credentials set up * @param domain the host domain in which the dataset can be found, i.e. "opendata.socrata.com" * @param datasetId the 4x4 id of the dataset */ public DatasyncDirectory(HttpUtility http, String domain, String datasetId) { this.http = http; this.baseFolder = datasync + datasetId + "/"; this.baseUri = new URIBuilder() .setScheme("https") .setHost(domain); } /** * Returns the complete path if one exists to the most recent signature file, otherwise null. * e.g. /datasync/id/some-4by4/completed/2014/6/3/signatures/02:32:42.567-filename.ssig */ public String getPathToSignature() throws ParseException, IOException, URISyntaxException { List<String> years = lsDirectory(completedFolder); if (years.size() > 0) { StringBuilder path = new StringBuilder(completedFolder); String year = findMostRecentContent(years, new SimpleDateFormat("yyyy")); path.append(year); String month = findMostRecentContent(lsDirectory(path.toString()), new SimpleDateFormat("MM")); path.append(month); String day = findMostRecentContent(lsDirectory(path.toString()), new SimpleDateFormat("dd")); path.append(day).append(signaturesFolder); String file = findMostRecentContent(lsDirectory(path.toString()), new SimpleDateFormat("hh:mm:ss.SSS")); path.append(file); return baseFolder + path.toString(); } else { return null; } } /** * Returns the contents of the given directory within this DatasyncDirectory. * @param path the path to the directory of interest, relative to this DatasyncDirectory, * e.g. '/completed' or '/completed/y/m/d/signatures/' * @return a list of the contents within the directory */ public List<String> lsDirectory(String path) throws URISyntaxException, IOException { URI uri = baseUri.setPath(baseFolder + path).build(); try(CloseableHttpResponse response = http.get(uri, ContentType.APPLICATION_JSON.getMimeType())) { int status = response.getStatusLine().getStatusCode(); if (status == HttpStatus.SC_OK || status == HttpStatus.SC_NOT_MODIFIED) { @SuppressWarnings("unchecked") ArrayList<String> ret = mapper.readValue(response.getEntity().getContent(), ArrayList.class); return ret; } else { // it isn't a show-stopper to be unable to read directories return new ArrayList<>(); } } } /** * Finds the most recent item in a directory * @param directoryContents the return value from lsDirectory * @param df the dateformater to apply to the directory contents, e.g. "yyyy" for the year directory * or "hh:mm:ss.SSS" for the lowest directory * @return the url-decoded item in the directory corresponding to the most recent time */ public String findMostRecentContent(List<String> directoryContents, final SimpleDateFormat df) throws ParseException, UnsupportedEncodingException { if (directoryContents == null || directoryContents.size() == 0) { return null; } int mostRecentIdx = 0; Date mostRecent = df.parse(cleanString(directoryContents.get(0))); Date date; for(int i=1; i < directoryContents.size(); i++){ date = df.parse(cleanString(directoryContents.get(i))); if (date.compareTo(mostRecent) > 0) { mostRecent = date; mostRecentIdx = i; } } return URLDecoder.decode(directoryContents.get(mostRecentIdx), "UTF-8"); } /** * Cleans the given string to work with the expected date formats needed for ordering the directory contents; * @param directoryItem a string, presumably one returned from lsDirectory * @return the string url-decoded and stripped of the slash and possble filename, leaving only the date items of the string */ private static String cleanString(String directoryItem) throws UnsupportedEncodingException { String withFilenameRemoved = directoryItem.split("-")[0]; String withTrailingSlashRemoved = withFilenameRemoved.split("/")[0]; return URLDecoder.decode(withTrailingSlashRemoved, "UTF-8"); } }