/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.samples.apps.iosched.io; import android.content.ContentProviderOperation; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.BaseColumns; import com.google.samples.apps.iosched.Config; import com.google.samples.apps.iosched.io.model.Expert; import com.google.samples.apps.iosched.provider.ScheduleContract; import com.google.gson.Gson; import com.google.gson.JsonElement; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import static com.google.samples.apps.iosched.util.LogUtils.*; public class ExpertsHandler extends JSONHandler { private static final String TAG = makeLogTag(ExpertsHandler.class); private HashMap<String, Expert> mExperts = new HashMap<String, Expert>(); public ExpertsHandler(Context context) { super(context); } @Override public void process(JsonElement element) { if (Config.hasExpertsDirectoryExpired()) { return; } for (Expert expert : new Gson().fromJson(element, Expert[].class)) { mExperts.put(expert.id, expert); } } @Override public void makeContentProviderOperations(ArrayList<ContentProviderOperation> list) { if (Config.hasExpertsDirectoryExpired()) { return; } Uri uri = ScheduleContract.addCallerIsSyncAdapterParameter( ScheduleContract.Experts.CONTENT_URI); HashMap<String, String> expertsHashcodes = loadExpertHashcodes(); HashSet<String> expertsToKeep = new HashSet<String>(); boolean isIncrementalUpdate = expertsHashcodes != null && expertsHashcodes.size() > 0; if (isIncrementalUpdate) { LOGD(TAG, "Doing incremental update for experts."); } else { LOGD(TAG, "Doing FULL (non incremental) update for experts."); list.add(ContentProviderOperation.newDelete(uri).build()); } int updatedExperts = 0; for (Expert expert : mExperts.values()) { String hashCode = expert.getImportHashCode(); expertsToKeep.add(expert.id); // Add the expert, if necessary if (!isIncrementalUpdate || !expertsHashcodes.containsKey(expert.id) || !expertsHashcodes.get(expert.id).equals(hashCode)) { ++updatedExperts; boolean isNew = !isIncrementalUpdate || !expertsHashcodes.containsKey(expert.id); buildExpert(isNew, expert, list); } } int deletedExperts = 0; if (isIncrementalUpdate) { for (String expertId : expertsHashcodes.keySet()) { if (!expertsToKeep.contains(expertId)) { buildDeleteOperation(expertId, list); ++deletedExperts; } } } LOGD(TAG, "Experts: " + (isIncrementalUpdate ? "INCREMENTAL" : "FULL") + " update. " + updatedExperts + " to update, " + deletedExperts + " to delete. New total: " + mExperts.size()); } private void buildExpert(boolean isInsert, Expert expert, ArrayList<ContentProviderOperation> list) { Uri allExpertsUri = ScheduleContract.addCallerIsSyncAdapterParameter( ScheduleContract.Experts.CONTENT_URI); Uri thisExpertUri = ScheduleContract.addCallerIsSyncAdapterParameter( ScheduleContract.Experts.buildExpertUri(expert.id)); ContentProviderOperation.Builder builder; if (isInsert) { builder = ContentProviderOperation.newInsert(allExpertsUri); } else { builder = ContentProviderOperation.newUpdate(thisExpertUri); } list.add(builder.withValue(ScheduleContract.Experts.UPDATED, System.currentTimeMillis()) .withValue(ScheduleContract.Experts.EXPERT_ID, expert.id) .withValue(ScheduleContract.Experts.EXPERT_NAME, expert.name) .withValue(ScheduleContract.Experts.EXPERT_IMAGE_URL, expert.imageUrl) .withValue(ScheduleContract.Experts.EXPERT_TITLE, expert.title) .withValue(ScheduleContract.Experts.EXPERT_ABSTRACT, expert.bio) .withValue(ScheduleContract.Experts.EXPERT_URL, expert.url) .withValue(ScheduleContract.Experts.EXPERT_COUNTRY, expert.country) .withValue(ScheduleContract.Experts.EXPERT_CITY, expert.city) .withValue(ScheduleContract.Experts.EXPERT_ATTENDING, expert.attending) .withValue(ScheduleContract.Experts.EXPERT_IMPORT_HASHCODE, expert.getImportHashCode()) .build()); } private void buildDeleteOperation(String expertId, ArrayList<ContentProviderOperation> list) { Uri expertUri = ScheduleContract.addCallerIsSyncAdapterParameter( ScheduleContract.Experts.buildExpertUri(expertId)); list.add(ContentProviderOperation.newDelete(expertUri).build()); } private HashMap<String, String> loadExpertHashcodes() { Uri uri = ScheduleContract.addCallerIsSyncAdapterParameter( ScheduleContract.Experts.CONTENT_URI); Cursor cursor = mContext.getContentResolver().query(uri, ExpertHashcodeQuery.PROJECTION, null, null, null); if (cursor == null) { LOGE(TAG, "Error querying expert hashcodes (got null cursor"); return null; } if (cursor.getCount() < 1) { LOGE(TAG, "Error querying expert hashcodes (no records returned)"); return null; } HashMap<String, String> result = new HashMap<String, String>(); while (cursor.moveToNext()) { String expertId = cursor.getString(ExpertHashcodeQuery.EXPERT_ID); String hashcode = cursor.getString(ExpertHashcodeQuery.EXPERT_IMPORT_HASHCODE); result.put(expertId, hashcode == null ? "" : hashcode); } cursor.close(); return result; } private interface ExpertHashcodeQuery { String[] PROJECTION = { BaseColumns._ID, ScheduleContract.Experts.EXPERT_ID, ScheduleContract.Experts.EXPERT_IMPORT_HASHCODE, }; final int _ID = 0; final int EXPERT_ID = 1; final int EXPERT_IMPORT_HASHCODE = 2; } }