/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.storagedriver.impl;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AbstractChangeTrackingSet;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.db.client.model.storagedriver.DriverRegistryRecord;
import com.emc.storageos.storagedriver.Registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of persistent registry for device drivers
*/
public class RegistryImpl implements Registry {
private Logger log = LoggerFactory.getLogger(RegistryImpl.class);
private static Registry registry;
private DbClient dbClient;
private RegistryImpl(DbClient dbClient) {
this.dbClient = dbClient;
}
public static Registry getInstance(DbClient dbClient) {
if (registry == null) {
registry = new RegistryImpl(dbClient);
}
return registry;
}
@Override
public void setDriverAttributesForKey(String driverName, String key, Map<String, List<String>> attributes) {
validateRegistryRequest(driverName, key);
DriverRegistryRecord registryEntryForKey = null;
// find existing entry for driver name and a given key
boolean existingEntry = false;
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
if (registryEntry.getRegistryKey().equals(key)) {
registryEntryForKey = registryEntry;
existingEntry = true;
break;
}
}
// have not find existing driver registry entry for a key, create a new entry for this key
if (registryEntryForKey == null) {
registryEntryForKey = new DriverRegistryRecord();
registryEntryForKey.setId(URIUtil.createId(DriverRegistryRecord.class));
registryEntryForKey.setDriverName(driverName);
registryEntryForKey.setRegistryKey(key);
}
// update/add attribute map for the key entry
StringSetMap attributesMap = new StringSetMap();
for (Map.Entry<String, List<String>> entry : attributes.entrySet()) {
StringSet values = new StringSet(entry.getValue());
updateAttributeInMap(attributesMap, entry.getKey(), values);
}
registryEntryForKey.setAttributes(attributesMap);
if (existingEntry) {
dbClient.updateObject(registryEntryForKey);
} else {
dbClient.createObject(registryEntryForKey);
}
}
@Override
public Map<String, List<String>> getDriverAttributesForKey(String driverName, String key) {
validateRegistryRequest(driverName, key);
Map<String, List<String>> attributesMap = new HashMap<>();
// find existing entry for driver name and a given key
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
if (registryEntry.getRegistryKey().equals(key)) {
StringSetMap attributes = registryEntry.getAttributes();
for (Map.Entry<String, AbstractChangeTrackingSet<String>> entry : attributes.entrySet()) {
attributesMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
break;
}
}
return attributesMap;
}
@Override
public Map<String, Map<String, List<String>>> getDriverAttributes(String driverName) {
Map<String, Map<String, List<String>>> keyMap = new HashMap<>();
// find existing entries for driver name
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
Map<String, List<String>> attributesMap = new HashMap<>();
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
StringSetMap attributes = registryEntry.getAttributes();
for (Map.Entry<String, AbstractChangeTrackingSet<String>> entry : attributes.entrySet()) {
attributesMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
keyMap.put(registryEntry.getRegistryKey(), attributesMap);
}
return keyMap;
}
@Override
public void clearDriverAttributes(String driverName) {
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
dbClient.markForDeletion(registryEntry);
}
}
@Override
public void clearDriverAttributesForKey(String driverName, String key) {
validateRegistryRequest(driverName, key);
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
if (registryEntry.getRegistryKey().equals(key)) {
// remove this entry from db
dbClient.markForDeletion(registryEntry);
break;
}
}
}
@Override
public void clearDriverAttributeForKey(String driverName, String key, String attribute) {
validateRegistryRequest(driverName, key);
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
DriverRegistryRecord registryEntry = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
if (registryEntry.getRegistryKey().equals(key)) {
// remove attribute from registry entry attribute map
registryEntry.getAttributes().remove(attribute);
if (registryEntry.getAttributes().isEmpty()) {
dbClient.markForDeletion(registryEntry);
} else {
dbClient.updateObject(registryEntry);
}
break;
}
}
}
@Override
public void addDriverAttributeForKey(String driverName, String key, String attribute, List<String> value) {
validateRegistryRequest(driverName, key);
DriverRegistryRecord registryEntryForKey = null;
// find existing entry for a driver name and a given key
boolean existingKey = false;
URIQueryResultList registryEntriesUris = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDriverRegistryEntriesByDriverName(driverName), registryEntriesUris);
while (registryEntriesUris.iterator().hasNext()) {
URI registryEntryUri = registryEntriesUris.iterator().next();
registryEntryForKey = dbClient.queryObject(DriverRegistryRecord.class, registryEntryUri);
if (registryEntryForKey.getRegistryKey().equals(key)) {
existingKey = true;
StringSetMap attributes = registryEntryForKey.getAttributes();
StringSet attributeValue = new StringSet(value);
updateAttributeInMap(attributes, attribute, attributeValue);
break;
}
}
if (existingKey == false) {
// no entry for this key in the registry, create a new entry
registryEntryForKey = new DriverRegistryRecord();
registryEntryForKey.setId(URIUtil.createId(DriverRegistryRecord.class));
registryEntryForKey.setDriverName(driverName);
registryEntryForKey.setRegistryKey(key);
StringSetMap attributesMap = new StringSetMap();
StringSet values = new StringSet(value);
updateAttributeInMap(attributesMap, attribute, values);
registryEntryForKey.setAttributes(attributesMap);
}
// update db
if (existingKey) {
dbClient.updateObject(registryEntryForKey);
} else {
dbClient.createObject(registryEntryForKey);
}
}
private void validateRegistryRequest(String driverName, String key) {
if (driverName == null || key == null) {
String msg = String.format("Illegal arguments: driverName %s , key %s ", driverName, key);
log.error(msg);
throw new IllegalArgumentException(msg);
}
}
/**
* Convenience method to add/update attribute to attribute map.
*
* @param attributes attribute map
* @param attributeName name of attribute
* @param attributeValue attribute value
*/
private void updateAttributeInMap(StringSetMap attributes, String attributeName, StringSet attributeValue) {
if (attributes.containsKey(attributeName)) {
attributes.get(attributeName).replace(attributeValue);
} else {
attributes.put(attributeName, attributeValue);
}
}
}