package org.swellrt.server.box.events.gcm; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import org.waveprotocol.box.server.persistence.mongodb.MongoDbProvider; import com.google.inject.Inject; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.typesafe.config.Config; public class GCMSubscriptionStoreMongoDb implements GCMSubscriptionStore { private static final String SUBSCRIPTIONS_KEY = "subscriptions"; private static final String TARGETS_KEY = "targets"; private static final String GCM_KEY = "gcm"; private static final String DEVICES_ID = "devices"; private static final String UNSUBSCRIBED_SOURCES_KEY = "unsubscribed_sources"; private static final String WAVE_ID = "waveId"; private static final String WAVE_ID_KEY = "wave_id"; private static final BasicDBObject gcmDevicesProjection = new BasicDBObject( SUBSCRIPTIONS_KEY + "." + TARGETS_KEY + "." + GCM_KEY + "." + DEVICES_ID, 1); private static final String PARTICIPANTS_KEY = "participants"; private DBCollection accountStore; private DBCollection modelStore; private static final Logger LOG = Logger.getLogger(GCMSubscriptionStoreMongoDb.class.getName()); @Inject public GCMSubscriptionStoreMongoDb(MongoDbProvider mongoDbProvider, Config config) { String accountStoreType = config.getString("core.account_store_type"); if (accountStoreType.equalsIgnoreCase("mongodb")) { this.accountStore = mongoDbProvider.getDBCollection("account"); this.modelStore = mongoDbProvider.getDBCollection("models"); } else { LOG.warning("Account store type is: \"" + accountStoreType + "\" instead of \"mongodb\". GCM Notifications will not work"); } } @Override public void addSubscriptor(String waveId, String userId) { BasicDBList sources = getSources(userId); BasicDBObject s = new BasicDBObject(WAVE_ID, waveId); sources.remove(s); assert (!sources.contains(s)); setSources(userId, sources); } @Override public void removeSubscriptor(String waveId, String userId) { BasicDBList sources = getSources(userId); BasicDBObject s = new BasicDBObject(WAVE_ID, waveId); if (sources == null) { sources = new BasicDBList(); } if (!sources.contains(s)) { sources.add(s); setSources(userId, sources); } } private void setSources(String userId, BasicDBList sources) { BasicDBObject o = new BasicDBObject(SUBSCRIPTIONS_KEY + "." + UNSUBSCRIBED_SOURCES_KEY, sources); BasicDBObject q = new BasicDBObject(); q.append("_id", userId); accountStore.update(q, new BasicDBObject("$set", o)); } private BasicDBList getSources(String userId) { BasicDBObject query = new BasicDBObject(); query.append("_id", userId); DBObject found = accountStore.findOne(query, new BasicDBObject(SUBSCRIPTIONS_KEY + "." + UNSUBSCRIBED_SOURCES_KEY, 1)); BasicDBList s; try { DBObject subs = (DBObject) found.get(SUBSCRIPTIONS_KEY); s = (BasicDBList) subs.get(UNSUBSCRIBED_SOURCES_KEY); } catch (NullPointerException e) { s = new BasicDBList(); } catch (ClassCastException e) { s = new BasicDBList(); } if (s == null) { s = new BasicDBList(); } return s; } @Override public List<String> getSubscriptorsDevices(String waveId) { BasicDBObject participantsProjection = new BasicDBObject(PARTICIPANTS_KEY, 1); BasicDBObject waveIdQuery = new BasicDBObject(WAVE_ID_KEY, waveId); DBObject waveData = modelStore.findOne(waveIdQuery, participantsProjection); BasicDBList participantAccounts = (BasicDBList) waveData.get(PARTICIPANTS_KEY); BasicDBObject inPraticipantsQuery = new BasicDBObject("$in", participantAccounts); BasicDBObject subscribedQuery = new BasicDBObject( SUBSCRIPTIONS_KEY + "." + UNSUBSCRIBED_SOURCES_KEY + "." + WAVE_ID, new BasicDBObject("$ne", waveId)); subscribedQuery.append("_id", inPraticipantsQuery); subscribedQuery.append(SUBSCRIPTIONS_KEY + "." + TARGETS_KEY + "." + GCM_KEY + "." + DEVICES_ID, new BasicDBObject("$exists", true)); DBCursor subscribedAccounts = accountStore.find(subscribedQuery, gcmDevicesProjection); List<String> result = new ArrayList<String>(); for (DBObject acc : subscribedAccounts) { BasicDBList devices = (BasicDBList) ((BasicDBObject) ((BasicDBObject) ((BasicDBObject) acc .get(SUBSCRIPTIONS_KEY)).get(TARGETS_KEY)).get(GCM_KEY)).get(DEVICES_ID); for (Object d : devices) { result.add((String) d); } } return result; } @Override public void register(String userId, String deviceId) { BasicDBList gcmDevices = getGCMDevices(userId); if (!gcmDevices.contains(deviceId)) { gcmDevices.add(deviceId); setGCMDevices(userId, gcmDevices); } } @Override public void unregister(String userId, String deviceId) { BasicDBList gcmDevices = getGCMDevices(userId); gcmDevices.remove(deviceId); assert (!gcmDevices.contains(deviceId)); setGCMDevices(userId, gcmDevices); } private void setGCMDevices(String userId, BasicDBList gcmDevices) { BasicDBObject o = new BasicDBObject( SUBSCRIPTIONS_KEY + "." + TARGETS_KEY + "." + GCM_KEY + "." + DEVICES_ID, gcmDevices); BasicDBObject q = new BasicDBObject(); q.append("_id", userId); accountStore.update(q, new BasicDBObject("$set", o)); } private BasicDBList getGCMDevices(String userId) { BasicDBObject query = new BasicDBObject(); query.append("_id", userId); DBObject o = accountStore.findOne(query, gcmDevicesProjection); BasicDBList devs; try { DBObject subs = (DBObject) o.get(SUBSCRIPTIONS_KEY); DBObject targ = (DBObject) subs.get(TARGETS_KEY); DBObject gcmTarg = (DBObject) targ.get(GCM_KEY); devs = (BasicDBList) gcmTarg.get(DEVICES_ID); } catch (NullPointerException e) { devs = new BasicDBList(); } return devs; } @Override public List<String> getSubscriptorsDevicesExcludingUser(String waveId, String userId) { BasicDBList devs = getGCMDevices(userId); List<String> allDevs = getSubscriptorsDevices(waveId); allDevs.removeAll(devs); return allDevs; } }