package de.cinovo.cloudconductor.server.web.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.Table.Cell;
import de.cinovo.cloudconductor.server.comparators.ConfigComperator;
import de.cinovo.cloudconductor.server.dao.IConfigValueDAO;
import de.cinovo.cloudconductor.server.model.EConfigValue;
import de.cinovo.cloudconductor.server.util.ReservedConfigKeyStore;
import de.cinovo.cloudconductor.server.util.exception.FormErrorException;
import de.cinovo.cloudconductor.server.web.CSViewModel;
import de.cinovo.cloudconductor.server.web.helper.AWebPage;
import de.cinovo.cloudconductor.server.web.helper.AjaxAnswer;
import de.cinovo.cloudconductor.server.web.helper.NavbarHardLinks;
import de.cinovo.cloudconductor.server.web.interfaces.IConfig;
import de.cinovo.cloudconductor.server.web.interfaces.IWebPath;
import de.taimos.cxf_renderer.model.RenderedUI;
import de.taimos.restutils.RESTAssert;
/**
* Copyright 2014 Cinovo AG<br>
* <br>
*
* @author psigloch
*
*/
public class ConfigImpl extends AWebPage implements IConfig {
@Autowired
protected IConfigValueDAO dConfig;
@Override
protected String getTemplateFolder() {
return "config";
}
@Override
protected void init() {
this.navRegistry.registerSubMenu(NavbarHardLinks.config, this.getNavElementName(), IConfig.ROOT);
this.addBreadCrumb(IWebPath.WEBROOT + IConfig.ROOT, this.getNavElementName());
this.addTopAction(IWebPath.WEBROOT + IConfig.ROOT + IWebPath.ACTION_ADD, "Create new Key");
this.addTopAction(IWebPath.WEBROOT + IConfig.ROOT + IConfig.BATCH_ACTION, "Batch modify");
}
private String templateNormer(String template) {
return template.trim().replace(" ", "_");
}
@Override
protected String getNavElementName() {
return "Config";
}
@Override
@Transactional
public RenderedUI view(String viewtype) {
this.clearViewType();
for (String template : this.dConfig.findTemplates()) {
if (template.equals(IConfig.RESERVED_GLOBAL)) {
this.addViewType(template, template, true);
} else {
this.addViewType(this.templateNormer(template), template, false);
}
}
String template = viewtype == null ? IConfig.RESERVED_GLOBAL : viewtype;
List<EConfigValue> configs = this.dConfig.findAll(template);
Map<String, List<EConfigValue>> conf = new HashMap<String, List<EConfigValue>>();
for (EConfigValue val : configs) {
String service = val.getService();
if ((service != null) && service.isEmpty()) {
service = null;
}
if (!conf.containsKey(service)) {
conf.put(service, new ArrayList<EConfigValue>());
}
conf.get(service).add(val);
}
ConfigComperator comperator = new ConfigComperator();
for (Entry<String, List<EConfigValue>> a : conf.entrySet()) {
Collections.sort(a.getValue(), comperator);
}
CSViewModel view = this.createView();
view.addModel("CONFIGS", this.sortMap(conf));
view.addModel("TEMPLATE", template);
return view.render();
}
@Override
public RenderedUI deleteConfigView(String id) {
RESTAssert.assertNotEmpty(id);
EConfigValue config = this.dConfig.findById(Long.valueOf(id));
RESTAssert.assertNotNull(config);
CSViewModel modal = this.createModal("mDeleteConfig");
modal.addModel("CONFIG", config);
return modal.render();
}
@Override
public RenderedUI deleteTemplateView(String template) {
RESTAssert.assertNotNull(template);
CSViewModel modal = this.createModal("mDeleteConfig");
modal.addModel("TEMPLATE", template);
return modal.render();
}
@Override
public RenderedUI deleteServiceView(String template, String service) {
RESTAssert.assertNotNull(template);
CSViewModel modal = this.createModal("mDeleteConfig");
modal.addModel("TEMPLATE", template);
modal.addModel("SERVICE", service);
return modal.render();
}
@Override
public RenderedUI editConfigView(String id) {
RESTAssert.assertNotEmpty(id);
EConfigValue config = this.dConfig.findById(Long.valueOf(id));
RESTAssert.assertNotNull(config);
CSViewModel modal = this.createModal("mModConfig");
modal.addModel("CONFIG", config);
return modal.render();
}
@Override
public RenderedUI addConfigView() {
CSViewModel modal = this.createModal("mModConfig");
return modal.render();
}
@Override
public RenderedUI addConfigView(String template) {
RESTAssert.assertNotNull(template);
CSViewModel modal = this.createModal("mModConfig");
modal.addModel("TEMPLATE", template);
return modal.render();
}
@Override
public RenderedUI addConfigView(String template, String service) {
RESTAssert.assertNotNull(template);
RESTAssert.assertNotNull(service);
CSViewModel modal = this.createModal("mModConfig");
modal.addModel("TEMPLATE", template);
modal.addModel("SERVICE", service);
return modal.render();
}
@Override
public RenderedUI batchModView() {
List<EConfigValue> total = this.dConfig.findList();
StringBuffer buffer = new StringBuffer();
for (EConfigValue value : total) {
buffer.append("#+/");
buffer.append(value.getTemplate());
buffer.append("/");
buffer.append(value.getService());
buffer.append("/");
buffer.append(value.getConfigkey());
buffer.append("=");
buffer.append(value.getValue());
buffer.append(System.lineSeparator());
}
CSViewModel modal = this.createModal("mBatchMod");
modal.addModel("BATCHDEFAULT", buffer.toString());
return modal.render();
}
@Override
public AjaxAnswer save(String oldId, String template, String service, String key, String value) throws FormErrorException {
FormErrorException error = null;
error = this.assertNotEmpty(template, error, "template");
error = this.assertNotEmpty(key, error, "key");
error = this.assertNotEmpty(value, error, "value");
if (ReservedConfigKeyStore.instance.isReserved(key)) {
error = error == null ? this.createError("The key is a reserved by CloudConductor. Please choose another one.") : error;
}
EConfigValue config = (oldId == null) || (Long.valueOf(oldId) < 1) ? null : this.dConfig.findById(Long.valueOf(oldId));
if ((config == null) || !config.getConfigkey().equals(key)) {
if ((service != null) && !service.isEmpty() && (this.dConfig.findBy(template, service, key) != null)) {
error = error == null ? this.createError("The key already exists.") : error;
error.addElementError("key", true);
} else if (this.dConfig.findKey(template, key) != null) {
error = error == null ? this.createError("The key already exists.") : error;
error.addElementError("key", true);
}
}
if (error != null) {
error.addFormParam("oldId", oldId);
error.addFormParam("template", template);
error.addFormParam("service", service);
error.addFormParam("key", key);
error.addFormParam("value", value);
if ((oldId != null) && oldId.equals("0")) {
error.setParentUrl(IConfig.ROOT, IWebPath.ACTION_ADD);
} else {
error.setParentUrl(IConfig.ROOT, oldId, IWebPath.ACTION_EDIT);
}
throw error;
}
if (config == null) {
config = new EConfigValue();
}
config.setTemplate(template);
config.setService((service == null) || service.isEmpty() ? null : service);
config.setConfigkey(key);
config.setValue(value);
this.dConfig.save(config);
this.addViewType(template, template, false);
return new AjaxAnswer(IWebPath.WEBROOT + IConfig.ROOT, template);
}
@Override
public AjaxAnswer deleteConfig(String id) {
RESTAssert.assertNotEmpty(id);
EConfigValue config = this.dConfig.findById(Long.valueOf(id));
RESTAssert.assertNotNull(config);
String auditMessage = "Removed config " + config.getConfigkey() + " from template " + config.getTemplate() + " and service " + config.getService();
this.dConfig.delete(config, auditMessage);
return new AjaxAnswer(IWebPath.WEBROOT + IConfig.ROOT, config.getTemplate());
}
@Override
public AjaxAnswer deleteTemplate(String template) {
RESTAssert.assertNotEmpty(template);
List<EConfigValue> found = this.dConfig.findAll(template);
for (EConfigValue cv : found) {
this.dConfig.delete(cv, "Removed template " + template);
}
return new AjaxAnswer(IWebPath.WEBROOT + IConfig.ROOT, IConfig.RESERVED_GLOBAL);
}
@Override
public AjaxAnswer deleteService(String template, String service) {
RESTAssert.assertNotEmpty(template);
RESTAssert.assertNotEmpty(service);
List<EConfigValue> found = this.dConfig.findBy(template, service);
for (EConfigValue cv : found) {
this.dConfig.delete(cv, "Removed service " + service + " of template " + template);
}
return new AjaxAnswer(IWebPath.WEBROOT + IConfig.ROOT);
}
@Override
public AjaxAnswer batchMod(String batch) {
RESTAssert.assertNotEmpty(batch);
Map<String, String> drop = new HashMap<>();
Table<String, String, Set<String>> remove = HashBasedTable.create();
Table<String, String, Map<String, String>> add = HashBasedTable.create();
try (Scanner sc = new Scanner(batch)) {
while (sc.hasNextLine()) {
String[] line = sc.nextLine().split("/", 4);
if ((line == null) || (line.length < 2) || line[0].startsWith("#")) {
continue;
}
if (line.length < 3) {
String[] tmp = new String[3];
tmp[0] = line[0];
tmp[1] = line[1];
tmp[2] = "";
line = tmp;
}
String[] pair = new String[2];
if ((line.length >= 4) && !line[3].isEmpty()) {
if (line[3].contains("=")) {
pair = line[3].split("=", 2);
} else {
pair[0] = line[3];
}
}
switch (line[0]) {
case "DROP":
drop.put(line[1], line[2]);
break;
case "-":
if ((pair[0] == null) || pair[0].isEmpty()) {
drop.put(line[1], line[2]);
continue;
}
if (remove.get(line[1], line[2]) == null) {
remove.put(line[1], line[2], new HashSet<String>());
}
remove.get(line[1], line[2]).add(pair[0]);
break;
case "+":
if (add.get(line[1], line[2]) == null) {
add.put(line[1], line[2], new HashMap<String, String>());
}
add.get(line[1], line[2]).put(pair[0], pair[1]);
break;
default:
break;
}
}
}
// drop
for (Entry<String, String> entry : drop.entrySet()) {
for (EConfigValue ecv : this.dConfig.findBy(entry.getKey(), entry.getValue())) {
this.dConfig.delete(ecv);
}
}
// delete
for (Cell<String, String, Set<String>> entry : remove.cellSet()) {
for (EConfigValue ecv : this.dConfig.findBy(entry.getRowKey(), entry.getColumnKey())) {
if (entry.getValue().contains(ecv.getConfigkey())) {
this.dConfig.delete(ecv);
}
}
}
// add
for (Cell<String, String, Map<String, String>> entry : add.cellSet()) {
for (Entry<String, String> kv : entry.getValue().entrySet()) {
EConfigValue ecv = this.dConfig.findBy(entry.getRowKey(), entry.getColumnKey(), kv.getKey());
if (ecv == null) {
ecv = new EConfigValue();
ecv.setTemplate(entry.getRowKey());
ecv.setService(entry.getColumnKey());
ecv.setConfigkey(kv.getKey());
}
ecv.setValue(kv.getValue());
this.dConfig.save(ecv);
}
}
return new AjaxAnswer(IWebPath.WEBROOT + IConfig.ROOT);
}
}