/* * RHQ Management Platform * Copyright (C) 2005-2014 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.modules.plugins.wildfly10; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.rhq.modules.plugins.wildfly10.json.Address; import org.rhq.modules.plugins.wildfly10.json.ComplexResult; import org.rhq.modules.plugins.wildfly10.json.Operation; /** * Generate properties, metrics and operation templates for the plugin * descriptor from a domain dump (server can run in domain or standalone mode). * * @author Heiko W. Rupp */ @SuppressWarnings("unchecked") public class Domain2Descriptor { private static final String PLUGIN_NAME = "EAP7"; //Need to hard code until JIRA addressed: https://issues.jboss.org/browse/AS7-4384 private String[] properties = { "cpu", "mem", "heap", "sessions", "requests", "send-traffic", "receive-traffic", "busyness", "connection-pool" }; private D2DMode mode = null; private boolean descriptorSegment = false; public static void main(String[] args) throws Exception { if (args.length < 1) { usage(); System.exit(1); } Domain2Descriptor d2d = new Domain2Descriptor(); d2d.run(args); } private void run(String[] args) { //process and populate command line args passed in and determine //operation modes. String user = null; String pass = null; int pos = 0; boolean optionFound = false; String arg; do { arg = args[pos]; if (arg.startsWith("-")) { if (arg.equals("-m")) { mode = D2DMode.METRICS; } else if (arg.equals("-p")) { mode = D2DMode.PROPERTIES; } else if (arg.equals("-o")) { mode = D2DMode.OPERATION; } else if (arg.equals("-r")) { mode = D2DMode.RECURSIVE; } else if (arg.equals("-rd")) { mode = D2DMode.RECURSIVE; descriptorSegment = true; } else if (arg.startsWith("-U")) { String tmp = arg.substring(2); if (!tmp.contains(":")) { usage(); } user = tmp.substring(0, tmp.indexOf(":")); pass = tmp.substring(tmp.indexOf(":") + 1); } else { usage(); return; } pos++; optionFound = true; } else { optionFound = false; } } while (optionFound); String path = arg; // pwd command //spinder Mar-29-2012: if additional child type info passed in then load it. What does this look like? String childType = null; if (args.length > pos + 1) { childType = args[pos + 1]; } //create connection ASConnectionParams asConnectionParams = new ASConnectionParamsBuilder() // .setHost("localhost") // .setPort(9990) // .setUsername(user) // .setPassword(pass)// .createASConnectionParams(); ASConnection conn = new ASConnection(asConnectionParams); try { Address address = new Address(path); //create request to get metadata type information Operation op = new Operation("read-resource-description", address); //recurse down the tree. op.addAdditionalProperty("recursive", "true"); //additionally request operation metadata if (mode == D2DMode.OPERATION) { op.addAdditionalProperty("operations", true); } //additionally request metric metadata if (mode == D2DMode.METRICS) { op.addAdditionalProperty("include-runtime", true); } //additionally request both metric and operations metadata if (mode == D2DMode.RECURSIVE) { op.addAdditionalProperty("operations", true); op.addAdditionalProperty("include-runtime", true); } ComplexResult res = conn.executeComplex(op); if (res == null) { System.err.println("Got no result"); return; } if (!res.isSuccess()) { System.err.println("Failure: " + res.getFailureDescription()); return; } //load json object hierarchy of response Map<String, Object> resMap = res.getResult(); String what; if (mode == D2DMode.OPERATION) { what = "operations"; } else { what = "attributes"; } //Determine which attributes to focus on. Map<String, Object> attributesMap = null; //when will childtype is actually passed then... if (childType != null) { Map childMap = (Map) resMap.get("children"); Map<String, Object> typeMap = (Map<String, Object>) childMap.get(childType); if (typeMap == null) { System.err.println("No child with type '" + childType + "' found"); return; } Map descriptionMap = (Map) typeMap.get("model-description"); if (descriptionMap == null) { System.err.println("No model description found"); return; } Map starMap = (Map) descriptionMap.get("*"); if (starMap != null) { attributesMap = (Map<String, Object>) starMap.get(what); } else {//when no *map is provided check for 'classic' Map classicMap = (Map) descriptionMap.get("classic"); attributesMap = (Map<String, Object>) classicMap.get(what); }//spinder: What about 'jsapi'? This occurs on some nodes. } else {//no child type passed in just load typical map attributesMap = (Map<String, Object>) resMap.get(what); } if (mode == D2DMode.OPERATION) { //populate operations(each special map type) and sort them for ordered listing Set<String> strings = attributesMap.keySet(); String[] keys = strings.toArray(new String[strings.size()]); Arrays.sort(keys); for (String key : keys) { //exclude typical 'read-' and 'write-attribute' operations typical to all types. if (!isExcludedOperation(key)) { //for each custom operation found, retrieve child hierarchy and pass into Map<String, Object> value = (Map<String, Object>) attributesMap.get(key); createOperation(key, value); } } } else if (mode == D2DMode.RECURSIVE) {// list the child nodes and properties String legend = "Key: - property, -M metric,* req'd, + operation, [] child node."; StringBuilder tree = new StringBuilder(path + " ->\t" + legend + " \n"); if (!descriptorSegment) { System.out.print(tree); listPropertiesAndChildren(3, resMap); } else { System.out.println(generateSegment(path, 0)); listPropertiesAndChildren(3, resMap); System.out.println("</service>\n"); } } else { createProperties(mode, attributesMap, 0, false); } } finally { conn.shutdown(); } } private StringBuilder generateSegment(String path, int indent) { StringBuilder segment = new StringBuilder(); if ((path != null) && !path.trim().isEmpty()) { //strip off slashes if (path.startsWith("/")) { path = path.substring(1); } if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } //split on , and take last node String[] elements = path.split(","); String terminal = elements[elements.length - 1]; String node = terminal; StringBuilder serviceElement = generateService(node, indent, true); System.out.print(serviceElement); } return segment; } private StringBuilder generateService(String terminal, int indent, boolean isRoot) { int childIndent = indent + 3; //Determine service name String node = terminal; String[] values = null; if (isRoot) { values = terminal.split("="); node = values[1]; node = node.substring(0, 1).toUpperCase() + node.substring(1); } else {//generate more friendly service names //convert dashes to spaces node = node.replaceAll("[-]", " "); //split on space and upcase first letter String[] elements = node.split(" "); if (elements.length > 1) { String newNode = ""; for (String element : elements) { newNode += element.substring(0, 1).toUpperCase() + element.substring(1) + " "; } node = newNode.trim(); } else { node = node.substring(0, 1).toUpperCase() + node.substring(1); } } //construct node StringBuilder element = new StringBuilder(); doIndent(indent, element); element.append("<service name=\"" + node + "\"\n"); doIndent(indent + 9, element); element.append("discovery=\"SubsystemDiscovery\"\n"); doIndent(indent + 9, element); element.append("class=\"BaseComponent\">\n"); if (values != null && (values[0].equals("subsystem"))) { //runs inside element.append("\n"); doIndent(childIndent, element); element.append("<runs-inside>\n"); doIndent(childIndent + 2, element); element.append("<parent-resource-type name=\"Profile\" plugin=\"" + PLUGIN_NAME + "\"/>\n"); doIndent(childIndent + 2, element); element.append("<parent-resource-type name=\"EAP7 Standalone Server\" plugin=\"" + PLUGIN_NAME + "\"/>\n"); doIndent(childIndent, element); element.append("</runs-inside>\n"); } //plugin config element.append("\n"); doIndent(childIndent, element); element.append("<plugin-configuration>\n"); doIndent(childIndent + 2, element); element.append("<c:simple-property name=\"path\" readOnly=\"true\" default=\"" + terminal + "\"/>\n"); doIndent(childIndent, element); element.append("</plugin-configuration>\n"); return element; } private boolean isExcludedOperation(String operation) { boolean excluded = false; if (operation.startsWith("read-attribute")) { excluded = true; } else if (operation.startsWith("read-children")) { excluded = true; } else if (operation.startsWith("read-operation")) { excluded = true; } else if (operation.startsWith("read-resource")) { excluded = true; } else if (operation.equals("write-attribute")) { excluded = true; } //exclude a few more shared operations: whoami, undefine-attribute else if (operation.equals("whoami")) { excluded = true; } else if (operation.equals("undefine-attribute")) { excluded = true; } return excluded; } /** Assume parent metadata type passed in with * i)description * ii)attributes * iii)operations * iv)children * * @param indent * @param metaDataNode */ private void listPropertiesAndChildren(int indent, Map<String, Object> metaDataNode) { if (metaDataNode == null) { return; } //retrieve the operations for the node. Map<String, Object> cOperationMap = (Map<String, Object>) metaDataNode.get("operations"); if (!descriptorSegment) {//if we're attempting to generate a descriptor if (cOperationMap != null) { //retrieve keys and sort. String[] ckeys = cOperationMap.keySet().toArray(new String[cOperationMap.size()]); Arrays.sort(ckeys); for (String ckey : ckeys) {//list each of the operations. if (!isExcludedOperation(ckey)) { StringBuilder sbc = new StringBuilder(); doIndent(indent + 2, sbc); sbc.append("+ " + ckey + "{..}"); System.out.println(sbc); } } StringBuilder sbc = new StringBuilder(); doIndent(indent + 2, sbc); sbc.append("------------------"); System.out.println(sbc); } } else { //populate operations(each special map type) and sort them for ordered listing Set<String> strings = cOperationMap.keySet(); String[] keys = strings.toArray(new String[strings.size()]); Arrays.sort(keys); for (String key : keys) { //exclude typical 'read-' and 'write-attribute' operations typical to all types. if (!isExcludedOperation(key)) { //for each custom operation found, retrieve child hierarchy and pass into Map<String, Object> value = (Map<String, Object>) cOperationMap.get(key); createOperation(key, value, indent); } } } //retrieve the attributes for the node. Map<String, Object> cAttributeMap = (Map<String, Object>) metaDataNode.get("attributes"); if (!descriptorSegment) {//if we're attempting to generate a descriptor if (cAttributeMap != null) { //retrieve keys and sort. String[] ckeys = cAttributeMap.keySet().toArray(new String[cAttributeMap.size()]); Arrays.sort(ckeys); for (String ckey : ckeys) {//list each of the attributes. StringBuilder sbc = new StringBuilder(); doIndent(indent + 2, sbc); Object attribute = cAttributeMap.get(ckey); String accessType = (String) ((Map<String, Object>) attribute).get("access-type"); boolean required = isRequired(attribute); String pre = null; if (accessType.equalsIgnoreCase("metric")) { pre = "-M "; if (required) pre = "-*M"; sbc.append(pre + ckey); } else { pre = "- "; if (required) pre = "-* "; sbc.append(pre + ckey); } System.out.println(sbc); } } } else { //resource configuration props if ((cAttributeMap != null) && cAttributeMap.size() > 0) { StringBuilder resCfg = new StringBuilder(); doIndent(indent, resCfg); resCfg.append("<resource-configuration>\n"); System.out.print(resCfg); createProperties(D2DMode.PROPERTIES, cAttributeMap, indent + 2, true); resCfg = new StringBuilder(); doIndent(indent, resCfg); resCfg.append("</resource-configuration>\n"); System.out.println(resCfg); //metrics properties createProperties(D2DMode.METRICS, cAttributeMap, indent + 2, true); } } //now check for children Object childrenType = ((Map<String, Object>) metaDataNode).get("children"); if (childrenType != null) { Map<String, Object> childrenMap = (Map<String, Object>) childrenType; String[] childKeys = childrenMap.keySet().toArray(new String[childrenMap.size()]); Arrays.sort(childKeys); for (String ckey : childKeys) { StringBuilder sb2 = new StringBuilder(); doIndent(indent + 2, sb2); sb2.append("[" + ckey + "]"); if (!descriptorSegment) { System.out.println(sb2); } else { System.out.println(generateService(ckey, indent + 2, false)); } //recurse Map<String, Object> child = (Map<String, Object>) childrenMap.get(ckey); Map<String, Object> retrievedType = locateMetaDataNodeFromMap(child); listPropertiesAndChildren(indent + 4, retrievedType); StringBuilder serviceClose = new StringBuilder(); doIndent(indent + 2, serviceClose); if (descriptorSegment) { serviceClose.append("</service><!-- End of " + ckey + " service -->\n"); System.out.println(serviceClose); } } } } private boolean isRequired(Object attribute) { if (!(attribute instanceof Map)) { throw new IllegalArgumentException("Attribute object passed in cannot be null and must be of type Map."); } Object isRequired = ((Map<String, Object>) attribute).get("required"); Object nillable = ((Map<String, Object>) attribute).get("nillable"); boolean required = ((isRequired != null) && ("" + isRequired).equals("true")) || ((nillable != null) && ("" + nillable).equals("false")); return required; } private Map<String, Object> locateMetaDataNodeFromMap(Map<String, Object> child) { Map<String, Object> retrieved = null; if (child != null) { //model description Object modelDescription = child.get("model-description"); if (modelDescription != null) { //*map Object starMap = ((Map<String, Object>) modelDescription).get("*"); if (starMap != null) { retrieved = (Map<String, Object>) starMap; } else {//check for classic Object classic = ((Map<String, Object>) modelDescription).get("classic"); retrieved = (Map<String, Object>) classic; }//spinder: What about 'jsapi'? This occurs on some nodes. } } return retrieved; } private void createProperties(D2DMode mode, Map<String, Object> attributesMap, int indent, boolean simpleProperty) { if (attributesMap == null) { return; } String[] keys = attributesMap.keySet().toArray(new String[attributesMap.size()]); Arrays.sort(keys); for (String key : keys) { Object entry = attributesMap.get(key); Map<String, Object> props = (Map<String, Object>) entry; Type ptype = getTypeFromProps(props); if (ptype == Type.OBJECT && mode != D2DMode.METRICS) { StringBuilder requiredStatus = new StringBuilder(); boolean required = isRequired(props); if (required) { requiredStatus.append(" required=\"true\""); } else { requiredStatus.append(" required=\"false\""); } StringBuilder sb1 = new StringBuilder(); doIndent(indent, sb1); if (!simpleProperty) { sb1.append("<c:map-property name=\"" + key + "\"" + requiredStatus + " description=\"" + props.get("description") + "\" "); } else { sb1.append("<c:simple-property name=\"" + key + "\"" + requiredStatus + " description=\"" + props.get("description") + "\" "); } sb1.append(useAvailableOptionsList(indent, props, null)); System.out.println(sb1); Map<String, Object> attributesMap1 = (Map<String, Object>) props.get("attributes"); Map<String, Object> valueTypes = (Map<String, Object>) props.get("value-type"); if (attributesMap1 != null) { createProperties(mode, attributesMap1, indent + 4, false); } else if (valueTypes != null) { for (Map.Entry<String, Object> myEntry : valueTypes.entrySet()) { if (myEntry instanceof Map) {// only display map instances otherwise STRING is child. createSimpleProp(indent + 4, myEntry); } } } else { for (Map.Entry<String, Object> emapEntry : props.entrySet()) { String emapKey = emapEntry.getKey(); if (emapKey.equals("type") || emapKey.equals("description") || emapKey.equals("required")) { continue; } if (emapEntry.getValue() instanceof Map) { Map<String, Object> emapEntryValue = (Map<String, Object>) emapEntry.getValue(); Type ts = getTypeFromProps(emapEntryValue); StringBuilder sb = generateProperty(indent, emapEntryValue, ts, emapEntry.getKey(), getAccessType(emapEntryValue)); System.out.println(sb.toString()); } else { System.out.println(emapEntry.getValue()); } } } sb1 = new StringBuilder(); doIndent(indent, sb1); if (!simpleProperty) { sb1.append("</c:map-property>"); } System.out.println(sb1); continue; } if (ptype == Type.LIST && mode != D2DMode.METRICS) { StringBuilder sb = new StringBuilder(); doIndent(indent, sb); sb.append("<c:list-property name=\""); sb.append(key); sb.append("\""); //include required status on plugin entry boolean required = isRequired(props); if (required) { sb.append(" required=\"true\""); } else { sb.append(" required=\"false\""); } String description = (String) props.get("description"); appendDescription(sb, description, null); sb.append(" >\n"); if (!props.containsKey("attributes")) { doIndent(indent, sb); sb.append(" <c:simple-property name=\"").append(key).append("\" />\n"); } else { doIndent(indent, sb); sb.append("<c:map-property name=\"").append(key).append("\">\n"); System.out.println(sb.toString()); createProperties(mode, (Map<String, Object>) props.get("attributes"), indent + 4, false); sb = new StringBuilder(); doIndent(indent, sb); sb.append("</c:map-property>\n"); } doIndent(indent, sb); sb.append("</c:list-property>"); System.out.println(sb.toString()); continue; } String accessType = getAccessType(props); if (mode == D2DMode.METRICS) { if (ptype == Type.OBJECT) { HashMap<String, Object> myMap = (HashMap<String, Object>) props.get("value-type"); if (accessType.equals("metric")) { for (Map.Entry<String, Object> myEntry : myMap.entrySet()) { if (myEntry.getValue() instanceof String && myEntry.getValue().equals("STRING")) { createMetricEntry(indent, props, key + ":" + myEntry.getKey(), getTypeFromProps(myMap)); } else if (myEntry.getValue() instanceof Map<?, ?>) { createMetricEntry(indent, (Map<String, Object>) myEntry.getValue(), key + ":" + myEntry.getKey(), getTypeFromProps(myMap)); } } } } else { if (!accessType.equals("metric")) { continue; } createMetricEntry(indent, props, key, ptype); } } else { // configuration if (accessType.equals("metric")) { continue; } StringBuilder sb = generateProperty(indent, props, ptype, key, accessType); System.out.println(sb.toString()); } } } private boolean noMapEntriesLocated(Map<String, Object> valueTypes) { int located = 0; for (Map.Entry<String, Object> myEntry : valueTypes.entrySet()) { if (myEntry instanceof Map) {// only display map instances otherwise STRING is child. located++; } } return located > 0; } private void createMetricEntry(int indent, Map<String, Object> props, String entryName, Type ptype) { StringBuilder sb = new StringBuilder(); doIndent(indent, sb); sb.append("<metric property=\""); sb.append(entryName).append('"'); if (ptype == Type.STRING) { sb.append(" dataType=\"trait\""); } String description = (String) props.get("description"); appendDescription(sb, description, null); sb.append("/>"); System.out.println(sb.toString()); } private void createSimpleProp(int indent, Map.Entry<String, Object> emapEntry) { StringBuilder sb; if (emapEntry.getValue() instanceof Map) { Map<String, Object> emapEntryValue = (Map<String, Object>) emapEntry.getValue(); sb = generateProperty(indent, emapEntryValue, getTypeFromProps(emapEntryValue), emapEntry.getKey(), getAccessType(emapEntryValue)); } else { sb = new StringBuilder(); doIndent(indent, sb); sb.append(emapEntry.getValue().toString()); } System.out.println(sb.toString()); } private void createOperation(String name, Map<String, Object> operationMap) { createOperation(name, operationMap, 0); } /** Assumes custom operation for AS7 node. * * @param name of custom operation. * @param operationMap Json node representation of operation details as Map<String,Object>. */ private void createOperation(String name, Map<String, Object> operationMap, int indent) { if ((name == null) && (operationMap == null)) { return; } //container for flexible string concatenation and each operation StringBuilder builder = new StringBuilder(); doIndent(indent, builder); builder.append("<operation name=\""); builder.append(name).append('"'); //description attribute String description = (String) operationMap.get("description"); appendDescription(builder, description, null); //close xml tag builder.append(">\n"); doIndent(indent, builder); //detect operation parameters if present. Map<String, Object> reqMap = (Map<String, Object>) operationMap.get("request-properties"); if (reqMap != null && !reqMap.isEmpty()) {//if present build parameters segment for plugin descriptor. builder.append(" <parameters>\n"); generatePropertiesForMap(builder, reqMap, indent + 4); doIndent(indent, builder); builder.append(" </parameters>\n"); doIndent(indent, builder); } Map replyMap = (Map) operationMap.get("reply-properties"); builder.append(" <results>\n"); doIndent(indent, builder); if (replyMap != null && !replyMap.isEmpty()) { // This fools the generateProperty to write simpleProperty, otherwise we get ClassCastException replyMap.remove("value-type"); builder.append(generateProperty(indent, replyMap, Type.STRING, "operationResult", null)); } else { builder.append(" <c:simple-property name=\"operationResult\" description=\"" + description + "\" />\n"); doIndent(indent, builder); } builder.append(" </results>\n"); doIndent(indent, builder); builder.append("</operation>\n"); System.out.println(builder.toString()); } /** Builds 'description' attribute for an xml node. * * @param builder * @param description * @param defaultValueText */ private void appendDescription(StringBuilder builder, String description, String defaultValueText) { if (description != null && !description.isEmpty()) { //wrap onto a new line if (builder.length() > 120) { builder.append("\n "); } builder.append(" description=\""); //trim period off of descriptions for consistency. if (defaultValueText != null) { if (description.charAt(description.length() - 1) != '.') { description += "."; } defaultValueText = escapeHtmlCharacters(defaultValueText + ""); description = description + " " + defaultValueText; } //replace problematic strings with correct escaped xml references. description = escapeHtmlCharacters(description); builder.append(description); builder.append('"'); } } /** Escape all known problematic html characters returned to prevent * xml or html parse issues. * * Currently includes a few popular and encountered escape characters. * We may want to add them all later. * * @param description * @return */ private String escapeHtmlCharacters(String description) { description = description.replace("<", "<"); description = description.replace(">", ">"); description = description.replace("\"", "\'"); description = description.replace("'", "'"); //add a few more related to regex description = description.replace("%", "%"); description = description.replace(":", ":"); description = description.replace("[", "["); description = description.replace("]", "]"); description = description.replace("^", "^"); description = description.replace("$", "$"); description = description.replace("?", "?"); description = description.replace("+", "+"); description = description.replace("-", "-"); //TODO: spinder should we add the other escape elements as well? return description; } private void generatePropertiesForMap(StringBuilder builder, Map<String, Object> map, int indent) { for (Map.Entry<String, Object> entry : map.entrySet()) { Object o = entry.getValue(); if (o instanceof Map) {// regular json type Map<String, Object> entryValue = (Map<String, Object>) o; String entryKey = entry.getKey(); Type type = Type.STRING; if (entryValue != null) { try { type = getTypeFromProps(entryValue); } catch (Exception e) { builder.append("<!-- Type ").append(entryValue).append(" NOT FOUND!!!-->\n"); } } builder.append(generateProperty(indent, entryValue, type, entryKey, null)); builder.append('\n'); } else {//do we list this as a comment because it's an as7 invalid type? doIndent(indent, builder); builder.append("<!--").append(entry.getKey()).append("..").append(entry.getValue().toString()) .append("-->\n"); } } } private String getAccessType(Map<String, Object> props) { String accessType = (String) props.get("access-type"); if (accessType == null) { accessType = "read-only"; // default of as7 } return accessType; } private StringBuilder generateProperty(int indent, Map<String, Object> props, Type type, String entryName, String accessType) { boolean expressionsAllowed = false; Boolean tmp = (Boolean) props.get("expressions-allowed"); if (tmp != null && tmp) { expressionsAllowed = true; } StringBuilder sb = new StringBuilder(); doIndent(indent, sb); sb.append("<c:simple-property name=\""); sb.append(entryName); if (expressionsAllowed && type.isNumeric()) { sb.append(":expr"); } sb.append('"'); boolean required = isRequired(props); if (required) { sb.append(" required=\"true\""); } else { sb.append(" required=\"false\""); } sb.append(" type=\""); if (expressionsAllowed && type.isNumeric()) { sb.append("string"); } else if (type.rhqName.equalsIgnoreCase("-option-list-") || ((mode == D2DMode.OPERATION) && type.rhqName.equalsIgnoreCase("-object-"))) { sb.append("string"); } else { if (type.rhqName.equalsIgnoreCase("-object-") || type.rhqName.equalsIgnoreCase("-list-")) { sb.append("string"); } else { sb.append(type.rhqName); } } sb.append("\""); sb.append(" readOnly=\""); if (accessType != null && accessType.equals("read-only")) { sb.append("true"); } else { sb.append("false"); } sb.append('"'); Object defVal = props.get("default"); String defaultValueDescription = null; if (defVal != null) { sb.append(" defaultValue=\"").append(escapeHtmlCharacters(defVal + "")).append('\"'); defaultValueDescription = "The default value is " + escapeHtmlCharacters(defVal + "") + "."; } String description = (String) props.get("description"); appendDescription(sb, description, defaultValueDescription); //Detect whether type PROPERTY and insert known supported properties before close. if (type.rhqName.equalsIgnoreCase("-option-list-")) {//if default provided then set it and close tag sb.append(generateOptionList(indent, properties, properties[7])); } else if (((mode == D2DMode.OPERATION) || (mode == D2DMode.PROPERTIES)) && ((type.rhqName.equalsIgnoreCase("-object-")) || (type.rhqName.equalsIgnoreCase("string")))) { //detect map type if present an build map instead if ((props.get("allowed") == null) && (props.get("value-type") != null)) { //<c:map-property name="filter" description="Defines a simple filter type." > StringBuilder mb = new StringBuilder(); doIndent(indent, mb); mb.append("<c:map-property name=\""); mb.append(entryName); mb.append('"'); if (required) { mb.append(" required=\"true\""); } else { mb.append(" required=\"false\""); } appendDescription(mb, description, defaultValueDescription); mb.append(">\n"); //iterate over map children Map<String, Object> mapType = (Map<String, Object>) props.get("value-type"); if (mapType != null) { for (Map.Entry<String, Object> entry : mapType.entrySet()) { Object o = entry.getValue(); if (o instanceof String && o.equals("STRING")) { mb.append(generateProperty(indent + 4, mapType, getTypeFromProps(mapType), entry.getKey(), null)); } else if (o instanceof Map<?, ?>) { Map<String, Object> entryValue = (Map<String, Object>) o; String entryKey = entry.getKey(); Type childType = getTypeFromProps(entryValue); mb.append(generateProperty(indent + 4, entryValue, childType, entryKey, null)); mb.append("\n"); } } doIndent(indent, mb); mb.append("</c:map-property>"); return mb; } } else {//contents of allowed defines the dropdown values. sb.append(useAvailableOptionsList(indent, props, null)); } } else { //no default provided close tag. sb.append("/>"); } return sb; } /** Assumes that -object- is a json type where allowable values are defined * in the 'allowed' child. Generates the matching <c:property-options> entries. * * @param indent * @param props * @param defaultSelection * @return */ private String useAvailableOptionsList(int indent, Map<String, Object> props, String defaultSelection) { StringBuilder optionList = new StringBuilder(); //if default provided append. if ((defaultSelection != null) && (!defaultSelection.trim().isEmpty())) { defaultSelection = escapeHtmlCharacters(defaultSelection + ""); optionList.append(" defaultValue=\"" + defaultSelection + "\" "); } //see if 'allowed' is set ArrayList<String> options = (ArrayList<String>) props.get("allowed"); if (options != null && !options.isEmpty()) { Collections.sort(options); //close simple-property with children optionList.append(">\n"); doIndent(indent + 1, optionList); optionList.append("<c:property-options>\n"); for (String prop : options) { doIndent(indent + 2, optionList); optionList.append("<c:option value=\"" + prop + "\" name=\"" + prop + "\"/>\n"); } doIndent(indent + 1, optionList);//move indentation for end of property-options optionList.append("</c:property-options>\n"); doIndent(indent, optionList); optionList.append("</c:simple-property>"); } else {//no additional child elements to add optionList.append("/>\n"); } return optionList.toString(); } /** Generates hardcoded list of options not available because of JIRA * https://issues.jboss.org/browse/AS7-4384 * * @param indent * @param properties * @param defaultSelection * @return */ private String generateOptionList(int indent, String[] properties, String defaultSelection) { StringBuilder optionList = new StringBuilder(); if ((defaultSelection != null) && (!defaultSelection.trim().isEmpty())) { defaultSelection = escapeHtmlCharacters(defaultSelection + ""); optionList.append(" defaultValue=\"" + defaultSelection + "\" >\n"); } else {//no default provided optionList.append(">\n"); } doIndent(indent + 1, optionList); optionList.append("<c:property-options>\n"); //spinder 3/28/12: There is not way to query this option list and process is not used much. Hardcoding for now. //https://issues.jboss.org/browse/AS7-4384 for (String prop : properties) { doIndent(indent + 2, optionList); optionList.append("<c:option value=\"" + prop + "\" name=\"" + prop + "\"/>\n"); } doIndent(indent + 1, optionList); optionList.append("</c:property-options>\n"); doIndent(indent, optionList); optionList.append("</c:simple-property>"); return optionList.toString(); } public static String convertAs7JsonToValidJson(String forConversion) { //-String top line off //-replace all ' => ' with ':' forConversion = forConversion.replaceAll(" => ", ":"); //-replace all 'STRING' with '"STRING"' forConversion = forConversion.replaceAll("STRING", "\"STRING\""); //-replace all 'LIST' with '"LIST"' forConversion = forConversion.replaceAll("LIST", "\"LIST\""); //-replace all 'OBJECT' with '"OBJECT"' forConversion = forConversion.replaceAll("OBJECT", "\"OBJECT\""); //-replace all 'BOOLEAN' with '"BOOLEAN"' forConversion = forConversion.replaceAll("BOOLEAN", "\"BOOLEAN\""); //-replace all 'INT' with '"INT"' forConversion = forConversion.replaceAll("INT", "\"INT\""); //-replace all 'L,' with ',' forConversion = forConversion.replaceAll("L,", ","); //-- case by case as above not regex. L not terminal with , return forConversion; } private void doIndent(int indent, StringBuilder sb) { for (int i = 0; i < indent; i++) { sb.append(" "); // 2 spaces } } private Type getTypeFromProps(Map<String, Object> props) { Map<String, String> tMap = (Map<String, String>) props.get("type"); if (tMap == null) { return Type.OBJECT; } String type = tMap.get("TYPE_MODEL_VALUE"); Type ret = Type.valueOf(type); return ret; } private static void usage() { System.out.println("Domain2Properties [-U<user>:<pass>] [-p|-m|-o|-r|-rd] path type"); System.out.println(" path is of kind 'key=value[,key=value]+"); System.out.println(" -p create properties (default)"); System.out.println(" -m create metrics"); System.out.println(" -o create operations"); System.out.println(" -r recurse node and list children, properties and operations."); System.out.println(" -rd recurse node and descriptor segment."); System.out.println(" -U<user>:<pass> - supply credentials to talk to AS7"); } public enum Type { STRING(false, "string"), INT(true, "integer"), BOOLEAN(false, "boolean"), LONG(true, "long"), BIG_DECIMAL(true, "long"), OBJECT(false, "-object-"), LIST(false, "-list-"), DOUBLE(true, "long"), PROPERTY(false, "-option-list-"); private boolean numeric; private String rhqName; private Type(boolean numeric, String rhqName) { this.numeric = numeric; this.rhqName = rhqName; } public boolean isNumeric() { return numeric; } } private enum D2DMode { METRICS, PROPERTIES, OPERATION, RECURSIVE } }