package org.amdatu.mongo.impl;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.amdatu.mongo.MongoDBService;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.log.LogService;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoOptions;
import com.mongodb.MongoURI;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
public class MongoDBServiceFactory implements ManagedServiceFactory {
private Map<String, Component> m_Components = new ConcurrentHashMap<String, Component>();
private volatile LogService m_logService;
private volatile DependencyManager m_dependencyManager;
@Override
public String getName() {
return "org.amdatu.mongo";
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void updated(String pid, Dictionary properties) throws ConfigurationException {
if (!m_Components.containsKey(pid)) {
String host = getProperty(properties, "host", "localhost");
int port = getProperty(properties, "port", 27017);
String mongoURI = getProperty(properties, "mongoURI", null);
String writeConcern = getProperty(properties, "writeConcern", "NORMAL");
String readPreference = getProperty(properties, "readPreference", "PrimaryReadPreference");
String dbName = getProperty(properties, "dbName", "test");
String username = getProperty(properties, "username", null);
String password = getProperty(properties, "password", null);
try {
Mongo mongo;
if (mongoURI != null) {
MongoURI uri = new MongoURI(mongoURI);
mongo = new Mongo(uri);
}
else {
MongoOptions mongoOptions = createMongoOptions(properties);
mongo = createMongo(host, port, mongoOptions);
}
mongo.setWriteConcern(WriteConcern.valueOf(writeConcern));
if (readPreference.equals("PrimaryReadPreference")) {
mongo.setReadPreference(ReadPreference.PRIMARY);
}
else if (readPreference.equals("PrimaryReadPreference")) {
mongo.setReadPreference(ReadPreference.SECONDARY);
} else {
m_logService.log(LogService.LOG_ERROR, "ReadPreference '" + readPreference + "' is not supported and was ignored." );
}
if(username != null) {
mongo.getDB(dbName).authenticate(username, password.toCharArray());
m_logService.log(LogService.LOG_INFO, "Authenticated as '" + username + "'");
}
MongoDBServiceImpl instance = new MongoDBServiceImpl(mongo, mongo.getDB(dbName));
Properties serviceProperties = new Properties();
serviceProperties.put("dbName", dbName);
Component component = m_dependencyManager.createComponent().setInterface(MongoDBService.class.getName(), serviceProperties).setImplementation(instance);
m_dependencyManager.add(component);
m_Components.put(pid, component);
m_logService.log(LogService.LOG_INFO, "Created MongoDB service for pid '" + pid + "'");
}
catch (MongoException e) {
throw new RuntimeException(e);
}
catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
private Mongo createMongo(String host, int port, MongoOptions mongoOptions) throws UnknownHostException {
Mongo mongo;
if(host.contains(",")) {
String[] hosts = host.split(",");
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
for (String hostUrl : hosts) {
ServerAddress serverAddress;
if(hostUrl.contains(":")) {
String[] hostUrlParts = hostUrl.split(":");
port = Integer.parseInt(hostUrlParts[1]);
serverAddress = new ServerAddress(hostUrlParts[0], port);
} else {
serverAddress = new ServerAddress(hostUrl);
}
addresses.add(serverAddress);
}
mongo = new Mongo(addresses, mongoOptions);
} else {
mongo = new Mongo(new ServerAddress(host, port), mongoOptions);
}
return mongo;
}
private MongoOptions createMongoOptions(Dictionary<String,String> properties) {
boolean autoConnectRetry = getProperty(properties, "autoConnectRetry", false);
int connectionsPerHost = getProperty(properties, "connectionsPerHost", 10);
int connectTimeout = getProperty(properties, "connectTimeout", 0);
String description = getProperty(properties, "description", "");
boolean fsync = getProperty(properties, "fsync", false);
boolean j = getProperty(properties, "j", false);
long maxAutoConnectRetryTime = getProperty(properties, "maxAutoConnectRetryTime", 0l);
int maxWaitTime = getProperty(properties, "maxWaitTime", 120000);
boolean safe = getProperty(properties, "safe", false);
boolean socketKeepAlive = getProperty(properties, "socketKeepAlive ", false);
int socketTimeout = getProperty(properties, "socketTimeout", 0);
int threadsAllowedToBlockForConnectionMultiplier = getProperty(properties, "threadsAllowedToBlockForConnectionMultiplier", 5);
int w = getProperty(properties, "w", 0);
int wtimeout = getProperty(properties, "wtimeout", 0);
MongoOptions mongoOptions = new MongoOptions();
mongoOptions.autoConnectRetry = autoConnectRetry;
mongoOptions.connectionsPerHost = connectionsPerHost;
mongoOptions.connectTimeout = connectTimeout;
mongoOptions.description = description;
mongoOptions.fsync = fsync;
mongoOptions.j = j;
mongoOptions.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
mongoOptions.maxWaitTime = maxWaitTime;
mongoOptions.safe = safe;
mongoOptions.socketKeepAlive = socketKeepAlive;
mongoOptions.socketTimeout = socketTimeout;
mongoOptions.threadsAllowedToBlockForConnectionMultiplier = threadsAllowedToBlockForConnectionMultiplier;
mongoOptions.w = w;
mongoOptions.wtimeout = wtimeout;
return mongoOptions;
}
@Override
public void deleted(String pid) {
if(m_Components.containsKey(pid)) {
Component instance = m_Components.get(pid);
((MongoDBServiceImpl)instance.getService()).close();
m_dependencyManager.remove(instance);
m_Components.remove(pid);
m_logService.log(LogService.LOG_INFO, "Removed MongoDB service for pid '" + pid + "'");
}
}
private String getProperty(Dictionary<String, String> properties, String key, String defaultValue) {
String value = properties.get(key);
if (value == null) {
return defaultValue;
}
else {
return value;
}
}
private boolean getProperty(Dictionary<String, String> properties, String key, boolean defaultValue) {
String value = properties.get(key);
if (value == null) {
return defaultValue;
}
else {
return Boolean.parseBoolean(value);
}
}
private int getProperty(Dictionary<String, String> properties, String key, int defaultValue) {
String value = properties.get(key);
if (value == null) {
return defaultValue;
}
else {
return Integer.parseInt(value);
}
}
private long getProperty(Dictionary<String, String> properties, String key, long defaultValue) {
String value = properties.get(key);
if (value == null) {
return defaultValue;
}
else {
return Long.parseLong(value);
}
}
}