package com.google.refine.extension.gdata; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.json.JSONObject; import com.google.api.client.http.AbstractInputStreamContent; import com.google.api.client.http.ByteArrayContent; import com.google.api.client.http.HttpResponseException; import com.google.api.services.fusiontables.Fusiontables; import com.google.refine.exporters.TabularSerializer; final class FusionTableSerializer implements TabularSerializer { private static final int BATCH_SIZE = 20; Fusiontables service; String tableName; List<Exception> exceptions; String tableId; List<String> columnNames; StringBuffer sbBatch; int rows; FusionTableSerializer(Fusiontables service, String tableName, List<Exception> exceptions) { this.service = service; this.tableName = tableName; this.exceptions = exceptions; } @Override public void startFile(JSONObject options) { } @Override public void endFile() { if (sbBatch != null) { sendBatch(rows % BATCH_SIZE); } } @Override public void addRow(List<CellData> cells, boolean isHeader) { if (isHeader) { columnNames = new ArrayList<String>(cells.size()); for (CellData cellData : cells) { columnNames.add(cellData.text); } try { tableId = FusionTableHandler.createTable(service, tableName, columnNames); } catch (Exception e) { tableId = null; exceptions.add(e); } } else if (tableId != null) { if (sbBatch == null) { sbBatch = new StringBuffer(); } formatCsv(cells, sbBatch); rows++; if (rows % BATCH_SIZE == 0) { if (!sendBatch(BATCH_SIZE)) { return; } } } } private boolean sendBatch(int batchSize) { try { // TODO: we really want to do GZIP compression here // FIXME: text/csv doesn't work even though that's what the content is AbstractInputStreamContent content = ByteArrayContent.fromString("application/octet-stream", sbBatch.toString()); Long count = FusionTableHandler.insertRows(service, tableId, content); if (count != null && count.intValue() != batchSize) { exceptions.add(new IOException("only imported " + count + " of " + batchSize + " rows")); } } catch (IOException e) { exceptions.add(e); if (e instanceof HttpResponseException) { int code = ((HttpResponseException)e).getStatusCode(); if (code >= 400 && code < 500) { return false; } // 500s appear to be retried automatically by li } } finally { 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"); } public String getUrl() { return tableId == null || exceptions.size() > 0 ? null : "https://www.google.com/fusiontables/DataSource?docid=" + tableId; } }