Java tutorial
// Copyright 2015 The Vanadium Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package io.v.syncslides.lib; import android.content.ContentResolver; import android.support.v4.provider.DocumentFile; import com.google.common.base.Charsets; import com.google.common.io.ByteStreams; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.FileNotFoundException; import java.io.IOException; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import io.v.syncslides.db.DB; import io.v.syncslides.model.Deck; import io.v.syncslides.model.DeckImpl; import io.v.syncslides.model.Slide; import io.v.syncslides.model.SlideImpl; import io.v.v23.verror.VException; import static io.v.v23.VFutures.sync; /** * Imports a slide deck from the given (local) folder directly into the DB. * * The folder must contain a JSON metadata file 'deck.json' with the following format: * { * "Title" : "<title>", * "Thumb" : "<filename>, * "Slides" : [ * { * "Thumb" : "<thumb_filename1>", * "Image" : "<image_filename1>", * "Note" : "<note1>" * }, * { * "Thumb" : "<thumb_filename2>", * "Image" : "<image_filename2>", * "Note" : "<note2>" * }, * * ... * ] * } * * All the filenames must be local to the given folder. */ public class DeckImporter { private static final String DECK_JSON = "deck.json"; private static final String TITLE = "Title"; private static final String THUMB = "Thumb"; private static final String SLIDES = "Slides"; private static final String IMAGE = "Image"; private static final String NOTE = "Note"; private final ListeningExecutorService mExecutorService; private ContentResolver mContentResolver; private DB mDB; public DeckImporter(ContentResolver contentResolver, DB db) { mExecutorService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); mContentResolver = contentResolver; mDB = db; } public ListenableFuture<Void> importDeck(final DocumentFile dir) { return mExecutorService.submit(() -> importDeckImpl(dir)); } private Void importDeckImpl(DocumentFile dir) throws ImportException { if (!dir.isDirectory()) { throw new ImportException("Must import from a directory, got: " + dir); } // Read the deck metadata file. DocumentFile metadataFile = dir.findFile(DECK_JSON); if (metadataFile == null) { throw new ImportException("Couldn't find deck metadata file 'deck.json'"); } JSONObject metadata = null; try { String data = new String( ByteStreams.toByteArray(mContentResolver.openInputStream(metadataFile.getUri())), Charsets.UTF_8); metadata = new JSONObject(data); } catch (FileNotFoundException e) { throw new ImportException("Couldn't open deck metadata file", e); } catch (IOException e) { throw new ImportException("Couldn't read data from deck metadata file", e); } catch (JSONException e) { throw new ImportException("Couldn't parse deck metadata", e); } try { String id = UUID.randomUUID().toString(); String title = metadata.getString(TITLE); byte[] thumbData = readImage(dir, metadata.getString(THUMB)); Deck deck = new DeckImpl(title, thumbData, id); Slide[] slides = readSlides(dir, metadata); sync(mDB.importDeck(deck, slides)); } catch (JSONException e) { throw new ImportException("Invalid format for deck metadata", e); } catch (IOException e) { throw new ImportException("Error interpreting deck metadata", e); } catch (VException e) { throw new ImportException("Error importing deck", e); } return null; } // TODO(kash): Lazily read the slide images so we don't need to have them all // in memory simultaneously. private Slide[] readSlides(DocumentFile dir, JSONObject metadata) throws JSONException, IOException { if (!metadata.has(SLIDES)) { return new Slide[0]; } JSONArray slides = metadata.getJSONArray(SLIDES); Slide[] ret = new Slide[slides.length()]; for (int i = 0; i < slides.length(); ++i) { JSONObject slide = slides.getJSONObject(i); byte[] thumbData = readImage(dir, slide.getString(THUMB)); byte[] imageData = thumbData; if (slide.has(IMAGE)) { imageData = readImage(dir, slide.getString(IMAGE)); } String note = slide.getString(NOTE); // Temporarily use the thumbnail image's filename as the slide's unique ID. SyncbaseDB // will generate a real ID on its own, so this is just a placeholder. ret[i] = new SlideImpl(slide.getString(THUMB), thumbData, imageData, note); } return ret; } private byte[] readImage(DocumentFile dir, String fileName) throws IOException { DocumentFile file = dir.findFile(fileName); if (file == null) { throw new FileNotFoundException("Image file doesn't exist: " + fileName); } return ByteStreams.toByteArray(mContentResolver.openInputStream(file.getUri())); } }