001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.mongodb4;
018
019import org.apache.logging.log4j.Logger;
020import org.apache.logging.log4j.core.Core;
021import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
022import org.apache.logging.log4j.core.config.plugins.Plugin;
023import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
024import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
025import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
026import org.apache.logging.log4j.core.filter.AbstractFilterable;
027import org.apache.logging.log4j.status.StatusLogger;
028import org.bson.codecs.configuration.CodecRegistries;
029import org.bson.codecs.configuration.CodecRegistry;
030
031import com.mongodb.ConnectionString;
032import com.mongodb.MongoClientSettings;
033import com.mongodb.client.MongoClient;
034import com.mongodb.client.MongoClients;
035import com.mongodb.client.MongoDatabase;
036
037/**
038 * The MongoDB implementation of {@link NoSqlProvider} using the MongoDB driver
039 * version 4 API.
040 */
041@Plugin(name = "MongoDb4", category = Core.CATEGORY_NAME, printObject = true)
042public final class MongoDb4Provider implements NoSqlProvider<MongoDb4Connection> {
043
044    public static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B>
045            implements org.apache.logging.log4j.core.util.Builder<MongoDb4Provider> {
046
047        @PluginBuilderAttribute(value = "connection")
048        @Required(message = "No connection string provided")
049        private String connectionStringSource;
050
051        @PluginBuilderAttribute
052        private int collectionSize = DEFAULT_COLLECTION_SIZE;
053
054        @PluginBuilderAttribute("capped")
055        private boolean capped = false;
056
057        @Override
058        public MongoDb4Provider build() {
059            return new MongoDb4Provider(connectionStringSource, capped, collectionSize);
060        }
061
062        public B setCapped(final boolean isCapped) {
063            this.capped = isCapped;
064            return asBuilder();
065        }
066
067        public B setCollectionSize(final int collectionSize) {
068            this.collectionSize = collectionSize;
069            return asBuilder();
070        }
071    }
072
073    private static final Logger LOGGER = StatusLogger.getLogger();
074
075    // @formatter:off
076    private static final CodecRegistry CODEC_REGISTRIES = CodecRegistries.fromRegistries(
077            MongoClientSettings.getDefaultCodecRegistry(),
078            CodecRegistries.fromCodecs(MongoDb4LevelCodec.INSTANCE));
079    // @formatter:on
080
081    // TODO Where does this number come from?
082    private static final int DEFAULT_COLLECTION_SIZE = 536_870_912;
083
084    @PluginBuilderFactory
085    public static <B extends Builder<B>> B newBuilder() {
086        return new Builder<B>().asBuilder();
087    }
088
089    private final Integer collectionSize;
090    private final boolean isCapped;
091    private final MongoClient mongoClient;
092    private final MongoDatabase mongoDatabase;
093    private final ConnectionString connectionString;
094
095    private MongoDb4Provider(final String connectionStringSource, final boolean isCapped,
096            final Integer collectionSize) {
097        LOGGER.debug("Creating ConnectionString {}...", connectionStringSource);
098        this.connectionString = new ConnectionString(connectionStringSource);
099        LOGGER.debug("Created ConnectionString {}", connectionString);
100        LOGGER.debug("Creating MongoClientSettings...");
101        // @formatter:off
102        final MongoClientSettings settings = MongoClientSettings.builder()
103                .applyConnectionString(this.connectionString)
104                .codecRegistry(CODEC_REGISTRIES)
105                .build();
106        // @formatter:on
107        LOGGER.debug("Created MongoClientSettings {}", settings);
108        LOGGER.debug("Creating MongoClient {}...", settings);
109        this.mongoClient = MongoClients.create(settings);
110        LOGGER.debug("Created MongoClient {}", mongoClient);
111        String databaseName = this.connectionString.getDatabase();
112        LOGGER.debug("Getting MongoDatabase {}...", databaseName);
113        this.mongoDatabase = this.mongoClient.getDatabase(databaseName);
114        LOGGER.debug("Got MongoDatabase {}", mongoDatabase);
115        this.isCapped = isCapped;
116        this.collectionSize = collectionSize;
117    }
118
119    @Override
120    public MongoDb4Connection getConnection() {
121        return new MongoDb4Connection(connectionString, mongoClient, mongoDatabase, isCapped, collectionSize);
122    }
123
124    @Override
125    public String toString() {
126        return String.format(
127                "%s [connectionString=%s, collectionSize=%s, isCapped=%s, mongoClient=%s, mongoDatabase=%s]",
128                MongoDb4Provider.class.getSimpleName(), connectionString, collectionSize, isCapped, mongoClient,
129                mongoDatabase);
130    }
131
132}