Java tutorial
/* * Firefox Bookmarks Importer for Tint Browser * * Copyright (C) 2012 - to infinity and beyond J. Devauchelle and contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 3 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package org.tint.firefoximporter; import java.io.IOException; import java.net.URI; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.emergent.android.weave.client.QueryParams; import org.emergent.android.weave.client.QueryResult; import org.emergent.android.weave.client.UserWeave; import org.emergent.android.weave.client.WeaveAccountInfo; import org.emergent.android.weave.client.WeaveBasicObject; import org.emergent.android.weave.client.WeaveException; import org.emergent.android.weave.client.WeaveFactory; import org.json.JSONException; import org.json.JSONObject; import org.tint.firefoximporter.model.BookmarksWrapper; import org.tint.firefoximporter.model.WeaveColumns; import org.tint.firefoximporter.model.WeaveWrapper; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.preference.PreferenceManager; public class SyncRunnable implements Runnable { private static final String WEAVE_PATH = "/storage/bookmarks"; private static final String WEAVE_HEADER_TYPE = "type"; private static final String WEAVE_VALUE_BOOKMARK = "bookmark"; private static final String WEAVE_VALUE_FOLDER = "folder"; private static final String WEAVE_VALUE_ITEM = "item"; private static final String WEAVE_VALUE_ID = "id"; private static final String WEAVE_VALUE_PARENT_ID = "parentid"; private static final String WEAVE_VALUE_TITLE = "title"; private static final String WEAVE_VALUE_URI = "bmkUri"; private static final String WEAVE_VALUE_DELETED = "deleted"; private static WeaveFactory mWeaveFactory = null; private Context mContext; private ContentResolver mContentResolver; private WeaveAccountInfo mAccountInfo; private ISyncListener mListener; private String mFolderName; private long mFolderId; private boolean mFullSync = false; private boolean mError; private String mErrorMessage; private static WeaveFactory getWeaveFactory() { if (mWeaveFactory == null) { mWeaveFactory = new WeaveFactory(true); } return mWeaveFactory; } public SyncRunnable(Context context, WeaveAccountInfo accountInfo, ISyncListener listener, String folderName) { mContext = context; mContentResolver = context.getContentResolver(); mAccountInfo = accountInfo; mListener = listener; mFolderName = folderName; } @Override public void run() { mError = false; mErrorMessage = null; boolean syncDone = syncWeaveDb(); if (syncDone) { writeToBookmarks(); } onEnd(syncDone); } private void writeToBookmarks() { publishProgress(4, 0, 0); mFolderId = BookmarksWrapper.deleteFirefoxFolderContent(mContentResolver, mFolderName, false); if (mFolderId == -1) { mFolderId = BookmarksWrapper.createFirefoxFolder(mContentResolver, mFolderName); } Map<String, Long> foldersMap = createFoldersRecursive("places", mFolderId, null); createBookmarks(foldersMap); } private void createBookmarks(Map<String, Long> foldersMap) { Cursor c = WeaveWrapper.getBookmarksOnly(mContentResolver); if (c != null) { if (c.moveToFirst()) { List<ContentValues> valuesList = new ArrayList<ContentValues>(); int parentIdIndex = c.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_PARENT_ID); int titleIndex = c.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_TITLE); int urlIndex = c.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_URL); do { String weaveParentId = c.getString(parentIdIndex); if (foldersMap.containsKey(weaveParentId)) { long parentId = foldersMap.get(weaveParentId); String title = c.getString(titleIndex); String url = c.getString(urlIndex); ContentValues values = new ContentValues(); values.put(BookmarksWrapper.Columns.TITLE, title); values.put(BookmarksWrapper.Columns.URL, url); values.put(BookmarksWrapper.Columns.BOOKMARK, 1); values.put(BookmarksWrapper.Columns.IS_FOLDER, 0); values.put(BookmarksWrapper.Columns.PARENT_FOLDER_ID, parentId); valuesList.add(values); } } while (c.moveToNext()); BookmarksWrapper.doBulkInsert(mContentResolver, valuesList.toArray(new ContentValues[valuesList.size()])); } c.close(); } } private Map<String, Long> createFoldersRecursive(String weaveParent, long id, Map<String, Long> foldersMap) { if (foldersMap == null) { foldersMap = new HashMap<String, Long>(); } Cursor c = WeaveWrapper.getFoldersByParent(mContentResolver, weaveParent); if (c != null) { if (c.moveToFirst()) { int weaveIdIndex = c.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID); int titleIndex = c.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_TITLE); do { String title = c.getString(titleIndex); ContentValues values = new ContentValues(); values.put(BookmarksWrapper.Columns.TITLE, title); values.putNull(BookmarksWrapper.Columns.URL); values.put(BookmarksWrapper.Columns.BOOKMARK, 0); values.put(BookmarksWrapper.Columns.IS_FOLDER, 1); values.put(BookmarksWrapper.Columns.PARENT_FOLDER_ID, id); long insertedId = BookmarksWrapper.insert(mContentResolver, values); String weaveId = c.getString(weaveIdIndex); foldersMap.put(weaveId, insertedId); if (insertedId != -1) { foldersMap = createFoldersRecursive(weaveId, insertedId, foldersMap); } } while (c.moveToNext()); } c.close(); } return foldersMap; } private boolean syncWeaveDb() { try { publishProgress(0, 0, 0); UserWeave userWeave = getWeaveFactory().createUserWeave(mAccountInfo.getServer(), mAccountInfo.getUsername(), mAccountInfo.getPassword()); long lastModifiedDate = getLastModified(userWeave).getTime(); long lastSyncDate = PreferenceManager.getDefaultSharedPreferences(mContext) .getLong(Constants.TECHNICAL_PREFERENCE_LAST_SYNC_DATE, -1); long folderId = BookmarksWrapper.getFolderId(mContentResolver, mFolderName); // Log.d("lastModifiedDate", Long.toString(lastModifiedDate)); // Log.d("lastSyncDate", Long.toString(lastSyncDate)); if ((lastModifiedDate > lastSyncDate) || (folderId == -1)) { mFullSync = (folderId == -1) || (lastSyncDate <= 0); QueryResult<List<WeaveBasicObject>> queryResult; QueryParams parms = null; if (!mFullSync) { parms = new QueryParams(); parms.setFull(false); parms.setNewer(new Date(lastSyncDate)); } else { WeaveWrapper.clear(mContentResolver); } queryResult = getCollection(userWeave, WEAVE_PATH, parms); List<WeaveBasicObject> wboList = queryResult.getValue(); if (mFullSync) { doSync(mAccountInfo, userWeave, wboList); } else { doSyncByDelta(mAccountInfo, userWeave, wboList); } return true; } else { return false; } } catch (WeaveException e) { e.printStackTrace(); mError = true; mErrorMessage = e.getMessage(); return false; } catch (JSONException e) { e.printStackTrace(); mError = true; mErrorMessage = e.getMessage(); return false; } catch (IOException e) { e.printStackTrace(); mError = true; mErrorMessage = e.getMessage(); return false; } catch (GeneralSecurityException e) { e.printStackTrace(); mError = true; mErrorMessage = e.getMessage(); return false; } } private void doSync(WeaveAccountInfo accountInfo, UserWeave userWeave, List<WeaveBasicObject> wboList) throws WeaveException, JSONException, IOException, GeneralSecurityException { int i = 0; int count = wboList.size(); List<ContentValues> values = new ArrayList<ContentValues>(); publishProgress(1, 0, 0); mContext.getContentResolver().delete(WeaveColumns.CONTENT_URI, null, null); for (WeaveBasicObject wbo : wboList) { JSONObject decryptedPayload = wbo.getEncryptedPayload(userWeave, accountInfo.getSecret()); i++; // if (i > 50) break; //Log.d("Decrypted:", decryptedPayload.toString()); if (decryptedPayload.has(WEAVE_HEADER_TYPE) && ((decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_BOOKMARK)) || (decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_FOLDER)))) { if (decryptedPayload.has(WEAVE_VALUE_TITLE)) { boolean isFolder = decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_FOLDER); String title = decryptedPayload.getString(WEAVE_VALUE_TITLE); String weaveId = decryptedPayload.has(WEAVE_VALUE_ID) ? decryptedPayload.getString(WEAVE_VALUE_ID) : null; String parentId = decryptedPayload.has(WEAVE_VALUE_PARENT_ID) ? decryptedPayload.getString(WEAVE_VALUE_PARENT_ID) : null; if ((title != null) && (title.length() > 0)) { ContentValues value = new ContentValues(); value.put(WeaveColumns.WEAVE_BOOKMARKS_TITLE, title); value.put(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID, weaveId); value.put(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_PARENT_ID, parentId); if (isFolder) { value.put(WeaveColumns.WEAVE_BOOKMARKS_FOLDER, true); } else { String url = decryptedPayload.getString(WEAVE_VALUE_URI); value.put(WeaveColumns.WEAVE_BOOKMARKS_FOLDER, false); value.put(WeaveColumns.WEAVE_BOOKMARKS_URL, url); } values.add(value); } } } publishProgress(2, i, count); } int j = 0; ContentValues[] valuesArray = new ContentValues[values.size()]; for (ContentValues value : values) { valuesArray[j++] = value; } publishProgress(3, 0, 0); mContext.getContentResolver().bulkInsert(WeaveColumns.CONTENT_URI, valuesArray); } private void doSyncByDelta(WeaveAccountInfo accountInfo, UserWeave userWeave, List<WeaveBasicObject> wboList) throws WeaveException, JSONException, IOException, GeneralSecurityException { int i = 0; int count = wboList.size(); for (WeaveBasicObject wbo : wboList) { JSONObject decryptedPayload = wbo.getEncryptedPayload(userWeave, accountInfo.getSecret()); i++; if (decryptedPayload.has(WEAVE_HEADER_TYPE)) { if (decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_ITEM) && decryptedPayload.has(WEAVE_VALUE_DELETED) && decryptedPayload.getBoolean(WEAVE_VALUE_DELETED)) { String weaveId = decryptedPayload.has(WEAVE_VALUE_ID) ? decryptedPayload.getString(WEAVE_VALUE_ID) : null; if ((weaveId != null) && (weaveId.length() > 0)) { WeaveWrapper.deleteByWeaveId(mContentResolver, weaveId); } } else if (decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_BOOKMARK) || decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_FOLDER)) { String weaveId = decryptedPayload.has(WEAVE_VALUE_ID) ? decryptedPayload.getString(WEAVE_VALUE_ID) : null; if ((weaveId != null) && (weaveId.length() > 0)) { boolean isFolder = decryptedPayload.getString(WEAVE_HEADER_TYPE).equals(WEAVE_VALUE_FOLDER); String title = decryptedPayload.getString(WEAVE_VALUE_TITLE); String parentId = decryptedPayload.has(WEAVE_VALUE_PARENT_ID) ? decryptedPayload.getString(WEAVE_VALUE_PARENT_ID) : null; ContentValues values = new ContentValues(); values.put(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID, weaveId); values.put(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_PARENT_ID, parentId); values.put(WeaveColumns.WEAVE_BOOKMARKS_TITLE, title); if (isFolder) { values.put(WeaveColumns.WEAVE_BOOKMARKS_FOLDER, true); } else { String url = decryptedPayload.getString(WEAVE_VALUE_URI); values.put(WeaveColumns.WEAVE_BOOKMARKS_FOLDER, false); values.put(WeaveColumns.WEAVE_BOOKMARKS_URL, url); } long id = WeaveWrapper.getBookmarkIdByWeaveId(mContentResolver, weaveId); if (id == -1) { // Insert. WeaveWrapper.insertWeaveBookmark(mContentResolver, values); } else { // Update. WeaveWrapper.updateWeaveBookmark(mContentResolver, id, values); } } } } //Log.d("Decrypted:", decryptedPayload.toString()); publishProgress(2, i, count); } } private void publishProgress(Integer... values) { mListener.onSyncProgress(values[0], values[1], values[2]); } private void onEnd(boolean syncDone) { mListener.onSyncEnd(syncDone, mError, mErrorMessage); } private QueryResult<List<WeaveBasicObject>> getCollection(UserWeave weave, String name, QueryParams params) throws WeaveException { if (params == null) params = new QueryParams(); URI uri = weave.buildSyncUriFromSubpath(name + params.toQueryString()); return weave.getWboCollection(uri); } private Date getLastModified(UserWeave userWeave) throws WeaveException { try { JSONObject infoCol = userWeave.getNode(UserWeave.HashNode.INFO_COLLECTIONS).getValue(); if (infoCol.has("bookmarks")) { long modLong = infoCol.getLong("bookmarks"); return new Date(modLong * 1000); } return null; } catch (JSONException e) { throw new WeaveException(e); } } }