package com.socrata.datasync; import com.socrata.datasync.config.userpreferences.UserPreferences; import com.socrata.model.importer.Column; import com.socrata.model.importer.Dataset; import com.socrata.model.importer.DatasetInfo; import org.apache.http.HttpException; import org.apache.http.HttpStatus; import org.apache.http.HttpEntity; import org.apache.http.util.EntityUtils; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.ResponseHandler; import org.apache.http.client.utils.URIBuilder; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class DatasetUtils { private static class DatasetInfoResponseHandler implements ResponseHandler<DatasetInfo> { @Override public DatasetInfo handleResponse(final HttpResponse response) throws ClientProtocolException, IOException { StatusLine statusLine = response.getStatusLine(); int status = statusLine.getStatusCode(); if (status >= 200 && status < 300) { HttpEntity entity = response.getEntity(); return entity != null ? mapper.readValue(entity.getContent(), DatasetInfo.class) : null; } else { throw new ClientProtocolException(statusLine.toString()); } } } private static final String LOCATION_DATATYPE_NAME = "location"; private static ObjectMapper mapper = new ObjectMapper().enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY); public static <T> T getDatasetInfo(UserPreferences userPrefs, String viewId, final Class<T> typ) throws URISyntaxException, IOException, HttpException { String justDomain = getDomainWithoutScheme(userPrefs); URI absolutePath = new URIBuilder() .setScheme("https") .setHost(justDomain) .setPath("/api/views/" + viewId) .build(); ResponseHandler<T> handler = new ResponseHandler<T>() { @Override public T handleResponse( final HttpResponse response) throws ClientProtocolException, IOException { StatusLine statusLine = response.getStatusLine(); int status = statusLine.getStatusCode(); if (status >= 200 && status < 300) { HttpEntity entity = response.getEntity(); return entity != null ? mapper.readValue(entity.getContent(), typ) : null; } else { throw new ClientProtocolException(statusLine.toString()); } } }; HttpUtility util = new HttpUtility(userPrefs, true); T datasetInfo = util.get(absolutePath, "application/json", handler); util.close(); return datasetInfo; } public static String getDatasetSample(UserPreferences userPrefs, String viewId, int rowsToSample) throws URISyntaxException, IOException, HttpException { String justDomain = getDomainWithoutScheme(userPrefs); URI absolutePath = new URIBuilder() .setScheme("https") .setHost(justDomain) .setPath("/resource/" + viewId + ".csv") .addParameter("$limit",""+rowsToSample) .build(); ResponseHandler<String> handler = new ResponseHandler<String>() { @Override public String handleResponse( final HttpResponse response) throws ClientProtocolException, IOException { StatusLine statusLine = response.getStatusLine(); int status = statusLine.getStatusCode(); if (status >= 200 && status < 300) { HttpEntity entity = response.getEntity(); return entity != null ? EntityUtils.toString(entity) : null; } else { throw new ClientProtocolException(statusLine.toString()); } } }; HttpUtility util = new HttpUtility(userPrefs, true); String sample = util.get(absolutePath, "application/csv", handler); util.close(); return sample; } public static String getDomainWithoutScheme(UserPreferences userPrefs){ return getDomainWithoutScheme(userPrefs.getDomain()); } public static String getDomainWithoutScheme(String domain){ String[] schemaAndDomain = domain.trim().split("//"); String justDomain = schemaAndDomain[schemaAndDomain.length - 1]; return justDomain.split("[/:]")[0]; } /** * Retruns the field name of the row identifier, if there is one, else null */ public static String getRowIdentifierName(Dataset schema) { Column rowIdentifierColumn = schema.lookupRowIdentifierColumn(); if (rowIdentifierColumn == null) { return null; } else { return rowIdentifierColumn.getFieldName(); } } /** * Returns list of dataset field names in the form: "col1","col2",... * * @param datasetId * @return list of field names or null if there */ public static String getFieldNamesString(UserPreferences userPrefs, String datasetId) throws HttpException, IOException, URISyntaxException { Dataset datasetInfo = getDatasetInfo(userPrefs, datasetId, Dataset.class); return getFieldNamesString(datasetInfo); } /** * Returns list of dataset field names in the form: "col1","col2",... * * @param datasetInfo * @return list of field names or null if there are none */ public static String getFieldNamesString(Dataset datasetInfo) { String columnsValue = ""; List<Column> columns = datasetInfo.getColumns(); for(int i = 0; i < columns.size(); i++) { if(i > 0) columnsValue += ","; columnsValue += "\"" + columns.get(i).getFieldName() + "\""; } return columnsValue; } /** * Returns an array of dataset field names. * * @param datasetInfo * @return array of field names or null if there are none */ public static String[] getFieldNamesArray(Dataset datasetInfo) { List<Column> columns = datasetInfo.getColumns(); String[] columnsArray = new String[columns.size()]; for(int i = 0; i < columns.size(); i++) { columnsArray[i] = columns.get(i).getFieldName(); } return columnsArray; } /** * Returns the set of dataset field names. * * @param datasetInfo * @return array of field names or null if there are none */ public static Set<String> getFieldNamesSet(Dataset datasetInfo) { List<Column> columns = datasetInfo.getColumns(); Set<String> fields = new HashSet<>(); for(int i = 0; i < columns.size(); i++) { fields.add(columns.get(i).getFieldName()); } return fields; } /** * Returns a mapping of dataset field names to their type. * * @param datasetInfo * @return a map of dataset field names to datatypes */ public static Map<String,String> getDatasetTypeMapping(Dataset datasetInfo) { List<Column> columns = datasetInfo.getColumns(); Map<String,String> mapping = new HashMap<>(); for(Column c : columns) { mapping.put(c.getFieldName(), c.getDataTypeName()); } return mapping; } /** * @return true if given dataset has one or more Location columns, false otherwise */ public static boolean hasLocationColumn(Dataset datasetInfo) { List<Column> columns = datasetInfo.getColumns(); for(int i = 0; i < columns.size(); i++) { if(columns.get(i).getDataTypeName().equals(LOCATION_DATATYPE_NAME)) return true; } return false; } }