/*
* Copyright 2012 The Stanford MobiSocial Laboratory
*
* 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 mobisocial.musubi.objects;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import mobisocial.musubi.App;
import mobisocial.musubi.feed.iface.DbEntryHandler;
import mobisocial.musubi.model.MFeed;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.model.MObject;
import mobisocial.musubi.model.helpers.EncodedMessageManager;
import mobisocial.musubi.model.helpers.FeedManager;
import mobisocial.musubi.model.helpers.IdentitiesManager;
import mobisocial.musubi.model.helpers.ObjectManager;
import mobisocial.musubi.provider.MusubiContentProvider;
import mobisocial.musubi.provider.MusubiContentProvider.Provided;
import mobisocial.musubi.util.Util;
import mobisocial.socialkit.obj.MemObj;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* An obj requesting the deletion of some other obj.
*
*/
public class DeleteObj extends DbEntryHandler {
private static final String TAG = "dungbeetle";
public static final String TYPE = "delete";
public static final String HASH = "hash";
public static final String HASHES = "hashes";
/**
* If true, delete Objs without marking them "deleted".
*/
public static final String FORCE = "force";
@Override
public String getType() {
return TYPE;
}
public static MemObj from(String[] hashStrings, boolean force) {
return new MemObj(TYPE, json(hashStrings, force));
}
static JSONObject json(String[] hashStrings, boolean force) {
JSONArray arr = new JSONArray();
for (String hash : hashStrings) {
arr.put(hash);
}
JSONObject obj = new JSONObject();
try {
obj.put(HASHES, arr);
obj.put(FORCE, force);
} catch(JSONException e) {}
return obj;
}
@Override
public boolean processObject(Context context, MFeed feed, MIdentity sender, MObject object) {
try {
JSONObject json = new JSONObject(object.json_);
Set<byte[]> hashes = new HashSet<byte[]>();
if (json.optJSONArray(HASHES) != null) {
JSONArray jsonHashes = json.optJSONArray(HASHES);
for (int i = 0; i < jsonHashes.length(); i++) {
try {
String hashStr = jsonHashes.getString(i);
hashes.add(Util.convertToByteArray(hashStr));
} catch (Exception e) {
Log.e(TAG, "Failed to convert hash " + jsonHashes.optString(i));
}
}
} else {
Log.d(TAG, "DeleteObj with no hashes!");
return false;
}
Log.d(TAG, "marking or deleting " + hashes.size());
markOrDeleteFeedObjs(context, feed, sender, hashes,
(json.has(FORCE) && json.optBoolean(FORCE)));
} catch (JSONException e) {
Log.e(TAG, "bad json in deleteObj", e);
}
return false;
}
private void markOrDeleteFeedObjs(Context context, MFeed feed, MIdentity sender,
Set<byte[]> hashes, boolean force) {
SQLiteOpenHelper db = App.getDatabaseSource(context);
EncodedMessageManager em = new EncodedMessageManager(db);
ObjectManager om = new ObjectManager(db);
FeedManager fm = new FeedManager(db);
IdentitiesManager im = new IdentitiesManager(db);
for (byte[] hash : hashes) {
long objId = -1;
try {
objId = om.getObjectIdForHash(hash);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Bad hash of len " + hash.length);
}
if (objId == -1) {
String hashStr = Util.convertToHex(hash);
Log.w(TAG, "Object for " + hashStr + " not found for delete, and ooo deletion not currently supported.");
continue;
}
MObject object = om.getObjectForId(objId);
//TODO: store a dummy object or someting so we can block this one
if(object == null)
continue;
em.delete(object.encodedId_);
if(feed.latestRenderableObjId_ != null && feed.latestRenderableObjId_ == object.id_) {
feed.latestRenderableObjId_ = null;
feed.latestRenderableObjTime_ = null;
fm.updateFeed(feed);
}
if (force || sender.owned_) {
om.delete(objId);
Log.d(TAG, "deleted " + objId);
} else {
MIdentity person = im.getIdentityForId(object.identityId_);
if (person.owned_) {
object.deleted_ = true;
om.updateObject(object);
} else {
om.delete(objId);
Log.d(TAG, "deleted " + objId);
}
}
//clean up corrupted feeds
if(feed.latestRenderableObjId_ == null) {
Long repl = om.getLatestFeedRenderable(feed.id_);
Log.d(TAG, "replacing with " + (repl != null ? repl : "null"));
feed.latestRenderableObjId_ = repl;
feed.latestRenderableObjTime_ = repl != null ? new Date().getTime() : null;
fm.updateFeed(feed);
}
context.getContentResolver().notifyChange(
MusubiContentProvider.uriForItem(Provided.OBJECTS, object.id_), null);
}
context.getContentResolver().notifyChange(
MusubiContentProvider.uriForDir(Provided.OBJECTS), null);
context.getContentResolver().notifyChange(
MusubiContentProvider.uriForDir(Provided.FEEDS), null);
}
}