package fr.imag.adele.histMan;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import com.mongodb.MongoException;
import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.CompositeType;
import fr.imag.adele.apam.ContextualManager;
import fr.imag.adele.apam.DynamicManager;
import fr.imag.adele.apam.Link;
import fr.imag.adele.apam.ManagerModel;
import fr.imag.adele.apam.PropertyManager;
import fr.imag.adele.apam.impl.CompositeTypeImpl;
public class HistMan implements ContextualManager, PropertyManager, DynamicManager {
public static class HistManData {
public String histURL;
public String histDBName;
public Integer histDBTimeout;
public String dropCollections;
public String dbName;
public String dbHost;
public int dbPort;
public HistManData(Properties prop) {
this.histURL = prop.getProperty(DBURL_KEY);
this.histDBName = prop.getProperty(DBNAME_KEY);
try {
this.histDBTimeout = Integer.parseInt((String)prop.get(DBTIMEOUT_KEY));
} catch (NumberFormatException e) {
this.histDBTimeout = Integer.parseInt(DBTIMEOUT_DEFAULT);
}
this.dropCollections = prop.getProperty(DBDROP_KEY);
this.dbName = prop.getProperty(DBNAME_KEY);
try {
this.dbPort = Integer.parseInt(prop.getProperty(DBPORT_KEY));
} catch (NumberFormatException e) {
this.histDBTimeout = Integer.parseInt(DBPORT_DEFAULT);
}
}
}
private int dbNameCounter=0;
// Link compositeType with it instance of obrManager
private final Map<String, String> histDbURLs;
private final Logger logger = LoggerFactory.getLogger(HistMan.class);
private Map<String, Properties> histModels = new HashMap<String, Properties>();
private MongoClient mongoClient;
/*
* The collection containing the attributes created, changed and removed.
*/
private static final String ChangedAttributes = "Attr";
/*
* The collection containing the entities (spec, implems, instances)
* created, and deleted
*/
private static final String Entities = "ME";
/*
* The collection containing the links (wires) created, and deleted
*/
private static final String Links = "Links";
private static final String DEFAULT_MODEL = "default";
private static final String DBHOST_KEY = "DBHost";
private static final String DBHOST_DEFAULT = "localhost";
private static final String DBPORT_KEY = "DBPort";
private static final String DBPORT_DEFAULT = "27017";
private static final String DBURL_KEY = "DBUrl";
private static final String DBNAME_KEY = "DBName";
private static final String DBNAME_DEFAULT = "ApamRootHistory";
private static final String DBTIMEOUT_KEY = "DBTimeout";
private static final String DBTIMEOUT_DEFAULT = "3000";
private static final String DBDROP_KEY = "dropCollectionsOnStart";
private static final Object DBDROP_DEFAULT = "true";
private DB db = null;
/**
* HISTMAN activated, register with APAM
*/
public HistMan(BundleContext context) {
histDbURLs = new HashMap<String, String>();
}
@Override
public void initializeContext(CompositeType context) {
ManagerModel model = context.getModel(this);
logger.debug("HISTMAN, newComposite(ManagerModel model = "
+(model==null?"null":model.getManagerName())
+ "CompositeType compositeType = "
+(context==null?"null":context.getName()));
if (model == null) { // model is root
model = CompositeTypeImpl.getRootCompositeType().getModel(this);
}
HistManData data =new HistManData(loadProperties(model));
try {
Builder options = new MongoClientOptions.Builder();
options.connectTimeout(data.histDBTimeout);
if(mongoClient==null) {
mongoClient = new MongoClient(data.histURL, options.build());
}
logger.info("trying to connect with database {} in host {}",
data.histDBName, data.histURL);
// force connection to be established
mongoClient.getDatabaseNames();
db = mongoClient.getDB(data.histDBName);
} catch (Exception e) {
logger.error("{} is inactive, it was unable to find the DB in {}",
this.getName(), data.histURL);
}
histDbURLs.put(context.getName(), data.histURL);
try {
// force connection to be established
mongoClient.getDatabaseNames();
/*
* if attribute dropComection is true, drop all collections
*/
if (data.dropCollections.equals("true")) {
db.getCollection(Entities).drop();
db.getCollection(ChangedAttributes).drop();
db.getCollection(Links).drop();
}
} catch (MongoException e) {
logger.error("no Mongo Database at URL {} name {}", model.getURL(),
data.histDBName);
stop();
}
}
@Override
public void addedComponent(Component comp) {
logger.info("Adding component");
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ME = db.getCollection(Entities);
BasicDBObject created = new BasicDBObject("name", comp.getName())
.append("time", System.currentTimeMillis()).append("op",
"created");
for (Map.Entry<String, Object> e : comp.getAllProperties()
.entrySet()) {
created.append(e.getKey().replace('.', '_'), e.getValue()
.toString());
}
ME.insert(created);
} catch (MongoException e) {
stop();
}
}
@Override
public void addedLink(Link wire) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ChangedLink = db.getCollection(Links);
BasicDBObject newLink = new BasicDBObject("name", wire.getSource()
.getName()).append("time", System.currentTimeMillis())
.append("linkType", "Wire")
.append("linkId", wire.getName())
.append("added", wire.getDestination().getName());
ChangedLink.insert(newLink);
} catch (MongoException e) {
stop();
}
}
@Override
public void attributeAdded(Component comp, String attr, String newValue) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ChangedAttr = db.getCollection(ChangedAttributes);
BasicDBObject newVal = new BasicDBObject("name", comp.getName())
.append("time", System.currentTimeMillis())
.append("op", "added").append("attribute", attr)
.append("value", newValue);
for (Map.Entry<String, Object> e : comp.getAllProperties()
.entrySet()) {
newVal.append(e.getKey(), e.getValue().toString());
}
ChangedAttr.insert(newVal);
} catch (MongoException e) {
stop();
}
}
@Override
public void attributeChanged(Component comp, String attr, String newValue,
String oldValue) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ChangedAttr = db.getCollection(ChangedAttributes);
BasicDBObject newVal = new BasicDBObject("name", comp.getName())
.append("time", System.currentTimeMillis())
.append("op", "changed").append("attribute", attr)
.append("value", newValue).append("oldValue", oldValue);
for (Map.Entry<String, Object> e : comp.getAllProperties()
.entrySet()) {
newVal.append(e.getKey(), e.getValue().toString());
}
ChangedAttr.insert(newVal);
} catch (MongoException e) {
stop();
}
}
@Override
public void attributeRemoved(Component comp, String attr, String oldValue) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ChangedAttr = db.getCollection(ChangedAttributes);
BasicDBObject newVal = new BasicDBObject("name", comp.getName())
.append("time", System.currentTimeMillis())
.append("op", "removed").append("attribute", attr)
.append("oldValue", oldValue);
for (Map.Entry<String, Object> e : comp.getAllProperties()
.entrySet()) {
newVal.append(e.getKey(), e.getValue().toString());
}
ChangedAttr.insert(newVal);
} catch (MongoException e) {
stop();
}
}
@Override
public String getName() {
return "HISTMAN";
}
private Properties addDefaultProperties(String modelName, Properties prop_model) {
if (prop_model == null) {
prop_model = new Properties();
}
logger.debug("For model : "+modelName);
if (prop_model.get(DBHOST_KEY) == null)
prop_model.put(DBHOST_KEY, DBHOST_DEFAULT);
logger.debug(" -> loaded DB Host : "+prop_model.get(DBHOST_KEY));
if (prop_model.get(DBPORT_KEY) == null)
prop_model.put(DBPORT_KEY, DBPORT_DEFAULT);
logger.debug(" -> loaded DB Port : "+prop_model.get(DBPORT_KEY));
if (prop_model.get(DBURL_KEY) == null)
prop_model.put(DBURL_KEY, DBHOST_DEFAULT.concat(":"+prop_model.get(DBPORT_KEY)));
logger.debug(" -> loaded DB URL : "+prop_model.get(DBURL_KEY));
if (prop_model.get(DBNAME_KEY) == null)
prop_model.put(DBNAME_KEY, DBNAME_DEFAULT.concat(String.valueOf(dbNameCounter++)));
logger.debug(" -> loaded DB Name : "+prop_model.get(DBNAME_KEY));
if (prop_model.get(DBTIMEOUT_KEY) == null)
prop_model.put(DBTIMEOUT_KEY, DBTIMEOUT_DEFAULT);
logger.debug(" -> loaded DB Timeout : "+prop_model.get(DBTIMEOUT_KEY));
if (prop_model.get(DBDROP_KEY) == null)
prop_model.put(DBDROP_KEY, DBDROP_DEFAULT);
logger.debug(" -> loaded DB Dropping Collection : "+prop_model.get(DBDROP_KEY));
histModels.put(modelName, prop_model);
return prop_model;
}
private Properties loadProperties(ManagerModel model) {
/*
* if no model for the compositeType, set the default values
*/
if (model == null) {
return addDefaultProperties(DEFAULT_MODEL, null);
} else {
try {// try to load the compositeType model
logger.info("Loading properties from {}", model.getURL());
Properties prop_model = new Properties();
prop_model.load(model.getURL().openStream());
return addDefaultProperties(model.getManagerName(), prop_model);
} catch (IOException e) {// if impossible to load the model for the
// compositeType, set the root composite
logger.error(
"Invalid Model. Cannot be read stream "
+ model.getURL(), e.getCause());
return addDefaultProperties(model.getManagerName(), null);
}
}
}
@Override
public void removedComponent(Component comp) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
logger.info("removing component");
DBCollection ME = db.getCollection(Entities);
BasicDBObject created = new BasicDBObject("name", comp.getName())
.append("time", System.currentTimeMillis()).append("op",
"deleted");
ME.insert(created);
} catch (MongoException e) {
stop();
}
}
@Override
public void removedLink(Link wire) {
try {
// force connection to be established
mongoClient.getDatabaseNames();
DBCollection ChangedLink = db.getCollection(Links);
BasicDBObject newLink = new BasicDBObject("name", wire.getSource()
.getName()).append("time", System.currentTimeMillis())
.append("linkType", "Wire")
.append("linkId", wire.getName())
.append("removed", wire.getDestination().getName());
ChangedLink.insert(newLink);
} catch (MongoException e) {
stop();
}
}
public void start() throws Exception {
ApamManagers.addPropertyManager(this);
ApamManagers.addDynamicManager(this);
}
public void stop() {
ApamManagers.removePropertyManager(this);
ApamManagers.removeDynamicManager(this);
histDbURLs.clear();
}
}