001/* 002 * (C) Copyright 2017 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Kevin Leturc 018 */ 019package org.nuxeo.runtime.mongodb; 020 021import java.util.Iterator; 022import java.util.Map; 023import java.util.Map.Entry; 024import java.util.concurrent.ConcurrentHashMap; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028import org.nuxeo.runtime.model.ComponentContext; 029import org.nuxeo.runtime.model.ComponentInstance; 030import org.nuxeo.runtime.model.ComponentStartOrders; 031import org.nuxeo.runtime.model.ContributionFragmentRegistry.FragmentList; 032import org.nuxeo.runtime.model.DefaultComponent; 033import org.nuxeo.runtime.model.SimpleContributionRegistry; 034 035import com.mongodb.MongoClient; 036import com.mongodb.client.MongoDatabase; 037 038/** 039 * Component used to get a database connection to MongoDB. Don't expose {@link MongoClient} directly, because it's this 040 * component which is responsible for creating and closing it. 041 * 042 * @since 9.1 043 */ 044public class MongoDBComponent extends DefaultComponent implements MongoDBConnectionService { 045 046 private static final Log log = LogFactory.getLog(MongoDBComponent.class); 047 048 public static final String NAME = "org.nuxeo.runtime.mongodb.MongoDBComponent"; 049 050 private static final String EP_CONNECTION = "connection"; 051 052 private static final String DEFAULT_CONNECTION_ID = "default"; 053 054 private final MongoDBConnectionConfigRegistry registry = new MongoDBConnectionConfigRegistry(); 055 056 private final Map<String, MongoClient> clients = new ConcurrentHashMap<>(); 057 058 @Override 059 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 060 switch (extensionPoint) { 061 case EP_CONNECTION: 062 registry.addContribution((MongoDBConnectionConfig) contribution); 063 log.info( 064 "Registering connection configuration: " + contribution + ", loaded from " + contributor.getName()); 065 break; 066 default: 067 throw new IllegalStateException("Invalid EP: " + extensionPoint); 068 } 069 } 070 071 @Override 072 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 073 switch (extensionPoint) { 074 case EP_CONNECTION: 075 MongoDBConnectionConfig config = (MongoDBConnectionConfig) contribution; 076 log.info("Unregistering connection configuration: " + config); 077 clients.remove(config.getId()).close(); 078 registry.removeContribution(config); 079 break; 080 default: 081 throw new IllegalStateException("Invalid EP: " + extensionPoint); 082 } 083 } 084 085 @Override 086 public void start(ComponentContext context) { 087 log.info("Activate MongoDB component"); 088 for (FragmentList<MongoDBConnectionConfig> fragment : registry.getFragments()) { 089 MongoDBConnectionConfig conf = fragment.object; 090 log.debug("Initializing MongoClient with id=" + conf.getId()); 091 @SuppressWarnings("resource") 092 MongoClient client = MongoDBConnectionHelper.newMongoClient(conf.getServer()); 093 clients.put(conf.getId(), client); 094 } 095 } 096 097 @Override 098 public void stop(ComponentContext context) { 099 Iterator<Entry<String, MongoClient>> it = clients.entrySet().iterator(); 100 while (it.hasNext()) { 101 Entry<String, MongoClient> entry = it.next(); 102 log.debug("Closing MongoClient with id=" + entry.getKey()); 103 MongoClient client = entry.getValue(); 104 client.close(); 105 it.remove(); 106 } 107 } 108 109 @Override 110 public int getApplicationStartedOrder() { 111 // start before repository 112 return ComponentStartOrders.REPOSITORY - 1; 113 } 114 115 /** 116 * @param id the connection id to retrieve. 117 * @return the database configured by {@link MongoDBConnectionConfig} for the input id, or the default one if it 118 * doesn't exist 119 */ 120 @Override 121 public MongoDatabase getDatabase(String id) { 122 MongoDBConnectionConfig config = registry.getCurrentContribution(id); 123 MongoClient client = clients.get(id); 124 if (client == null) { 125 config = registry.getCurrentContribution(DEFAULT_CONNECTION_ID); 126 client = clients.get(DEFAULT_CONNECTION_ID); 127 } 128 return MongoDBConnectionHelper.getDatabase(client, config.getDbname()); 129 } 130 131 /** 132 * @return all configured databases 133 */ 134 @Override 135 public Iterable<MongoDatabase> getDatabases() { 136 return () -> clients.entrySet() 137 .stream() 138 .map(e -> MongoDBConnectionHelper.getDatabase(e.getValue(), 139 registry.getCurrentContribution(e.getKey()).getDbname())) 140 .iterator(); 141 } 142 143 protected static class MongoDBConnectionConfigRegistry extends SimpleContributionRegistry<MongoDBConnectionConfig> { 144 145 @Override 146 public String getContributionId(MongoDBConnectionConfig contrib) { 147 return contrib.getId(); 148 } 149 150 @Override 151 public MongoDBConnectionConfig getCurrentContribution(String id) { 152 return super.getCurrentContribution(id); 153 } 154 155 } 156 157}