Java tutorial
/* * Copyright 2015 Crosstree Labs. * * 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.crosstreelabs.cognitio.service.mongo; import com.crosstreelabs.cognitio.api.resource.CatalogueEntry; import com.crosstreelabs.cognitio.api.resource.Reference; import com.crosstreelabs.cognitio.api.service.ReferenceService; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.MongoClient; import com.mongodb.WriteConcern; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Queue; import org.apache.commons.collections4.queue.CircularFifoQueue; import org.joda.time.DateTime; public class MongoReferenceService implements ReferenceService { private final MongoClient client; private final DB db; private final DBCollection references; private final Queue<CacheEntry> referenceCache = new CircularFifoQueue<>(100); public MongoReferenceService(final MongoClient client) { this.client = client; db = client.getDB("cognitio"); if (!db.collectionExists("references")) { references = db.createCollection("references", null); // references.createIndex(new BasicDBObject("location", 1), new BasicDBObject("unique", true)); } else { references = db.getCollection("references"); } } @Override public Collection<Reference> findReferencesTo(final CatalogueEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public Collection<Reference> findReferencesFrom(final CatalogueEntry entry) { Collection<Reference> result = new HashSet<>(); DBCursor cursor = references.find(new BasicDBObject("linker", entry.id)); for (DBObject obj : cursor) { Reference ref = fromMongoObject(obj); result.add(ref); } return result; } @Override public Collection<String> findReferencedUrlsFrom(final CatalogueEntry entry) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public Reference find(final String from, final String to) { // Check cache first for (CacheEntry entry : referenceCache) { if (entry.getReference().linker.equals(from) && entry.getReference().linkee.equals(to)) { return entry.getReference(); } } DBObject obj = references.findOne(new BasicDBObject("linker", from).append("linkee", to)); if (obj == null) { return null; } Reference result = fromMongoObject(obj); referenceCache.add(new CacheEntry(result)); return result; } @Override public void save(final Reference reference) { Reference existing = find(reference.linker, reference.linkee); if (existing != null) { return; } DBObject obj = toMongoObject(reference); references.insert(obj, WriteConcern.JOURNALED); reference.id = obj.get("_id").toString(); referenceCache.add(new CacheEntry(reference)); } @Override public void saveAll(final Reference... references) { saveAll(Arrays.asList(references)); } @Override public void saveAll(final Collection<Reference> references) { if (references.isEmpty()) { return; } List<DBObject> objs = new ArrayList<>(); for (Reference ref : references) { objs.add(toMongoObject(ref)); } this.references.insert(objs); } //~ Conversion methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected DBObject toMongoObject(final Reference reference) { DBObject result = new BasicDBObject(); result.put("linker", reference.linker); result.put("linkee", reference.linkee); if (reference.discovered == null) { reference.discovered = new DateTime(); } result.put("discovered", reference.discovered.toDate()); if (reference.defunct != null) { result.put("defunct", reference.defunct.toDate()); } return result; } protected Reference fromMongoObject(final DBObject obj) { Reference result = new Reference(); result.id = obj.get("_id").toString(); result.linker = obj.get("linker").toString(); result.linkee = obj.get("linkee").toString(); if (obj.get("discovered") != null) { result.discovered = new DateTime((Date) obj.get("discovered")); } if (obj.get("defunct") != null) { result.defunct = new DateTime((Date) obj.get("defunct")); } return result; } private static final class CacheEntry { private final Reference reference; private Map<String, Object> originalData; public CacheEntry(final Reference reference) { this.reference = reference; update(); } public Reference getReference() { return reference; } public boolean isDirty() { return !(Objects.equals(reference.id, originalData.get("id")) && Objects.equals(reference.linker, originalData.get("linker")) && Objects.equals(reference.linkee, originalData.get("linkee")) && Objects.equals(reference.discovered, originalData.get("discovered")) && Objects.equals(reference.defunct, originalData.get("defunct"))); } public void update() { Map<String, Object> data = new HashMap<>(); data.put("id", reference.id); data.put("linker", reference.linker); data.put("linkee", reference.linkee); data.put("discovered", reference.discovered); data.put("defunct", reference.defunct); this.originalData = Collections.unmodifiableMap(data); } } }