Project

General

Profile

1
package eu.dnetlib.oai.mongo;
2

    
3
import java.util.List;
4
import java.util.stream.Collectors;
5
import javax.annotation.Resource;
6

    
7
import com.mongodb.BasicDBObjectBuilder;
8
import com.mongodb.DBObject;
9
import com.mongodb.MongoClient;
10
import com.mongodb.client.FindIterable;
11
import com.mongodb.client.MongoCollection;
12
import com.mongodb.client.MongoDatabase;
13
import com.mongodb.client.model.Filters;
14
import eu.dnetlib.cql.CqlTranslator;
15
import eu.dnetlib.enabling.tools.DnetStreamSupport;
16
import eu.dnetlib.oai.PublisherStoreDAO;
17
import eu.dnetlib.oai.RecordChangeDetector;
18
import eu.dnetlib.oai.conf.OAIConfigurationReader;
19
import eu.dnetlib.oai.sets.MongoSetCollection;
20
import eu.dnetlib.rmi.provision.MDFInfo;
21
import eu.dnetlib.rmi.provision.OaiPublisherException;
22
import eu.dnetlib.rmi.provision.OaiPublisherRuntimeException;
23
import net.sf.ehcache.Cache;
24
import net.sf.ehcache.Element;
25
import org.apache.commons.logging.Log;
26
import org.apache.commons.logging.LogFactory;
27
import org.springframework.beans.factory.annotation.Autowired;
28
import org.springframework.beans.factory.annotation.Required;
29

    
30
public class MongoPublisherStoreDAO implements PublisherStoreDAO<MongoPublisherStore, DNetOAIMongoCursor> {
31

    
32
	private static final Log log = LogFactory.getLog(MongoPublisherStoreDAO.class); // NOPMD by marko on 11/24/08 5:02 PM
33

    
34
	@Autowired
35
	private MongoClient publisherMongoClient;
36

    
37
	/**
38
	 * Name of the collection with information about the OAI stores.
39
	 **/
40
	private String metadataCollection;
41

    
42
	@Autowired
43
	private RecordInfoGenerator recordInfoGenerator;
44
	@Autowired
45
	private MetadataExtractor metadataExtractor;
46
	@Autowired
47
	private CqlTranslator cqlTranslator;
48
	@Resource(name = "oaiConfigurationExistReader")
49
	private OAIConfigurationReader configuration;
50
	@Autowired
51
	private RecordChangeDetector recordChangeDetector;
52
	@Autowired
53
	private MongoSetCollection mongoSetCollection;
54

    
55
	/**
56
	 * Cache for oaistores. Keys are dbName-storeId, values are objects of type MongoPublisherStore.
57
	 */
58
	private Cache mongoOaistoreCache;
59

    
60
	/**
61
	 * Cache for oaistores. Keys is OAI metadata prefixes, values are objects of type MongoPublisherStore.
62
	 */
63
	private Cache mongoOaistoreCacheByMdPrefix;
64

    
65
	private boolean alwaysNewRecord;
66

    
67
	protected MongoDatabase getDB(final String dbName) {
68
		return this.publisherMongoClient.getDatabase(dbName);
69
	}
70

    
71
	@Override
72
	public List<MongoPublisherStore> listPublisherStores(final String dbName) {
73
		final MongoDatabase db = getDB(dbName);
74
		final FindIterable<DBObject> stores = db.getCollection(this.metadataCollection, DBObject.class).find();
75
		return DnetStreamSupport.generateStreamFromIterator(stores.iterator())
76
				.map(storeInfo -> createFromDBObject(storeInfo, db))
77
				.collect(Collectors.toList());
78
	}
79

    
80
	@Override
81
	public MongoPublisherStore getStore(final String storeId, final String dbName) {
82
		final DBObject storeInfo = getDB(dbName).getCollection(this.metadataCollection, DBObject.class).find(Filters.eq("id", storeId)).first();
83
		return this.createFromDBObject(storeInfo, getDB(dbName));
84
	}
85

    
86
	@Override
87
	public MongoPublisherStore getStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName) {
88
		return this.getStore(this.generateStoreId(mdfName, mdfInterpretation, mdfLayout), dbName);
89
	}
90

    
91
	@Override
92
	public MongoPublisherStore getStoreFor(final String targetMetadataPrefix, final String dbName) {
93

    
94
		final Element elem = this.mongoOaistoreCacheByMdPrefix.get(targetMetadataPrefix);
95

    
96
		if (elem != null) {
97
			return (MongoPublisherStore) elem.getObjectValue();
98
		} else {
99
			final MDFInfo info = this.configuration.getMetadataFormatInfo(targetMetadataPrefix);
100
			final MongoPublisherStore store =
101
					this.getStore(info.getSourceFormat(), info.getSourceInterpretation(), info.getSourceLayout(), dbName);
102
			this.mongoOaistoreCacheByMdPrefix.put(new Element(targetMetadataPrefix, store));
103
			return store;
104
		}
105
	}
106

    
107
	@Override
108
	public MongoPublisherStore createStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName)
109
			throws OaiPublisherException {
110
		final MongoDatabase db = getDB(dbName);
111
		final DBObject store = createMetadataEntry(mdfName, mdfInterpretation, mdfLayout);
112
		final MongoCollection<DBObject> metadata = db.getCollection(this.metadataCollection, DBObject.class);
113
		metadata.insertOne(store);
114
		final MongoPublisherStore theStore = this.createFromDBObject(store, db);
115
		return theStore;
116

    
117
	}
118

    
119
	@Override
120
	public boolean deleteStore(final String storeId, final String dbName) {
121

    
122
		final MongoDatabase db = getDB(dbName);
123
		final MongoCollection<DBObject> metadata = db.getCollection(this.metadataCollection, DBObject.class);
124
		final DBObject storeDeleted = metadata.findOneAndDelete(Filters.eq("id", storeId));
125
		if (storeDeleted == null) {
126
			return false;
127
		} else {
128
			db.getCollection(storeId).drop();
129
			// TODO: should drop entries related to mdPrefix served by the store we are deleting, not all of them.
130
			this.mongoSetCollection.dropOAISets(dbName);
131
			log.debug("Deleted oaistore " + storeId + ", db: " + dbName);
132
			return true;
133
		}
134
	}
135

    
136
	@Override
137
	public boolean deleteFromStore(final String storeId, final String dbName, final String set) {
138
		final MongoDatabase db = getDB(dbName);
139
		final MongoCollection<DBObject> metadata = db.getCollection(this.metadataCollection, DBObject.class);
140
		final DBObject storeInfo = metadata.find(Filters.eq("id", storeId)).first();
141
		if (storeInfo == null) {
142
			return false;
143
		} else {
144
            db.getCollection(storeId).deleteMany(Filters.eq(OAIConfigurationReader.SET_FIELD, this.mongoSetCollection.normalizeSetSpec(set)));
145
            this.mongoSetCollection.dropSet(dbName, set);
146
			log.debug("Deleted set " + set + " from oaistore " + storeId + ", db: " + dbName);
147
			return true;
148
		}
149
	}
150

    
151
	@Override
152
	public boolean deleteFromStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName, final String set) {
153
		return this.deleteFromStore(this.generateStoreId(mdfName, mdfInterpretation, mdfLayout), dbName, set);
154
	}
155

    
156
	@Override
157
	public boolean deleteStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName) {
158
		return this.deleteStore(this.generateStoreId(mdfName, mdfInterpretation, mdfLayout), dbName);
159
	}
160

    
161
	public void ensureIndex(final MongoPublisherStore store) {
162
		if (store == null) { throw new OaiPublisherRuntimeException("Can't ensure index on null store"); }
163
		final Thread t = new Thread() {
164

    
165
			@Override
166
			public void run() {
167
				store.ensureIndices();
168
			}
169
		};
170
		t.start();
171
	}
172

    
173
	public void ensureIndex(final String dbName) {
174
		final List<MongoPublisherStore> stores = this.listPublisherStores(dbName);
175
		for (final MongoPublisherStore s : stores) {
176
			s.ensureIndices();
177
		}
178

    
179
	}
180

    
181
	private MongoPublisherStore createFromDBObject(final DBObject storeInfo, final MongoDatabase db) {
182
		if (storeInfo == null) { return null; }
183
		final String storeId = (String) storeInfo.get("id");
184
		final String mdFormat = (String) storeInfo.get("metadataFormat");
185
		final String mdInterpreation = (String) storeInfo.get("interpretation");
186
		final String mdLayout = (String) storeInfo.get("layout");
187
		final String k = db.getName() + "-" + storeId;
188

    
189
		final Element elem = this.mongoOaistoreCache.get(k);
190
		if (elem != null) {
191
			log.debug("Store retrieved from cache and alwaysNewRecord is" + this.alwaysNewRecord);
192
			final MongoPublisherStore store = (MongoPublisherStore) elem.getObjectValue();
193
			store.setAlwaysNewRecord(this.alwaysNewRecord);
194
			log.debug(store);
195
			return store;
196
		} else {
197
			log.debug("Store retrieved, cache miss,  alwaysNewRecord is" + this.alwaysNewRecord);
198
			log.fatal("Not using cache to create oaistore from dbObject: " + k);
199
			final MongoPublisherStore store = new MongoPublisherStore(storeId, mdFormat, mdInterpreation, mdLayout, db.getCollection(storeId, DBObject.class),
200
					this.configuration.getFields(mdFormat, mdInterpreation, mdLayout), this.cqlTranslator, this.recordInfoGenerator,
201
					this.configuration.getIdScheme(),
202
					this.configuration.getIdNamespace(), this.metadataExtractor, this.recordChangeDetector, this.alwaysNewRecord, db);
203
			store.setMongoSetCollection(this.mongoSetCollection);
204
			this.mongoOaistoreCache.put(new Element(k, store));
205
			return store;
206
		}
207
	}
208

    
209
	private DBObject createMetadataEntry(final String mdfName, final String mdfInterpretation, final String mdfLayout) {
210
		final DBObject info = BasicDBObjectBuilder.start("id", generateStoreId(mdfName, mdfInterpretation, mdfLayout)).append("metadataFormat", mdfName)
211
				.append("interpretation", mdfInterpretation).append("layout", mdfLayout).get();
212
		return info;
213

    
214
	}
215

    
216
	private String generateStoreId(final String mdfName, final String mdfInterpretation, final String mdfLayout) {
217
		return mdfName + "-" + mdfLayout + "-" + mdfInterpretation;
218
	}
219

    
220
	public String getMetadataCollection() {
221
		return this.metadataCollection;
222
	}
223

    
224
	@Required
225
	public void setMetadataCollection(final String metadataCollection) {
226
		this.metadataCollection = metadataCollection;
227
	}
228

    
229
	public OAIConfigurationReader getConfiguration() {
230
		return this.configuration;
231
	}
232

    
233
	public void setConfiguration(final OAIConfigurationReader configuration) {
234
		this.configuration = configuration;
235
	}
236

    
237
	public RecordInfoGenerator getRecordInfoGenerator() {
238
		return this.recordInfoGenerator;
239
	}
240

    
241
	public void setRecordInfoGenerator(final RecordInfoGenerator recordInfoGenerator) {
242
		this.recordInfoGenerator = recordInfoGenerator;
243
	}
244

    
245
	public MetadataExtractor getMetadataExtractor() {
246
		return this.metadataExtractor;
247
	}
248

    
249
	public void setMetadataExtractor(final MetadataExtractor metadataExtractor) {
250
		this.metadataExtractor = metadataExtractor;
251
	}
252

    
253
	public RecordChangeDetector getRecordChangeDetector() {
254
		return this.recordChangeDetector;
255
	}
256

    
257
	public void setRecordChangeDetector(final RecordChangeDetector recordChangeDetector) {
258
		this.recordChangeDetector = recordChangeDetector;
259
	}
260

    
261
	public MongoSetCollection getMongoSetCollection() {
262
		return this.mongoSetCollection;
263
	}
264

    
265
	public void setMongoSetCollection(final MongoSetCollection mongoSetCollection) {
266
		this.mongoSetCollection = mongoSetCollection;
267
	}
268

    
269
	public boolean isAlwaysNewRecord() {
270
		return this.alwaysNewRecord;
271
	}
272

    
273
	public void setAlwaysNewRecord(final boolean alwaysNewRecord) {
274
		this.alwaysNewRecord = alwaysNewRecord;
275
	}
276

    
277
	public Cache getMongoOaistoreCache() {
278
		return this.mongoOaistoreCache;
279
	}
280

    
281
	@Required
282
	public void setMongoOaistoreCache(final Cache mongoOaistoreCache) {
283
		this.mongoOaistoreCache = mongoOaistoreCache;
284
	}
285

    
286
	public Cache getMongoOaistoreCacheByMdPrefix() {
287
		return this.mongoOaistoreCacheByMdPrefix;
288
	}
289

    
290
	@Required
291
	public void setMongoOaistoreCacheByMdPrefix(final Cache mongoOaistoreCacheByMdPrefix) {
292
		this.mongoOaistoreCacheByMdPrefix = mongoOaistoreCacheByMdPrefix;
293
	}
294

    
295
	public CqlTranslator getCqlTranslator() {
296
		return cqlTranslator;
297
	}
298

    
299
	public void setCqlTranslator(final CqlTranslator cqlTranslator) {
300
		this.cqlTranslator = cqlTranslator;
301
	}
302

    
303
}
(4-4/6)