/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.client.proxy; import org.rhq.enterprise.client.ClientMain; import org.rhq.bindings.output.TabularWriter; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.configuration.definition.ConfigurationTemplate; import org.rhq.core.domain.configuration.definition.PropertyGroupDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinition; import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; import org.rhq.core.domain.configuration.definition.PropertyDefinitionEnumeration; import org.rhq.core.domain.configuration.definition.PropertySimpleType; import java.io.PrintWriter; import java.io.IOException; import java.util.Map; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import jline.ConsoleReader; import jline.ConsoleOperations; /** * @author Greg Hinkle */ public class ConfigurationEditor { private ClientMain client; private PrintWriter writer; private ConsoleReader console; public ConfigurationEditor(ClientMain client) { this.client = client; this.writer = client.getPrintWriter(); this.console = client.getConsoleReader(); } /** * Edit a configuration interactively. Return the altered config if the user chooses * to save or null otherwise. * * @param def * @param config * @return * @throws IOException */ public Configuration editConfiguration(ConfigurationDefinition def, Configuration config) { try { Configuration newConfig = config.deepCopy(); newConfig = editExistingConfiguration(def, newConfig); while (true) { String input = console.readLine("[R]eview, [E]dit, Re[V]ert [S]ave or [C]ancel: "); char inputChar = input.charAt(0); switch (inputChar) { case 'r': case 'R': printConfiguration(newConfig); continue; case 'e': case 'E': editExistingConfiguration(def, newConfig); continue; case 'v': case 'V': newConfig = config; continue; case 's': case 'S': return newConfig; case 'c': case 'C': return null; default: writer.println("unknown option"); } } } catch (IOException e) { e.printStackTrace(); return null; } catch (QuitException e) { writer.println("Cancelling edit"); return null; } } public Configuration createConfiguration(ConfigurationDefinition def) throws IOException, QuitException { if (client.isInteractiveMode()) { throw new UnsupportedOperationException("Configuration wizard is only available in interactive model."); } Map<String, ConfigurationTemplate> templates = def.getTemplates(); ConfigurationTemplate template = (ConfigurationTemplate) question(templates, null, "template", "Select from the available templates"); return editConfiguration(def, template == null ? null : template.createConfiguration()); } public Configuration editExistingConfiguration(ConfigurationDefinition def, Configuration config) throws IOException, QuitException { List<PropertyGroupDefinition> groups = new ArrayList<PropertyGroupDefinition>(def.getGroupDefinitions()); if (config == null) { config = new Configuration(); } writer.println("Non-Grouped Properties: "); List<PropertyDefinition> properties = new ArrayList<PropertyDefinition>(def.getNonGroupedProperties()); Collections.sort(properties, new Comparator<PropertyDefinition>() { public int compare(PropertyDefinition o1, PropertyDefinition o2) { return new Integer(o1.getOrder()).compareTo(new Integer(o2.getOrder())); } }); for (PropertyDefinition propDef : properties) { question(propDef, config); } Collections.sort(groups, new Comparator<PropertyGroupDefinition>() { public int compare(PropertyGroupDefinition o1, PropertyGroupDefinition o2) { return new Integer(o1.getOrder()).compareTo(new Integer(o2.getOrder())); } }); for (PropertyGroupDefinition groupDef : groups) { writer.println("Group: " + groupDef.getDisplayName()); properties = new ArrayList<PropertyDefinition>(def.getPropertiesInGroup(groupDef.getName())); Collections.sort(properties, new Comparator<PropertyDefinition>() { public int compare(PropertyDefinition o1, PropertyDefinition o2) { return new Integer(o1.getOrder()).compareTo(new Integer(o2.getOrder())); } }); for (PropertyDefinition propDef : properties) { question(propDef, config); } } return config; } private void question(PropertyDefinition definition, Configuration template) throws IOException, QuitException { if (definition instanceof PropertyDefinitionSimple) { PropertyDefinitionSimple simpleDef = (PropertyDefinitionSimple) definition; String base = null; if (template != null && template.getSimple(definition.getName()) != null) { PropertySimple simple = template.getSimple(definition.getName()); if (simple == null) { simple = new PropertySimple(definition.getName(), null); template.put(simple); } List<PropertyDefinitionEnumeration> optionList = simpleDef.getEnumeratedValues(); if (optionList != null && optionList.size() > 0) { // Select from a set of enumerate options Map options = new LinkedHashMap(); for (PropertyDefinitionEnumeration enumValue : simpleDef.getEnumeratedValues()) { options.put(enumValue.getName(), enumValue.getValue()); } Object result = question(options, simple.getStringValue(), definition.getName(), definition.getDescription()); if (result == null) { template.remove(simple.getName()); } else { simple.setValue(result); } } else { while (true) { String currentValue = simple.getStringValue(); String prompt = definition.getName() + (currentValue != null ? "[" + currentValue + "]" : "") + ": "; String input = getInput(prompt, definition.getDescription()); if (input == null) { template.remove(simple.getName()); break; } else { try { String newval = validate(simpleDef, input); simple.setStringValue(newval); break; } catch (Exception e) { writer.println("Invalid value for " + simpleDef.getType().name() + ": " + e.getMessage()); } } } } } } } public String validate(PropertyDefinitionSimple def, String value) { switch (def.getType()) { case BOOLEAN: if ("y".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value) || "t".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)) { return Boolean.TRUE.toString(); } else if ("n".equalsIgnoreCase(value) || "no".equalsIgnoreCase(value) || "f".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) { return Boolean.FALSE.toString(); } break; case INTEGER: return String.valueOf(Integer.parseInt(value)); case LONG: return String.valueOf(Long.parseLong(value)); case FLOAT: return String.valueOf(Float.parseFloat(value)); case DOUBLE: return String.valueOf(Double.parseDouble(value)); } return null; } private Object question(Map map, String currentValue, String prompt, String help) throws IOException, QuitException { PrintWriter writer = client.getPrintWriter(); if (map != null && map.size() > 0) { writer.println("Select a " + prompt + ":"); int i = 1; int currentSelection = -1; for (Object key : map.keySet()) { if (currentValue != null && currentValue.equals(map.get(key))) currentSelection = i; writer.println("\t" + i++ + ") " + key); } writer.flush(); Object answer = null; while (answer == null) { String input = getInput(prompt + "[" + currentSelection + "]:", help); int index = -1; if (input == null) { return null; } else if (input.length() == 0) { index = currentSelection; } else { index = Integer.parseInt(input); } if (index == 0) { return null; } i = 1; for (Object templateName : map.keySet()) { if (i++ == index) { answer = map.get(templateName); writer.println("\t" + templateName + " selected."); } } } return answer; } else { return null; } } private void printConfiguration(Configuration configuration) { TabularWriter tw = new TabularWriter(writer); tw.print(configuration); } private String getInput(String prompt, String extraHelp) throws IOException, QuitException { StringBuilder buf = new StringBuilder(); writer.print(prompt); writer.flush(); try { while (true) { int ch = console.readVirtualKey(); switch ((char) ch) { case ConsoleOperations.CTRL_K: // quit editing throw new QuitException(); case ConsoleOperations.CTRL_D: // unset return null; case ConsoleOperations.CTRL_E: writer.println(); writer.println(extraHelp); writer.print(prompt); writer.print(buf.toString()); writer.print(prompt); writer.flush(); break; case 10: return buf.toString(); default: buf.append(ch); break; } } } finally { writer.println(); writer.flush(); } } static class QuitException extends Exception { } }