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.mongodb.core; 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.ecm.core.repository.RepositoryService; 029import org.nuxeo.runtime.api.Framework; 030import org.nuxeo.runtime.model.ComponentContext; 031import org.nuxeo.runtime.model.ComponentInstance; 032import org.nuxeo.runtime.model.ContributionFragmentRegistry.FragmentList; 033import org.nuxeo.runtime.model.DefaultComponent; 034import org.nuxeo.runtime.model.SimpleContributionRegistry; 035 036import com.mongodb.MongoClient; 037import com.mongodb.client.MongoDatabase; 038 039/** 040 * Component used to get a database connection to MongoDB. Don't expose {@link MongoClient} directly, because it's this 041 * component which is responsible for creating and closing it. 042 * 043 * @since 9.1 044 */ 045public class MongoDBComponent extends DefaultComponent implements MongoDBConnectionService { 046 047 private static final Log log = LogFactory.getLog(MongoDBComponent.class); 048 049 public static final String NAME = "org.nuxeo.mongodb.core.MongoDBComponent"; 050 051 private static final String EP_CONNECTION = "connection"; 052 053 private static final String DEFAULT_CONNECTION_ID = "default"; 054 055 private final MongoDBConnectionConfigRegistry registry = new MongoDBConnectionConfigRegistry(); 056 057 private final Map<String, MongoClient> clients = new ConcurrentHashMap<>(); 058 059 @Override 060 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 061 switch (extensionPoint) { 062 case EP_CONNECTION: 063 registry.addContribution((MongoDBConnectionConfig) contribution); 064 log.info( 065 "Registering connection configuration: " + contribution + ", loaded from " + contributor.getName()); 066 break; 067 default: 068 throw new IllegalStateException("Invalid EP: " + extensionPoint); 069 } 070 } 071 072 @Override 073 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 074 switch (extensionPoint) { 075 case EP_CONNECTION: 076 MongoDBConnectionConfig config = (MongoDBConnectionConfig) contribution; 077 log.info("Unregistering connection configuration: " + config); 078 clients.remove(config.getId()).close(); 079 registry.removeContribution(config); 080 break; 081 default: 082 throw new IllegalStateException("Invalid EP: " + extensionPoint); 083 } 084 } 085 086 @Override 087 public void applicationStarted(ComponentContext context) { 088 log.info("Activate MongoDB component"); 089 for (FragmentList<MongoDBConnectionConfig> fragment : registry.getFragments()) { 090 MongoDBConnectionConfig conf = fragment.object; 091 log.debug("Initializing MongoClient with id=" + conf.getId()); 092 MongoClient client = MongoDBConnectionHelper.newMongoClient(conf.getServer()); 093 clients.put(conf.getId(), client); 094 } 095 } 096 097 @Override 098 public void deactivate(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 RepositoryService component = (RepositoryService) Framework.getRuntime().getComponent( 112 "org.nuxeo.ecm.core.repository.RepositoryServiceComponent"); 113 return component.getApplicationStartedOrder() + 1; 114 } 115 116 /** 117 * @param id the connection id to retrieve. 118 * @return the database configured by {@link MongoDBConnectionConfig} for the input id, or the default one if it 119 * doesn't exist 120 */ 121 @Override 122 public MongoDatabase getDatabase(String id) { 123 MongoDBConnectionConfig config = registry.getCurrentContribution(id); 124 MongoClient client = clients.get(id); 125 if (client == null) { 126 config = registry.getCurrentContribution(DEFAULT_CONNECTION_ID); 127 client = clients.get(DEFAULT_CONNECTION_ID); 128 } 129 return MongoDBConnectionHelper.getDatabase(client, config.getDbname()); 130 } 131 132 /** 133 * @return all configured databases 134 */ 135 @Override 136 public Iterable<MongoDatabase> getDatabases() { 137 return () -> clients.entrySet() 138 .stream() 139 .map(e -> MongoDBConnectionHelper.getDatabase(e.getValue(), 140 registry.getCurrentContribution(e.getKey()).getDbname())) 141 .iterator(); 142 } 143 144 private static class MongoDBConnectionConfigRegistry extends SimpleContributionRegistry<MongoDBConnectionConfig> { 145 146 @Override 147 public String getContributionId(MongoDBConnectionConfig contrib) { 148 return contrib.getId(); 149 } 150 151 @Override 152 public MongoDBConnectionConfig getCurrentContribution(String id) { 153 return super.getCurrentContribution(id); 154 } 155 156 } 157 158}