/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.nifi.processors.mongodb; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.net.ssl.SSLContext; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.annotation.lifecycle.OnStopped; import org.apache.nifi.authentication.exception.ProviderCreationException; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.processor.AbstractProcessor; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.security.util.SslContextFactory; import org.apache.nifi.ssl.SSLContextService; import org.bson.Document; import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; import com.mongodb.MongoClientOptions.Builder; import com.mongodb.MongoClientURI; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; public abstract class AbstractMongoProcessor extends AbstractProcessor { protected static final PropertyDescriptor URI = new PropertyDescriptor.Builder() .name("Mongo URI") .description("MongoURI, typically of the form: mongodb://host1[:port1][,host2[:port2],...]") .required(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .build(); protected static final PropertyDescriptor DATABASE_NAME = new PropertyDescriptor.Builder() .name("Mongo Database Name") .description("The name of the database to use") .required(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .build(); protected static final PropertyDescriptor COLLECTION_NAME = new PropertyDescriptor.Builder() .name("Mongo Collection Name") .description("The name of the collection to use") .required(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .build(); public static final PropertyDescriptor SSL_CONTEXT_SERVICE = new PropertyDescriptor.Builder() .name("ssl-context-service") .displayName("SSL Context Service") .description("The SSL Context Service used to provide client certificate information for TLS/SSL " + "connections.") .required(false) .identifiesControllerService(SSLContextService.class) .build(); public static final PropertyDescriptor CLIENT_AUTH = new PropertyDescriptor.Builder() .name("ssl-client-auth") .displayName("Client Auth") .description("Client authentication policy when connecting to secure (TLS/SSL) cluster. " + "Possible values are REQUIRED, WANT, NONE. This property is only used when an SSL Context " + "has been defined and enabled.") .required(false) .allowableValues(SSLContextService.ClientAuth.values()) .defaultValue("REQUIRED") .build(); static List<PropertyDescriptor> descriptors = new ArrayList<>(); static { descriptors.add(URI); descriptors.add(DATABASE_NAME); descriptors.add(COLLECTION_NAME); descriptors.add(SSL_CONTEXT_SERVICE); descriptors.add(CLIENT_AUTH); } protected MongoClient mongoClient; @OnScheduled public final void createClient(ProcessContext context) throws IOException { if (mongoClient != null) { closeClient(); } getLogger().info("Creating MongoClient"); // Set up the client for secure (SSL/TLS communications) if configured to do so final SSLContextService sslService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class); final String rawClientAuth = context.getProperty(CLIENT_AUTH).getValue(); final SSLContext sslContext; if (sslService != null) { final SSLContextService.ClientAuth clientAuth; if (StringUtils.isBlank(rawClientAuth)) { clientAuth = SSLContextService.ClientAuth.REQUIRED; } else { try { clientAuth = SSLContextService.ClientAuth.valueOf(rawClientAuth); } catch (final IllegalArgumentException iae) { throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]", rawClientAuth, StringUtils.join(SslContextFactory.ClientAuth.values(), ", "))); } } sslContext = sslService.createSSLContext(clientAuth); } else { sslContext = null; } try { final String uri = context.getProperty(URI).getValue(); if(sslContext == null) { mongoClient = new MongoClient(new MongoClientURI(uri)); } else { mongoClient = new MongoClient(new MongoClientURI(uri, getClientOptions(sslContext))); } } catch (Exception e) { getLogger().error("Failed to schedule {} due to {}", new Object[] { this.getClass().getName(), e }, e); throw e; } } protected Builder getClientOptions(final SSLContext sslContext) { MongoClientOptions.Builder builder = MongoClientOptions.builder(); builder.sslEnabled(true); builder.socketFactory(sslContext.getSocketFactory()); return builder; } @OnStopped public final void closeClient() { if (mongoClient != null) { getLogger().info("Closing MongoClient"); mongoClient.close(); mongoClient = null; } } protected MongoDatabase getDatabase(final ProcessContext context) { final String databaseName = context.getProperty(DATABASE_NAME).getValue(); return mongoClient.getDatabase(databaseName); } protected MongoCollection<Document> getCollection(final ProcessContext context) { final String collectionName = context.getProperty(COLLECTION_NAME).getValue(); return getDatabase(context).getCollection(collectionName); } }