/*
* (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Funsho David
*
*/
package org.nuxeo.directory.mongodb;
import static org.nuxeo.ecm.directory.BaseDirectoryDescriptor.CREATE_TABLE_POLICY_ALWAYS;
import static org.nuxeo.ecm.directory.BaseDirectoryDescriptor.CREATE_TABLE_POLICY_ON_MISSING_COLUMNS;
import static org.nuxeo.directory.mongodb.MongoDBSerializationHelper.MONGODB_ID;
import static org.nuxeo.directory.mongodb.MongoDBSerializationHelper.MONGODB_SEQ;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.nuxeo.ecm.core.cache.CacheService;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.Schema;
import org.nuxeo.ecm.directory.AbstractDirectory;
import org.nuxeo.ecm.directory.Directory;
import org.nuxeo.ecm.directory.DirectoryCSVLoader;
import org.nuxeo.ecm.directory.DirectoryException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.runtime.api.Framework;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
/**
* MongoDB implementation of a {@link Directory}
*
* @since 9.1
*/
public class MongoDBDirectory extends AbstractDirectory {
protected Map<String, Field> schemaFieldMap;
protected String countersCollectionName;
protected boolean initialized;
public MongoDBDirectory(MongoDBDirectoryDescriptor descriptor) {
super(descriptor);
// register the references to other directories
addReferences(descriptor.getInverseReferences());
addReferences(descriptor.getMongoDBReferences());
// cache parameterization
String cacheEntryName = descriptor.cacheEntryName;
String cacheEntryNameWithoutReferencesName = descriptor.cacheEntryWithoutReferencesName;
cache.setEntryCacheName(cacheEntryName);
cache.setEntryCacheWithoutReferencesName(cacheEntryNameWithoutReferencesName);
cache.setNegativeCaching(descriptor.negativeCaching);
// cache fallback
CacheService cacheService = Framework.getService(CacheService.class);
if (cacheService != null) {
if (cacheEntryName == null && descriptor.getCacheMaxSize() != 0) {
cache.setEntryCacheName("cache-" + getName());
cacheService.registerCache("cache-" + getName(), descriptor.getCacheMaxSize(),
descriptor.getCacheTimeout() / 60);
}
if (cacheEntryNameWithoutReferencesName == null && descriptor.getCacheMaxSize() != 0) {
cache.setEntryCacheWithoutReferencesName("cacheWithoutReference-" + getName());
cacheService.registerCache("cacheWithoutReference-" + getName(), descriptor.getCacheMaxSize(),
descriptor.getCacheTimeout() / 60);
}
}
countersCollectionName = getName() + ".counters";
}
@Override
public MongoDBDirectoryDescriptor getDescriptor() {
return (MongoDBDirectoryDescriptor) descriptor;
}
@Override
public Session getSession() throws DirectoryException {
SchemaManager schemaManager = Framework.getService(SchemaManager.class);
Schema schema = schemaManager.getSchema(getSchema());
if (schema == null) {
throw new DirectoryException(getSchema() + " is not a registered schema");
}
schemaFieldMap = new LinkedHashMap<>();
schema.getFields().forEach(f -> schemaFieldMap.put(f.getName().getLocalName(), f));
MongoDBSession session = new MongoDBSession(this);
addSession(session);
// Initialize counters collection if autoincrement enabled
if (descriptor.isAutoincrementIdField() && !session.hasCollection(countersCollectionName)) {
Map<String, Object> seq = new HashMap<>();
seq.put(MONGODB_ID, getName());
seq.put(MONGODB_SEQ, 0L);
session.getCollection(countersCollectionName).insertOne(MongoDBSerializationHelper.fieldMapToBson(seq));
}
if (!initialized) {
String policy = descriptor.getCreateTablePolicy();
MongoCollection collection = session.getCollection(getName());
boolean dropCollection = false;
boolean loadData = false;
switch (policy) {
case CREATE_TABLE_POLICY_ALWAYS:
dropCollection = true;
loadData = true;
break;
case CREATE_TABLE_POLICY_ON_MISSING_COLUMNS:
if (session.hasCollection(getName())) {
long totalEntries = collection.count();
boolean missingColumns = schema.getFields().stream().map(f -> f.getName().getLocalName()).anyMatch(
fname -> collection.count(Filters.exists(fname, false)) == totalEntries);
if (missingColumns) {
dropCollection = true;
loadData = true;
}
} else {
loadData = true;
}
break;
default:
if (!session.hasCollection(getName())) {
loadData = true;
}
break;
}
if (dropCollection) {
collection.drop();
}
if (loadData) {
loadData(schema, session);
}
initialized = true;
}
return session;
}
protected void loadData(Schema schema, Session session) {
if (descriptor.getDataFileName() != null) {
DirectoryCSVLoader.loadData(descriptor.getDataFileName(), descriptor.getDataFileCharacterSeparator(),
schema, session::createEntry);
}
}
public Map<String, Field> getSchemaFieldMap() {
return schemaFieldMap;
}
public String getCountersCollectionName() {
return countersCollectionName;
}
}