First pass implementation of new Fusion Tables API - fixes #539

This commit is contained in:
Tom Morris 2013-02-11 16:33:51 -05:00
parent 2464421014
commit 7fb95ebbad
5 changed files with 213 additions and 227 deletions

View File

@ -29,20 +29,18 @@
package com.google.refine.extension.gdata; package com.google.refine.extension.gdata;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import com.google.gdata.client.GoogleService; import com.google.api.client.auth.oauth2.Credential;
import com.google.gdata.client.Service.GDataRequest; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.gdata.client.Service.GDataRequest.RequestType; import com.google.api.client.http.AbstractInputStreamContent;
import com.google.gdata.util.ContentType; import com.google.api.services.fusiontables.Fusiontables;
import com.google.gdata.util.ServiceException; import com.google.api.services.fusiontables.Fusiontables.Query.Sql;
import com.google.api.services.fusiontables.Fusiontables.Query.SqlGet;
import com.google.api.services.fusiontables.Fusiontables.Table.ImportRows;
import com.google.api.services.fusiontables.model.FusiontablesImport;
import com.google.api.services.fusiontables.model.Sqlresponse;
/** /**
* @author Tom Morris <tfmorris@gmail.com> * @author Tom Morris <tfmorris@gmail.com>
@ -51,54 +49,83 @@ import com.google.gdata.util.ServiceException;
public class FusionTableHandler { public class FusionTableHandler {
final static private String FUSION_TABLES_SERVICE_URL = static private Sqlresponse executeQuery (Fusiontables service, String query)
"https://www.google.com/fusiontables/api/query"; throws IOException {
// "https://www.googleapis.com/fusiontables/v1/query"; Sql sql = service.query().sql(query);
Sqlresponse response = sql.execute();
final static private Pattern CSV_VALUE_PATTERN = return response;
Pattern.compile("([^,\\r\\n\"]*|\"(([^\"]*\"\")*[^\"]*)\")(,|\\r?\\n)"); }
static public GDataRequest createFusionTablesPostRequest( static String createTable(Fusiontables service, String name, List<String> columnNames) throws IOException {
GoogleService service, RequestType requestType, String query) StringBuffer sb = new StringBuffer();
throws IOException, ServiceException { sb.append("CREATE TABLE '");
sb.append(name);
URL url = new URL(FUSION_TABLES_SERVICE_URL); sb.append("' (");
GDataRequest request = service.getRequestFactory().getRequest( boolean first = true;
requestType, url, new ContentType("application/x-www-form-urlencoded")); for (String columnName : columnNames) {
if (first) {
OutputStreamWriter writer = first = false;
new OutputStreamWriter(request.getRequestStream()); } else {
writer.append("sql=" + URLEncoder.encode(query, "UTF-8") + "&alt=csv"); sb.append(',');
writer.flush(); }
writer.close(); sb.append("'");
sb.append(columnName);
return request; sb.append("': STRING");
}
sb.append(")");
String createQuery = sb.toString();
Sqlresponse response = executeQuery(service, createQuery);
// response.getTableId(); // FIXME: Oh wait, there's no such F*ing method!!!
return getTableId(response);
} }
static public GDataRequest createFusionTablesRequest( private static String getTableId(Sqlresponse response) {
GoogleService service, RequestType requestType, String query) List<Object> row = response.getRows().get(0);
throws IOException, ServiceException { int i = 0;
URL url = new URL(FUSION_TABLES_SERVICE_URL + "?sql=" + for (String colname : response.getColumns()) {
URLEncoder.encode(query, "UTF-8")+"&alt=csv"); if ("tableid".equals(colname)) {
return service.getRequestFactory().getRequest( return (String) row.get(i);
requestType, url, ContentType.TEXT_PLAIN); }
}
return null;
} }
/**
* Insert a set of rows and optionally return the IDs of the new rows.
*
* @param service a Fusiontables object
* @param sql SQL statement to do the inserts
* @param returnIds true to return the IDs of the newly inserted rows
* @return
* @throws IOException
*/
static Long insertRows(Fusiontables service, String tableId, AbstractInputStreamContent mediaContent) throws IOException {
ImportRows importRows = service.table().importRows(tableId, mediaContent);
importRows.setIsStrict(false);
FusiontablesImport response = importRows.execute();
return response.getNumRowsReceived();
}
static String getFusionTableKey(URL url) { static String getFusionTableKey(URL url) {
String tableId = getParamValue(url,"dsrcid"); String tableId = getParamValue(url,"dsrcid"); // old style phased out
// TODO: Any special id format considerations to worry about? if (tableId == null || tableId.isEmpty()) {
// if (tableId.startsWith("p") || !tableId.contains(".")) { tableId = getParamValue(url,"docid");
// return tableId; }
// }
return tableId; return tableId;
} }
static public GoogleService getFusionTablesGoogleService(String token) { static public Fusiontables getFusionTablesService(String token) {
GoogleService service = new GoogleService("fusiontables", GDataExtension.SERVICE_APP_NAME); Credential credential = new GoogleCredential().setAccessToken(token);
if (token != null) { Fusiontables fusiontables = new Fusiontables.Builder(
service.setAuthSubToken(token); GDataExtension.HTTP_TRANSPORT, GDataExtension.JSON_FACTORY, credential)
} .setApplicationName(GDataExtension.SERVICE_APP_NAME)
return service; .build();;
return fusiontables;
} }
static boolean isFusionTableURL(URL url) { static boolean isFusionTableURL(URL url) {
@ -109,60 +136,17 @@ public class FusionTableHandler {
} }
return url.getHost().endsWith(".google.com") return url.getHost().endsWith(".google.com")
&& url.getPath().startsWith("/fusiontables/DataSource") && url.getPath().startsWith("/fusiontables/DataSource")
&& query.contains("dsrcid="); && (query.contains("dsrcid=")||query.contains("docid="));
} }
static public List<List<String>> parseFusionTablesResults(GDataRequest request) throws IOException { static Sqlresponse runFusionTablesSelect(Fusiontables service, String selectQuery)
List<List<String>> rows = new ArrayList<List<String>>(); throws IOException {
List<String> row = null;
Scanner scanner = new Scanner(request.getResponseStream(), "UTF-8"); // FIXME: alt=csv doesn't actually work! It will attempt to parse response as JSON and die
while (scanner.hasNextLine()) { // perhaps use .executeUnparsed() would work?
scanner.findWithinHorizon(CSV_VALUE_PATTERN, 0); SqlGet query = service.query().sqlGet(selectQuery);//.setAlt("csv");
MatchResult match = scanner.match(); Sqlresponse response = query.execute();
String quotedString = match.group(2); return response;
String decoded = quotedString == null ? match.group(1) : quotedString.replaceAll("\"\"", "\"");
if (row == null) {
row = new ArrayList<String>();
}
row.add(decoded);
if (!match.group(4).equals(",")) {
if (row != null) {
rows.add(row);
row = null;
}
}
}
scanner.close();
if (row != null) {
rows.add(row);
}
return rows;
}
static public List<List<String>> listTables(GoogleService service) throws IOException, ServiceException {
List<List<String>> rows = runFusionTablesSelect(service, "SHOW TABLES");
// Format is id, name to which we append a link URL based on ID
if (rows.size() > 1) { // excluding headers
for (int i = 1; i < rows.size(); i++) {
List<String> row = rows.get(i);
if (row.size() >= 2) {
String id = row.get(0);
row.add("https://www.google.com/fusiontables/DataSource?docid=" + id);
}
}
}
return rows;
}
static public List<List<String>> runFusionTablesSelect(GoogleService service, String selectQuery)
throws IOException, ServiceException {
GDataRequest request = createFusionTablesRequest(service, RequestType.QUERY, selectQuery);
request.execute();
return parseFusionTablesResults(request);
} }
static private String getParamValue(URL url, String key) { static private String getParamValue(URL url, String key) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, Thomas F. Morris * Copyright (c) 2010,2013 Thomas F. Morris and other contributors
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,8 +34,10 @@ import java.util.List;
import org.json.JSONObject; import org.json.JSONObject;
import com.google.gdata.client.GoogleService; import com.google.api.services.fusiontables.Fusiontables;
import com.google.gdata.util.ServiceException; import com.google.api.services.fusiontables.model.Column;
import com.google.api.services.fusiontables.model.Sqlresponse;
import com.google.api.services.fusiontables.model.Table;
import com.google.refine.ProjectMetadata; import com.google.refine.ProjectMetadata;
import com.google.refine.importers.TabularImportingParserBase; import com.google.refine.importers.TabularImportingParserBase;
@ -61,7 +63,7 @@ public class FusionTableImporter {
JSONObject options, JSONObject options,
List<Exception> exceptions) { List<Exception> exceptions) {
GoogleService service = FusionTableHandler.getFusionTablesGoogleService(token); Fusiontables service = FusionTableHandler.getFusionTablesService(token);
parse( parse(
service, service,
project, project,
@ -89,7 +91,7 @@ public class FusionTableImporter {
final ImportingJob job; final ImportingJob job;
final String fileSource; final String fileSource;
final GoogleService service; final Fusiontables service;
final List<FTColumnData> columns; final List<FTColumnData> columns;
final int batchSize; final int batchSize;
@ -102,7 +104,7 @@ public class FusionTableImporter {
boolean usedHeaders = false; boolean usedHeaders = false;
public FusionTableBatchRowReader(ImportingJob job, String fileSource, public FusionTableBatchRowReader(ImportingJob job, String fileSource,
GoogleService service, String tableId, List<FTColumnData> columns, Fusiontables service, String tableId, List<FTColumnData> columns,
int batchSize) { int batchSize) {
this.job = job; this.job = job;
this.fileSource = fileSource; this.fileSource = fileSource;
@ -143,14 +145,10 @@ public class FusionTableImporter {
if (rowsOfCells == null || (nextRow >= batchRowStart + rowsOfCells.size() && !end)) { if (rowsOfCells == null || (nextRow >= batchRowStart + rowsOfCells.size() && !end)) {
int newBatchRowStart = batchRowStart + (rowsOfCells == null ? 0 : rowsOfCells.size()); int newBatchRowStart = batchRowStart + (rowsOfCells == null ? 0 : rowsOfCells.size());
try { rowsOfCells = getRowsOfCells(newBatchRowStart);
rowsOfCells = getRowsOfCells(newBatchRowStart); batchRowStart = newBatchRowStart;
batchRowStart = newBatchRowStart;
GDataImporter.setProgress(job, fileSource, -1 /* batchRowStart * 100 / totalRows */);
GDataImporter.setProgress(job, fileSource, -1 /* batchRowStart * 100 / totalRows */);
} catch (ServiceException e) {
throw new IOException(e);
}
} }
if (rowsOfCells != null && nextRow - batchRowStart < rowsOfCells.size()) { if (rowsOfCells != null && nextRow - batchRowStart < rowsOfCells.size()) {
@ -161,18 +159,19 @@ public class FusionTableImporter {
} }
private List<List<Object>> getRowsOfCells(int startRow) throws IOException, ServiceException { private List<List<Object>> getRowsOfCells(int startRow) throws IOException {
List<List<Object>> rowsOfCells = new ArrayList<List<Object>>(batchSize); List<List<Object>> rowsOfCells = new ArrayList<List<Object>>(batchSize);
String query = baseQuery + " OFFSET " + startRow + " LIMIT " + batchSize; String query = baseQuery + " OFFSET " + startRow + " LIMIT " + batchSize;
List<List<String>> rows = FusionTableHandler.runFusionTablesSelect(service, query); Sqlresponse sqlresponse = FusionTableHandler.runFusionTablesSelect(service, query);
List<List<Object>> rows = sqlresponse.getRows();
if (rows.size() > 1) { if (rows.size() > 1) {
for (int i = 1; i < rows.size(); i++) { for (int i = 1; i < rows.size(); i++) {
List<String> row = rows.get(i); List<Object> row = rows.get(i);
List<Object> rowOfCells = new ArrayList<Object>(row.size()); List<Object> rowOfCells = new ArrayList<Object>(row.size());
for (int j = 0; j < row.size() && j < columns.size(); j++) { for (int j = 0; j < row.size() && j < columns.size(); j++) {
String text = row.get(j); String text = (String)row.get(j);
if (text.isEmpty()) { if (text.isEmpty()) {
rowOfCells.add(null); rowOfCells.add(null);
} else { } else {
@ -208,7 +207,7 @@ public class FusionTableImporter {
} }
static public void parse( static public void parse(
GoogleService service, Fusiontables service,
Project project, Project project,
ProjectMetadata metadata, ProjectMetadata metadata,
final ImportingJob job, final ImportingJob job,
@ -222,37 +221,34 @@ public class FusionTableImporter {
try { try {
List<FTColumnData> columns = new ArrayList<FusionTableImporter.FTColumnData>(); List<FTColumnData> columns = new ArrayList<FusionTableImporter.FTColumnData>();
List<List<String>> rows = FusionTableHandler.runFusionTablesSelect(service, "DESCRIBE " + id); Table table = service.table().get(id).execute();
if (rows.size() > 1) { for (Column col : table.getColumns()) {
for (int i = 1; i < rows.size(); i++) { FTColumnData cd = new FTColumnData();
List<String> row = rows.get(i); cd.name = col.getName();
if (row.size() >= 2) { String type = col.getType();
FTColumnData cd = new FTColumnData(); if (type.equals("STRING")) {
cd.name = row.get(1); cd.type = FTColumnType.STRING;
cd.type = FTColumnType.STRING; } else if (type.equals("NUMBER")) {
cd.type = FTColumnType.NUMBER;
if (row.size() > 2) { } else if (type.equals("DATETIME")) {
String type = row.get(2).toLowerCase(); cd.type = FTColumnType.DATETIME;
if (type.equals("number")) { } else if (type.equals("LOCATION")) {
cd.type = FTColumnType.NUMBER; cd.type = FTColumnType.LOCATION;
} else if (type.equals("datetime")) { } else {
cd.type = FTColumnType.DATETIME; // TODO: unknown type
} else if (type.equals("location")) { cd.type = FTColumnType.STRING;
cd.type = FTColumnType.LOCATION;
}
}
columns.add(cd);
}
} }
columns.add(cd);
setProgress(job, docUrlString, -1); }
// Force these options for the next call because each fusion table setProgress(job, docUrlString, -1);
// is strictly structured with a single line of headers.
JSONUtilities.safePut(options, "ignoreLines", 0); // number of blank lines at the beginning to ignore // Force these options for the next call because each fusion table
JSONUtilities.safePut(options, "headerLines", 1); // number of header lines // is strictly structured with a single line of headers.
JSONUtilities.safePut(options, "ignoreLines", 0); // number of blank lines at the beginning to ignore
TabularImportingParserBase.readTable( JSONUtilities.safePut(options, "headerLines", 1); // number of header lines
TabularImportingParserBase.readTable(
project, project,
metadata, metadata,
job, job,
@ -262,14 +258,10 @@ public class FusionTableImporter {
options, options,
exceptions exceptions
); );
setProgress(job, docUrlString, 100); setProgress(job, docUrlString, 100);
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
exceptions.add(e); exceptions.add(e);
} catch (ServiceException e) {
e.printStackTrace();
exceptions.add(e);
} }
} }

View File

@ -6,15 +6,16 @@ import java.util.List;
import org.json.JSONObject; import org.json.JSONObject;
import com.google.gdata.client.GoogleService; import com.google.api.client.http.AbstractInputStreamContent;
import com.google.gdata.client.Service.GDataRequest; import com.google.api.client.http.ByteArrayContent;
import com.google.gdata.client.Service.GDataRequest.RequestType; import com.google.api.client.http.HttpResponseException;
import com.google.gdata.util.ServiceException; import com.google.api.services.fusiontables.Fusiontables;
import com.google.refine.exporters.TabularSerializer; import com.google.refine.exporters.TabularSerializer;
final class FusionTableSerializer implements TabularSerializer { final class FusionTableSerializer implements TabularSerializer {
GoogleService service; private static final int BATCH_SIZE = 20;
Fusiontables service;
String tableName; String tableName;
List<Exception> exceptions; List<Exception> exceptions;
@ -23,7 +24,7 @@ final class FusionTableSerializer implements TabularSerializer {
StringBuffer sbBatch; StringBuffer sbBatch;
int rows; int rows;
FusionTableSerializer(GoogleService service, String tableName, List<Exception> exceptions) { FusionTableSerializer(Fusiontables service, String tableName, List<Exception> exceptions) {
this.service = service; this.service = service;
this.tableName = tableName; this.tableName = tableName;
this.exceptions = exceptions; this.exceptions = exceptions;
@ -44,68 +45,75 @@ final class FusionTableSerializer implements TabularSerializer {
public void addRow(List<CellData> cells, boolean isHeader) { public void addRow(List<CellData> cells, boolean isHeader) {
if (isHeader) { if (isHeader) {
columnNames = new ArrayList<String>(cells.size()); columnNames = new ArrayList<String>(cells.size());
StringBuffer sb = new StringBuffer();
sb.append("CREATE TABLE '");
sb.append(tableName);
sb.append("' (");
boolean first = true;
for (CellData cellData : cells) { for (CellData cellData : cells) {
columnNames.add(cellData.text); columnNames.add(cellData.text);
}
if (first) {
first = false;
} else {
sb.append(',');
}
sb.append("'");
sb.append(cellData.text);
sb.append("': STRING");
}
sb.append(")");
try { try {
String createQuery = sb.toString(); tableId = FusionTableHandler.createTable(service, tableName, columnNames);
GDataRequest createTableRequest = FusionTableHandler.createFusionTablesPostRequest(
service, RequestType.INSERT, createQuery);
createTableRequest.execute();
List<List<String>> createTableResults =
FusionTableHandler.parseFusionTablesResults(createTableRequest);
if (createTableResults != null && createTableResults.size() == 2) {
tableId = createTableResults.get(1).get(0);
}
} catch (Exception e) { } catch (Exception e) {
tableId = null;
exceptions.add(e); exceptions.add(e);
} }
} else if (tableId != null) { } else if (tableId != null) {
if (sbBatch == null) { if (sbBatch == null) {
sbBatch = new StringBuffer(); sbBatch = new StringBuffer();
} }
formulateInsert(cells, sbBatch); formatCsv(cells, sbBatch);
rows++; rows++;
if (rows % 20 == 0) { if (rows % BATCH_SIZE == 0) {
sendBatch(); if (!sendBatch()) {
return;
}
} }
} }
} }
private void sendBatch() { private boolean sendBatch() {
try { try {
GDataRequest createTableRequest = FusionTableHandler.createFusionTablesPostRequest( // FIXME: text/csv doesn't work even though that's what the content is
service, RequestType.INSERT, sbBatch.toString()); AbstractInputStreamContent content = ByteArrayContent.fromString("application/octet-stream", sbBatch.toString());
createTableRequest.execute();
// AbstractInputStreamContent content = new InputStreamContent("application/octet-stream",
// // TODO: we really want to do GZIP compression here
// new ByteArrayInputStream(sbBatch.toString().getBytes("UTF-8")));
Long count = FusionTableHandler.insertRows(service, tableId, content);
if (count != BATCH_SIZE) {
exceptions.add(new IOException("only imported %d of %d rows"));
}
} catch (IOException e) { } catch (IOException e) {
exceptions.add(e); exceptions.add(e);
} catch (ServiceException e) { if (e instanceof HttpResponseException) {
exceptions.add(e); int code = ((HttpResponseException)e).getStatusCode();
if (code >= 400 && code < 500) {
return false;
}
// 500s appear to be retried automatically by li
}
} finally { } finally {
sbBatch = null; sbBatch = null;
} }
return true;
}
private void formatCsv(List<CellData> cells, StringBuffer sb) {
boolean first = true;
for (int i = 0; i < cells.size() && i < columnNames.size(); i++) {
CellData cellData = cells.get(i);
if (!first) {
sb.append(',');
} else {
first = false;
}
sb.append("\"");
if (cellData != null && cellData.text != null) {
sb.append(cellData.text.replaceAll("\"", "\\\\\""));
}
sb.append("\"");
}
sb.append("\n");
} }
// Old-style SQL INSERT can be removed once we're sure importRows will work
private void formulateInsert(List<CellData> cells, StringBuffer sb) { private void formulateInsert(List<CellData> cells, StringBuffer sb) {
StringBuffer sbColumnNames = new StringBuffer(); StringBuffer sbColumnNames = new StringBuffer();
StringBuffer sbValues = new StringBuffer(); StringBuffer sbValues = new StringBuffer();

View File

@ -49,7 +49,9 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.google.gdata.client.GoogleService; import com.google.api.services.fusiontables.Fusiontables;
import com.google.api.services.fusiontables.model.Table;
import com.google.api.services.fusiontables.model.TableList;
import com.google.gdata.client.docs.DocsService; import com.google.gdata.client.docs.DocsService;
import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.SpreadsheetService;
@ -59,6 +61,7 @@ import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed; import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.data.spreadsheet.WorksheetEntry; import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed; import com.google.gdata.data.spreadsheet.WorksheetFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException; import com.google.gdata.util.ServiceException;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
@ -125,13 +128,15 @@ public class GDataImportingController implements ImportingController {
try { try {
listSpreadsheets(GDataExtension.getDocsService(token), writer); listSpreadsheets(GDataExtension.getDocsService(token), writer);
listFusionTables(FusionTableHandler.getFusionTablesGoogleService(token), writer); listFusionTables(FusionTableHandler.getFusionTablesService(token), writer);
} catch (AuthenticationException e) {
TokenCookie.deleteToken(request, response);
} catch (ServiceException e) { } catch (ServiceException e) {
e.printStackTrace(); e.printStackTrace();
} finally {
writer.endArray();
writer.endObject();
} }
writer.endArray();
writer.endObject();
} catch (JSONException e) { } catch (JSONException e) {
throw new ServletException(e); throw new ServletException(e);
} finally { } finally {
@ -167,27 +172,24 @@ public class GDataImportingController implements ImportingController {
} }
} }
private void listFusionTables(GoogleService service, JSONWriter writer) private void listFusionTables(Fusiontables service, JSONWriter writer)
throws IOException, ServiceException, JSONException { throws IOException, ServiceException, JSONException {
List<List<String>> rows = FusionTableHandler.listTables(service); Fusiontables.Table.List listTables = service.table().list();
if (rows.size() > 1) { // excluding headers TableList tablelist = listTables.execute();
for (int i = 1; i < rows.size(); i++) { for (Table table : tablelist.getItems()) {
List<String> row = rows.get(i); String id = table.getTableId();
if (row.size() >= 2) { String name = table.getName();
String id = row.get(0); String link = "https://www.google.com/fusiontables/DataSource?docid=" + id;
String name = row.get(1);
String link = row.get(2); // Add JSON object to our stream
writer.object();
writer.object(); writer.key("docId"); writer.value(id);
writer.key("docId"); writer.value(id); writer.key("docLink"); writer.value(link);
writer.key("docLink"); writer.value(link); writer.key("docSelfLink"); writer.value(link);
writer.key("docSelfLink"); writer.value(link); writer.key("title"); writer.value(name);
writer.key("title"); writer.value(name); writer.key("type"); writer.value("table");
writer.key("type"); writer.value("table"); writer.endObject();
writer.endObject();
}
}
} }
} }

View File

@ -46,7 +46,6 @@ import org.json.JSONWriter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.google.gdata.client.GoogleService;
import com.google.gdata.client.docs.DocsService; import com.google.gdata.client.docs.DocsService;
import com.google.gdata.client.spreadsheet.CellQuery; import com.google.gdata.client.spreadsheet.CellQuery;
import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.SpreadsheetService;
@ -292,8 +291,9 @@ public class UploadCommand extends Command {
static private String uploadFusionTable( static private String uploadFusionTable(
Project project, final Engine engine, final Properties params, Project project, final Engine engine, final Properties params,
String token, String name, List<Exception> exceptions) { String token, String name, List<Exception> exceptions) {
GoogleService service = FusionTableHandler.getFusionTablesGoogleService(token);
FusionTableSerializer serializer = new FusionTableSerializer(service, name, exceptions); FusionTableSerializer serializer = new FusionTableSerializer(
FusionTableHandler.getFusionTablesService(token), name, exceptions);
CustomizableTabularExporterUtilities.exportRows( CustomizableTabularExporterUtilities.exportRows(
project, engine, params, serializer); project, engine, params, serializer);