package codeine.db.mongo; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.apache.log4j.Logger; import codeine.db.IAlertsDatabaseConnector; import codeine.db.IStatusDatabaseConnector; import codeine.jsons.labels.LabelJsonProvider; import codeine.jsons.labels.ProjectLabelVersionJson; import codeine.jsons.mails.AlertsCollectionType; import codeine.jsons.mails.CollectorNotificationJson; import codeine.jsons.peer_status.PeerStatusJsonV2; import codeine.model.Constants; import codeine.utils.ExceptionUtils; import codeine.utils.MongoUtils; import com.google.common.base.Function; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.gson.Gson; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObjectBuilder; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.MongoClient; import com.mongodb.util.JSON; public class MongoConnector implements IAlertsDatabaseConnector, LabelJsonProvider, IStatusDatabaseConnector { private static final Logger log = Logger.getLogger(MongoConnector.class); @Inject private Gson gson; @Inject private MongoClient mongoClient; private <T> void onItems(Class<T> type, DBObject query, Function<ObjectWithCollection, Void> function) { MongoClient mongoClient = getClient(); try { DBCollection collection = getCollection(type, mongoClient); DBCursor cursor = collection.find(query); try { while (cursor.hasNext()) { final DBObject obj = cursor.next(); log.debug("got " + obj); function.apply(new ObjectWithCollection(obj, collection)); } } finally { cursor.close(); } } finally { // mongoClient.close(); } } public static class ObjectWithCollection{ private DBObject object; private DBCollection collection; public ObjectWithCollection(DBObject object, DBCollection collection) { this.object = object; this.collection = collection; } public DBCollection collection() { return collection; } public DBObject object() { return object; } } private MongoClient getClient() { return mongoClient; } private <T> void putInternal(T t) { MongoClient mongoClient = getClient(); try { DBCollection coll = getCollection(t.getClass(), mongoClient); String json = gson.toJson(t); log.debug("json is " + json); DBObject doc = (DBObject) JSON.parse(encode(json)); log.debug("insert " + doc); coll.insert(doc); } catch (Exception e) { throw ExceptionUtils.asUnchecked(e); } finally { // mongoClient.close(); } } @Override public void putReplaceStatus(PeerStatusJsonV2 p){ delete(PeerStatusJsonV2.class, getStatusQuery(p)); putInternal(p); } private DBObject getStatusQuery(PeerStatusJsonV2 p) { return new BasicDBObject("peer_key", encode(p.peer_key())); } private String encode(String key) { return MongoUtils.encode(key); } private String decode(String key) { return MongoUtils.decode(key); } private <T> DBCollection getCollection(Class<T> type, MongoClient mongoClient) { DB db = mongoClient.getDB(Constants.DB_NAME); DBCollection coll = db.getCollection(type.getCanonicalName()); return coll; } @Override public Multimap<String, CollectorNotificationJson> getAlertsAndUpdate(final AlertsCollectionType collType) { final Multimap<String, CollectorNotificationJson> allItems = HashMultimap.create(); DBObject alertsQuery = getAlertsQuery(collType); Function<ObjectWithCollection, Void> function = new Function<ObjectWithCollection, Void>() { @Override public Void apply(ObjectWithCollection input) { final CollectorNotificationJson collectorNotification = gson.fromJson(decode(input.object().toString()), CollectorNotificationJson.class); log.debug("Considering " + collectorNotification); input.object().put("collection_type", collType.toLong()); input.object().put("collection_type_update_time", System.currentTimeMillis()); input.collection().save(input.object()); allItems.put(collectorNotification.project_name(),collectorNotification); return null; } }; onItems(CollectorNotificationJson.class, alertsQuery, function); return allItems; } @Override public void removeOldAlerts() { delete(CollectorNotificationJson.class, getRemoveAlertsQuery()); } private DBObject getRemoveAlertsQuery() { BasicDBList and = new BasicDBList(); long timeToRemove = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); log.info("will remove older than " + timeToRemove); and.add(new BasicDBObject("collection_type_update_time", new BasicDBObject("$lt", timeToRemove))); and.add(new BasicDBObject("collection_type", AlertsCollectionType.Daily.toLong())); DBObject query = new BasicDBObject("$and", and); return query; } private DBObject getAlertsQuery(AlertsCollectionType collType) { BasicDBList or = new BasicDBList(); or.add(new BasicDBObject("collection_type", new BasicDBObject("$lt", collType.toLong()))); or.add(new BasicDBObject("collection_type", new BasicDBObject("$exists", false))); DBObject query = new BasicDBObject("$or", or); return query; } private DBObject getAllQuery() { return new BasicDBObject(); } private DBObject getLabelsQuery(String project) { return new BasicDBObject("project", encode(project)); } @Override public Set<ProjectLabelVersionJson> versions(String project) { final Set<ProjectLabelVersionJson> $ = Sets.newHashSet(); onJsonItems(ProjectLabelVersionJson.class, getLabelsQuery(project), new Function<ProjectLabelVersionJson, Void>() { @Override public Void apply(ProjectLabelVersionJson input) { $.add(input); return null; } }); return $; } private <T> void onJsonItems(final Class<T> type, DBObject query, final Function<T, Void> function) { Function<ObjectWithCollection, Void> function1 = new Function<MongoConnector.ObjectWithCollection, Void>() { @Override public Void apply(ObjectWithCollection input) { T item = gson.fromJson(decode(input.object().toString()), type); log.debug("parsed item " + item); function.apply(item); return null; } }; onItems(type, query, function1); } @Override public void updateLabel(ProjectLabelVersionJson versionLabelJson) { deleteLabel(versionLabelJson.label(), versionLabelJson.project()); putInternal(versionLabelJson); } @Override public void deleteLabel(String label, String project) { delete(ProjectLabelVersionJson.class, getLabelQuery(label, project)); } private void delete(Class<?> type, DBObject alertsQuery) { Function<ObjectWithCollection, Void> function = new Function<ObjectWithCollection, Void>() { @Override public Void apply(ObjectWithCollection input) { log.debug("removing " + input.object()); input.collection().remove(input.object()); return null; } }; onItems(type, alertsQuery, function); } private DBObject getLabelQuery(String label, String project) { return BasicDBObjectBuilder.start().add("label", label).add("project", project).get(); } private DBObject getVersionQuery(String version, String project) { BasicDBList and = new BasicDBList(); and.add(new BasicDBObject("version", encode(version))); and.add(new BasicDBObject("project", encode(project))); DBObject query = new BasicDBObject("$and", and); return query; } @Override public String labelForVersion(String version, String project) { final Set<String> $ = Sets.newHashSet(); onJsonItems(ProjectLabelVersionJson.class, getVersionQuery(version, project), new Function<ProjectLabelVersionJson, Void>() { @Override public Void apply(ProjectLabelVersionJson input) { $.add(input.label()); return null; } }); if ($.isEmpty()){ return version; } return $.iterator().next(); } @Override public String versionForLabel(String label, String project) { final Set<String> $ = Sets.newHashSet(); onJsonItems(ProjectLabelVersionJson.class, getLabelQuery(label, project), new Function<ProjectLabelVersionJson, Void>() { @Override public Void apply(ProjectLabelVersionJson input) { $.add(input.version()); return null; } }); if ($.isEmpty()){ return label; } return $.iterator().next(); } @Override public Map<String, PeerStatusJsonV2> getPeersStatus(){ Map<String, PeerStatusJsonV2> $ = Maps.newHashMap(); List<PeerStatusJsonV2> allItems = getAllItems(PeerStatusJsonV2.class); for (PeerStatusJsonV2 projectStatusList : allItems) { $.put(projectStatusList.peer_key(), projectStatusList); } return $; } private <T> List<T> getAllItems(Class<T> class1) { final List<T> $ = Lists.newArrayList(); Function<T, Void> function = new Function<T, Void>() { @Override public Void apply(T t){ $.add(t); return null; } }; onJsonItems(class1, getAllQuery(), function); return $; } @Override public void put(CollectorNotificationJson collectorNotificationJson) { putInternal(collectorNotificationJson); } @Override public void updatePeersStatus(long timeToRemove, long timeToDisc) { throw new UnsupportedOperationException(); } @Override public String server() { // TODO Auto-generated method stub return null; } }