/*
* The MIT License
*
* Copyright 2015 Tim Boudreau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.mastfrog.giulius.mongodb.async;
import com.mastfrog.util.Exceptions;
import com.mongodb.MongoCommandException;
import com.mongodb.async.SingleResultCallback;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import com.mongodb.client.model.CreateCollectionOptions;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Provider;
/**
*
* @author Tim Boudreau
*/
class MongoTypedCollectionProvider<T> implements Provider<MongoCollection<T>> {
private final Provider<MongoDatabase> dbProvider;
private final String collectionName;
private final Class<T> collectionType;
private final AtomicBoolean initialized = new AtomicBoolean();
private final Provider<KnownCollections> knownProvider;
private final CreateCollectionOptions createOpts;
private final Provider<MongoAsyncInitializer.Registry> inits;
MongoTypedCollectionProvider(Provider<MongoDatabase> dbProvider, String collectionName, Class<T> collectionType, Provider<KnownCollections> knownProvider, CreateCollectionOptions createOpts, Provider<MongoAsyncInitializer.Registry> inits) {
this.dbProvider = dbProvider;
this.collectionName = collectionName;
this.collectionType = collectionType;
this.knownProvider = knownProvider;
this.createOpts = createOpts;
this.inits = inits;
}
@Override
public MongoCollection<T> get() {
boolean created = false;
if (initialized.compareAndSet(false, true)) {
created = ensureCollectionExists();
}
MongoCollection<T> result = dbProvider.get().getCollection(collectionName, collectionType);
if (created) {
inits.get().onCreateCollection(collectionName, result);
}
return result;
}
private boolean ensureCollectionExists() {
if (!knownProvider.get().exists(collectionName)) {
final AtomicBoolean created = new AtomicBoolean();
final Throwable[] thrown = new Throwable[1];
final CountDownLatch latch = new CountDownLatch(1);
dbProvider.get().createCollection(collectionName, createOpts, new SingleResultCallback<Void>() {
private boolean isAlreadyExists(Throwable thbl) {
if (thbl instanceof MongoCommandException) {
MongoCommandException ex = (MongoCommandException) thbl;
return ex.getCode() == 48;
}
return false;
}
@Override
public void onResult(Void t, Throwable thrwbl) {
boolean alreadyExisted = isAlreadyExists(thrwbl);
if (alreadyExisted) { // not a failure
thrwbl = null;
}
thrown[0] = thrwbl;
if (thrwbl == null) {
knownProvider.get().add(collectionName);
created.set(!alreadyExisted);
}
latch.countDown();
}
});
try {
latch.await();
if (thrown[0] != null) {
Exceptions.chuck(thrown[0]);
}
return created.get();
} catch (InterruptedException ex) {
return Exceptions.chuck(ex);
}
}
return false;
}
}