All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mastfrog.giulius.mongodb.async.ExistingCollections Maven / Gradle / Ivy

There is a newer version: 2.9.7
Show newest version
/*
 * The MIT License
 *
 * Copyright 2018 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.google.common.collect.Maps;
import com.mastfrog.settings.Settings;
import com.mastfrog.util.preconditions.Exceptions;
import com.mongodb.MongoCommandException;
import com.mongodb.async.client.MongoClient;
import com.mongodb.async.client.MongoCollection;
import com.mongodb.async.client.MongoDatabase;
import com.mongodb.client.model.CreateCollectionOptions;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.function.Supplier;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.bson.Document;

/**
 *
 * @author Tim Boudreau
 */
public class ExistingCollections {

    private final Map>> collections
            = Maps.newConcurrentMap();
    private final Provider dbName;
    private final Provider reg;
    private Provider dbProvider;
    public static final String SETTINGS_KEY_MAX_WAIT_SECONDS = "mongo.list.collections.max.wait.seconds";
    private final Provider settings;

    @Inject
    ExistingCollections(@Named(GiuliusMongoAsyncModule.SETTINGS_KEY_DATABASE_NAME) Provider dbName, Provider reg, Provider settings) {
        this.dbName = dbName;
        this.reg = reg;
        this.settings = settings;
    }

    MongoCollection get(String name) {
        Supplier> result = collections.get(name);
        if (result == null) {
            synchronized (this) {
                result = collections.get(name);
                if (result == null) {
                    addBound(name, new CreateCollectionOptions());
                    result = collections.get(name);
                }
            }
        }
        return result.get();
    }

    void init(MongoClient client, Provider clientProvider) {
        CountDownLatch latch = new CountDownLatch(1);
        dbProvider = new MongoDatabaseProvider(clientProvider, dbName.get());
        MongoDatabase db = dbProvider.get();
        Throwable[] th = new Throwable[1];
        db.listCollectionNames().batchSize(1000).forEach((name) -> {
            addExisting(name);
        }, (v, thrown) -> {
            if (thrown != null) {
                th[0] = thrown;
                return;
            }
            latch.countDown();
        });
        try {
            latch.await(settings.get().getInt(SETTINGS_KEY_MAX_WAIT_SECONDS, 60), SECONDS);
        } catch (InterruptedException ex) {
            Exceptions.chuck(ex);
        }
    }

    boolean addExisting(String s) {
        boolean result = collections.get(s) == null || collections.get(s) instanceof CreatingCollectionSupplier;
        collections.put(s, new CollectionSupplier(s));
        return result;
    }

    void addBound(String s, CreateCollectionOptions opts) {
        collections.put(s, new CreatingCollectionSupplier(s, opts));
    }

    class CreatingCollectionSupplier implements Supplier> {

        private final String name;
        private final CreateCollectionOptions opts;

        public CreatingCollectionSupplier(String name, CreateCollectionOptions opts) {
            this.name = name;
            this.opts = opts;
        }

        @Override
        public synchronized MongoCollection get() {
            if (collections.get(name) instanceof CreatingCollectionSupplier) {
                CountDownLatch latch = new CountDownLatch(1);
                Throwable[] th = new Throwable[1];
                dbProvider.get().createCollection(name, opts, (v, thrown) -> {
                    boolean created = true;
                    try {
                        if (thrown != null) {
                            if (!isAlreadyExists(thrown)) {
                                th[0] = thrown;
                                return;
                            } else {
                                created = false;
                            }
                        }
                        CollectionSupplier result = new CollectionSupplier(name);
                        if (created) {
                            reg.get().onCreateCollection(name, result.get());
                        }
                        collections.put(name, result);
                    } finally {
                        latch.countDown();
                    }
                });
                try {
                    latch.await();
                } catch (InterruptedException ex) {
                    return Exceptions.chuck(ex);
                }
                if (th[0] != null) {
                    return Exceptions.chuck(th[0]);
                }
            }
            CollectionSupplier result = new CollectionSupplier(name);
            collections.put(name, result);
            return result.get();
        }
    }

    class CollectionSupplier implements Supplier> {

        private final String name;

        CollectionSupplier(String name) {
            this.name = name;
        }

        @Override
        public MongoCollection get() {
            return dbProvider.get().getCollection(name);
        }
    }

    private boolean isAlreadyExists(Throwable thbl) {
        if (thbl instanceof MongoCommandException) {
            MongoCommandException ex = (MongoCommandException) thbl;
            boolean result = ex.getCode() == 48; // older mongodb
            if (!result) {
                result = (ex.getCode() == -1 && "collection already exists".equals(ex.getErrorMessage()))
                        || (ex.getMessage() != null && ex.getMessage().contains("colletion already exists"));
            }
            return result;
        }
        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy