clients.mongodb.DBMongoClient Maven / Gradle / Ivy
The newest version!
package clients.mongodb;
import clients.mongodb.codec.DocumentCodecProvider;
import com.github.simondan.definition.*;
import com.github.simondan.definition.database.*;
import com.github.simondan.definition.fields.IDField;
import com.mongodb.MongoClient;
import com.mongodb.client.*;
import com.mongodb.client.model.UpdateOptions;
import config.InternalConfig;
import org.bson.Document;
import org.bson.codecs.configuration.*;
import org.bson.types.ObjectId;
import util.DatabaseUtil;
import java.util.*;
/**
* Klasse für den Mongo-Datenbank-Zugriff.
* Kann nicht direkt initialisiert werden, eine Instanz wird über die Methode "getInstance" geliefert.
* Bei der Erzeugung wird eine Verbindung zu der in der Config festgelegten Datenbank erzeugt.
* Diese Klasse bietet alle nötigen Methoden zu Datenbank-Abfragen und Manipulationen
*
* @author Simon Danner, 03.08.2015.
*/
public class DBMongoClient implements IDatabaseClient
{
private MongoDatabase database;
@Override
public boolean providesEmbedded()
{
return true;
}
@Override
public IEmbeddedDB startEmbedded()
{
MongoDBEmbedded embedded = new MongoDBEmbedded();
embedded.startUp();
return embedded;
}
@Override
public boolean connect()
{
MongoClient mongoClient = new MongoClient(InternalConfig.DATABASE_HOST, InternalConfig.DATABASE_PORT);
database = mongoClient.getDatabase(InternalConfig.DATABASE_NAME);
return true;
}
@Override
public T findOne(ObjectBox pBox, SearchCondition... pConditions)
{
return _getCollection(pBox).find(_conditionsToDocument(pConditions)).first();
}
@Override
public List find(ObjectBox pBox, SearchCondition... pConditions)
{
return _iterableToList(_getCollection(pBox).find(_conditionsToDocument(pConditions)));
}
@Override
public void insert(ObjectBox pBox, T pObject)
{
_getCollection(pBox).insertOne(pObject);
_checkNewObjectID(pBox, pObject);
}
@Override
public void insert(ObjectBox pBox, Collection pObjects)
{
_getCollection(pBox).insertMany(new ArrayList<>(pObjects));
_checkNewObjectID(pBox, pObjects);
}
@Override
public void update(ObjectBox pBox, T pObject, boolean pUpsert,
SearchCondition... pConditions)
{
Document filter = _conditionsToDocument(pObject, pConditions);
_getCollection(pBox).replaceOne(filter, pObject, new UpdateOptions().upsert(true));
_checkNewObjectID(pBox, pObject);
}
@Override
public void remove(ObjectBox pBox, T pObject)
{
remove(pBox, DatabaseUtil.storableObjectToConditions(pObject));
}
@Override
public void remove(ObjectBox pBox, SearchCondition... pConditions)
{
_getCollection(pBox).deleteMany(_conditionsToDocument(pConditions));
}
@Override
public int count(ObjectBox pBox, SearchCondition... pConditions)
{
return (int) _getCollection(pBox).count(_conditionsToDocument(pConditions));
}
@Override
public int size(ObjectBox pBox)
{
return (int) _getCollection(pBox).count();
}
@Override
public List getBoxAsList(ObjectBox pBox)
{
List list = new ArrayList<>();
for (T object : _getCollection(pBox).find())
list.add(object);
return list;
}
@Override
public List getSingleFieldValues(ObjectBox pBox,
AbstractFieldDescription pDescription)
{
List values = new ArrayList<>();
for (T object : getBoxAsList(pBox))
values.add(object.getValue(pDescription));
return values;
}
/**
* Gibt eine Datenbank-Collection anhand eines ObjectBox-Typen zurück.
* Dabei wird auch die Object-Class der annotations.Collection gesetzt.
*
* @param pBox die ObjectBox
* @return die bestimmte Mongo-handling.DB-annotations.Collection der aktuellen handling.DB-Verbindung
*/
private MongoCollection _getCollection(ObjectBox pBox)
{
MongoCollection collection = database.getCollection(pBox.getName(), pBox.getObjectClass());
return collection.withCodecRegistry(_getCodecRegistry(pBox.getObjectClass()));
}
/**
* Liefert eine CodecRegistry, um Collections abzufragen, die Objekte von eigenen Erweiterungen von Document
* zurückgeben können (Object-Class von MongoDB-Collections)
*
* @param pObjectClass die Klasse, die von der annotations.Collection abgefragt werden soll
* @return eine CodecRegistry mit einem eigenen DocumentCodec (siehe. Klasse: CustomDocumentCodec)
*/
private CodecRegistry _getCodecRegistry(Class extends AbstractStorableObject> pObjectClass)
{
CodecRegistry defaultCodec = MongoClient.getDefaultCodecRegistry();
CodecRegistry documentCodec = CodecRegistries.fromProviders(new DocumentCodecProvider<>(pObjectClass));
return CodecRegistries.fromRegistries(defaultCodec, documentCodec);
}
private Document _conditionsToDocument(SearchCondition... pConditions)
{
Document document = new Document();
for (SearchCondition condition : pConditions)
{
boolean isID = condition.getFieldDescription() instanceof IDField;
Object condValue = condition.getValue();
String key = isID ? InternalConfig.OBJECT_ID : condition.getKey();
Object value = isID ? condValue != null ? new ObjectId(condValue.toString()) : new ObjectId() : condValue;
document.put(key, value);
}
return document;
}
private Document _conditionsToDocument(AbstractStorableObject pObject, SearchCondition... pConditions)
{
Document filter = _conditionsToDocument(pConditions);
if (pObject instanceof AbstractUniqueStorableObject && ((AbstractUniqueStorableObject) pObject).getID() == null)
((AbstractUniqueStorableObject) pObject).setID(filter.get(InternalConfig.OBJECT_ID).toString());
return filter;
}
/**
* Wandelt ein Find-Iterable in eine Liste um
*/
private List _iterableToList(FindIterable pIterable)
{
List list = new ArrayList<>();
for (T object : pIterable)
list.add(object);
return list;
}
private void _checkNewObjectID(ObjectBox pBox, Collection pObjects)
{
for (T object : pObjects)
_checkNewObjectID(pBox, object);
}
private void _checkNewObjectID(ObjectBox pBox, T pObject)
{
if (pObject instanceof AbstractUniqueStorableObject && ((AbstractUniqueStorableObject) pObject).getID() == null)
{
T latest = _getCollection(pBox).find().sort(new Document("id", -1)).limit(1).first(); //TODO besser
String latestID = ((AbstractUniqueStorableObject) latest).getID();
((AbstractUniqueStorableObject) pObject).setID(latestID);
}
}
/**
* Setzt für ein Objekt aus der Datenbank für alle Fremdschlüssel-Referenzen die richtigen Werte ein
*
* @param pObject das Dokument, welches untersucht werden soll
* @param pCollection die betreffende annotations.Collection
*/
@SuppressWarnings("unchecked")
private void _fillForeignKeys(T pObject, ObjectBox pCollection)
{
/*for (AbstractFieldDescription description : pObject.getFieldDescriptions())
{
Reference foreignKey = metadata.getForeignKey();
if (foreignKey != null)
{
Object replacement = null;
//Sonderfall: Bei Maps können die Keys auch Referenzen sein
if (metadata.getTypeInfo().getType().equals(TypeInfo.ColumnType.MAP))
{
Map