This is an automated email from the ASF dual-hosted git repository. pradeep pushed a commit to branch RANGER-5027_master in repository https://gitbox.apache.org/repos/asf/ranger.git
commit d1d30f19a01dcd171ed43c8196ac88fcbcfba85c Author: Pradeep AgrawaL <[email protected]> AuthorDate: Mon Dec 16 16:38:56 2024 +0530 RANGER-5027: agents-installer module: update for code readability improvement --- agents-installer/pom.xml | 5 + .../ranger/utils/install/XmlConfigChanger.java | 895 ++++++++++----------- 2 files changed, 432 insertions(+), 468 deletions(-) diff --git a/agents-installer/pom.xml b/agents-installer/pom.xml index 6d80eff3f..89ac6e260 100644 --- a/agents-installer/pom.xml +++ b/agents-installer/pom.xml @@ -27,6 +27,11 @@ <packaging>jar</packaging> <name>Installer Support Component</name> <description>Security Plugins Installer</description> + <properties> + <checkstyle.failOnViolation>true</checkstyle.failOnViolation> + <checkstyle.skip>false</checkstyle.skip> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> <dependencies> <dependency> <groupId>commons-cli</groupId> diff --git a/agents-installer/src/main/java/org/apache/ranger/utils/install/XmlConfigChanger.java b/agents-installer/src/main/java/org/apache/ranger/utils/install/XmlConfigChanger.java index 270e52181..28113cd77 100644 --- a/agents-installer/src/main/java/org/apache/ranger/utils/install/XmlConfigChanger.java +++ b/agents-installer/src/main/java/org/apache/ranger/utils/install/XmlConfigChanger.java @@ -17,26 +17,7 @@ * under the License. */ - package org.apache.ranger.utils.install; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.util.Properties; - -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; +package org.apache.ranger.utils.install; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; @@ -52,454 +33,432 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -public class XmlConfigChanger { +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; - private static final String EMPTY_TOKEN = "%EMPTY%"; - private static final String EMPTY_TOKEN_VALUE = ""; - - public static final String ROOT_NODE_NAME = "configuration"; - public static final String NAME_NODE_NAME = "name"; - public static final String PROPERTY_NODE_NAME = "property"; - public static final String VALUE_NODE_NAME = "value"; - - private File inpFile; - private File outFile; - private File confFile; - private File propFile; - - private Document doc; - Properties installProperties = new Properties(); - - public static void main(String[] args) { - XmlConfigChanger xmlConfigChanger = new XmlConfigChanger(); - xmlConfigChanger.parseConfig(args); - try { - xmlConfigChanger.run(); - } - catch(Throwable t) { - System.err.println("*************************************************************************"); - System.err.println("******* ERROR: unable to process xml configuration changes due to error:" + t.getMessage()); - t.printStackTrace(); - System.err.println("*************************************************************************"); - System.exit(1); - } - } - - @SuppressWarnings("static-access") - public void parseConfig(String[] args) { - - - Options options = new Options(); - - Option inputOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("input").withDescription("Input xml file name").create('i'); - options.addOption(inputOption); - - Option outputOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("output").withDescription("Output xml file name").create('o'); - options.addOption(outputOption); - - Option configOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("config").withDescription("Config file name").create('c'); - options.addOption(configOption); - - Option installPropOption = OptionBuilder.hasArgs(1).isRequired(false).withLongOpt("installprop").withDescription("install.properties").create('p'); - options.addOption(installPropOption); - - CommandLineParser parser = new BasicParser(); - CommandLine cmd = null; - try { - cmd = parser.parse(options, args); - } catch (ParseException e) { - String header = "ERROR: " + e; - HelpFormatter helpFormatter = new HelpFormatter(); - helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); - throw new RuntimeException(e); - } - - String inputFileName = cmd.getOptionValue('i'); - this.inpFile = new File(inputFileName); - if (! this.inpFile.canRead()) { - String header = "ERROR: Input file [" + this.inpFile.getAbsolutePath() + "] can not be read."; - HelpFormatter helpFormatter = new HelpFormatter(); - helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); - throw new RuntimeException(header); - } - - String outputFileName = cmd.getOptionValue('o'); - this.outFile = new File(outputFileName); - if (this.outFile.exists()) { - String header = "ERROR: Output file [" + this.outFile.getAbsolutePath() + "] already exists. Specify a filepath for creating new output file for the input [" + this.inpFile.getAbsolutePath() + "]"; - HelpFormatter helpFormatter = new HelpFormatter(); - helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); - throw new RuntimeException(header); - } - - String configFileName = cmd.getOptionValue('c'); - this.confFile = new File(configFileName); - if (! this.confFile.canRead()) { - String header = "ERROR: Config file [" + this.confFile.getAbsolutePath() + "] can not be read."; - HelpFormatter helpFormatter = new HelpFormatter(); - helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); - throw new RuntimeException(header); - } - - String installPropFileName = (cmd.hasOption('p') ? cmd.getOptionValue('p') : null ); - if (installPropFileName != null) { - this.propFile = new File(installPropFileName); - if (! this.propFile.canRead()) { - String header = "ERROR: Install Property file [" + this.propFile.getAbsolutePath() + "] can not be read."; - HelpFormatter helpFormatter = new HelpFormatter(); - helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); - throw new RuntimeException(header); - } - } - - } - - public void run() throws ParserConfigurationException, SAXException, IOException, TransformerException { - loadInstallProperties(); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - DocumentBuilder builder = factory.newDocumentBuilder(); - doc = builder.parse(inpFile); - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(confFile)); - - String line = null; - - @SuppressWarnings("unused") - int lineNo = 0; - Properties variables = new Properties(); - while ((line = reader.readLine()) != null) { - lineNo++; - line = line.trim(); - if (line.isEmpty() ) - continue; - if (line.startsWith("#")) { - continue; - } - if (line.contains("#")) { - int len = line.indexOf("#"); - line = line.substring(0,len); - } - String[] tokens = line.split("\\s+"); - String propName = tokens[0]; - String propValue = null; - try { - if (propnameContainsVariables(propName)) { - propName = replaceProp(propName, variables); - } - propValue = replaceProp(tokens[1],installProperties); - } catch (ValidationException e) { - // throw new RuntimeException("Unable to replace tokens in the line: \n[" + line + "]\n in file [" + confFile.getAbsolutePath() + "] line number:[" + lineNo + "]" ); - throw new RuntimeException(e); - } - - String actionType = tokens[2]; - String options = (tokens.length > 3 ? tokens[3] : null); - boolean createIfNotExists = (options != null && options.contains("create-if-not-exists")); - - - if ("add".equals(actionType)) { - addProperty(propName, propValue); - } - else if ("mod".equals(actionType)) { - modProperty(propName, propValue,createIfNotExists); - } - else if ("del".equals(actionType)) { - delProperty(propName); - } - else if ("append".equals(actionType)) { - String curVal = getProperty(propName); - if (curVal == null) { - if (createIfNotExists) { - addProperty(propName, propValue); - } - } - else { - String appendDelimitor = (tokens.length > 4 ? tokens[4] : " "); - if (! curVal.contains(propValue)) { - String newVal = null; - if (curVal.length() == 0) { - newVal = propValue; - } - else { - newVal = curVal + appendDelimitor + propValue; - } - modProperty(propName, newVal,createIfNotExists); - } - } - } - else if ("delval".equals(actionType)) { - String curVal = getProperty(propName); - if (curVal != null) { - String appendDelimitor = (tokens.length > 4 ? tokens[4] : " "); - if (curVal.contains(propValue)) { - String[] valTokens = curVal.split(appendDelimitor); - StringBuilder sb = new StringBuilder(); - for(String v : valTokens) { - if (! v.equals(propValue)) { - if (sb.length() > 0) { - sb.append(appendDelimitor); - } - sb.append(v); - } - } - String newVal = sb.toString(); - modProperty(propName, newVal,createIfNotExists); - } - } - } - else if ("var".equals(actionType)) { - variables.put(propName, propValue); - } - else { - throw new RuntimeException("Unknown Command Found: [" + actionType + "], Supported Types: add modify del append"); - } - - } - - TransformerFactory tfactory = TransformerFactory.newInstance(); - tfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); - Transformer transformer = tfactory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - - DOMSource source = new DOMSource(doc); - FileOutputStream out = new FileOutputStream(outFile); - StreamResult result = new StreamResult(out); - transformer.transform(source, result); - out.close(); - - } - finally { - if (reader != null) { - reader.close(); - } - } - - } - - /** - * Check if prop name contains a substitution variable embedded in it, e.g. %VAR_NAME%. - * @param propName - * @return true if propname contains at least 2 '%' characters in it, else false - */ - private boolean propnameContainsVariables(String propName) { - - if (propName != null) { - int first = propName.indexOf('%'); - if (first != -1) { - // indexof is safe even if 2nd argument is beyond size of string, i.e. if 1st percent was the last character of the string. - int second = propName.indexOf('%', first + 1); - if (second != -1) { - return true; - } - } - } - return false; - } - - - private void addProperty(String propName, String val) { - NodeList nl = doc.getElementsByTagName(ROOT_NODE_NAME); - Node rootConfig = nl.item(0); - rootConfig.appendChild(createNewElement(propName,val)); - } - - private void modProperty(String propName, String val, boolean createIfNotExists) { - Node node = findProperty(propName); - if (node != null) { - NodeList cnl = node.getChildNodes(); - for (int j = 0; j < cnl.getLength() ; j++) { - String nodeName = cnl.item(j).getNodeName(); - if (nodeName.equals(VALUE_NODE_NAME)) { - if (cnl.item(j).hasChildNodes()) { - cnl.item(j).getChildNodes().item(0).setNodeValue(val); - } - else { - Node propValueNode = cnl.item(j); - Node txtNode = doc.createTextNode(val); - propValueNode.appendChild(txtNode); - txtNode.setNodeValue(val); - } - return; - } - } - } - if (createIfNotExists) { - addProperty(propName, val); - } - } - - private String getProperty(String propName) { - String ret = null; - try { - Node node = findProperty(propName); - if (node != null) { - NodeList cnl = node.getChildNodes(); - for (int j = 0; j < cnl.getLength() ; j++) { - String nodeName = cnl.item(j).getNodeName(); - if (nodeName.equals(VALUE_NODE_NAME)) { - Node valueNode = null; - if (cnl.item(j).hasChildNodes()) { - valueNode = cnl.item(j).getChildNodes().item(0); - } - if (valueNode == null) { // Value Node is defined with - ret = ""; - } - else { - ret = valueNode.getNodeValue(); - } - break; - } - } - } - } - catch(Throwable t) { - throw new RuntimeException("getProperty(" + propName + ") failed.", t); - } - return ret; - } - - - private void delProperty(String propName) { - Node node = findProperty(propName); - if (node != null) { - node.getParentNode().removeChild(node); - } - } - - - private Node findProperty(String propName) { - Node ret = null; - try { - NodeList nl = doc.getElementsByTagName(PROPERTY_NODE_NAME); - - for(int i = 0; i < nl.getLength() ; i++) { - NodeList cnl = nl.item(i).getChildNodes(); - boolean found = false; - for (int j = 0; j < cnl.getLength() ; j++) { - String nodeName = cnl.item(j).getNodeName(); - if (nodeName.equals(NAME_NODE_NAME)) { - String pName = cnl.item(j).getChildNodes().item(0).getNodeValue(); - found = pName.equals(propName); - if (found) - break; - } - } - if (found) { - ret = nl.item(i); - break; - } - } - } - catch(Throwable t) { - throw new RuntimeException("findProperty(" + propName + ") failed.", t); - } - return ret; - } - - - private Element createNewElement(String propName, String val) { - Element ret = null; - - try { - if (doc != null) { - ret = doc.createElement(PROPERTY_NODE_NAME); - Node propNameNode = doc.createElement(NAME_NODE_NAME); - Node txtNode = doc.createTextNode(propName); - propNameNode.appendChild(txtNode); - propNameNode.setNodeValue(propName); - ret.appendChild(propNameNode); - - Node propValueNode = doc.createElement(VALUE_NODE_NAME); - txtNode = doc.createTextNode(val); - propValueNode.appendChild(txtNode); - propValueNode.setNodeValue(propName); - ret.appendChild(propValueNode); - } - } - catch(Throwable t) { - throw new RuntimeException("createNewElement(" + propName + ") with value [" + val + "] failed.", t); - } - - return ret; - } - - private void loadInstallProperties() { - if (propFile != null) { - try (FileInputStream in = new FileInputStream(propFile)) { - installProperties.load(in); - } catch (IOException ioe) { - System.err.println("******* ERROR: load file failure. The reason: " + ioe.getMessage()); - ioe.printStackTrace(); - } - } - // To support environment variable, we will add all environment variables to the Properties - installProperties.putAll(System.getenv()); - } - - private String replaceProp(String propValue, Properties prop) throws ValidationException { - - StringBuilder tokensb = new StringBuilder(); - StringBuilder retsb = new StringBuilder(); - boolean isToken = false; - - for(char c : propValue.toCharArray()) { - if (c == '%') { - if (isToken) { - String token = tokensb.toString(); - String tokenValue = (token.length() == 0 ? "%" : prop.getProperty(token) ); - if (tokenValue == null || tokenValue.trim().isEmpty()) { - throw new ValidationException("ERROR: configuration token [" + token + "] is not defined in the file: [" + (propFile != null ? propFile.getAbsolutePath() : "{no install.properties file specified using -p option}") + "]"); - } - else { - if (EMPTY_TOKEN.equals(tokenValue)) { - retsb.append(EMPTY_TOKEN_VALUE); - } - else { - retsb.append(tokenValue); - } - } - isToken = false; - } - else { - isToken = true; - tokensb.setLength(0); - } - } - else if (isToken) { - tokensb.append(String.valueOf(c)); - } - else { - retsb.append(String.valueOf(c)); - } - } - - if (isToken) { - throw new ValidationException("ERROR: configuration has a token defined without end-token [" + propValue + "] in the file: [" + (propFile != null ? propFile.getAbsolutePath() : "{no install.properties file specified using -p option}") + "]"); - } - - return retsb.toString(); - } - - - @SuppressWarnings("serial") - class ValidationException extends Exception { - - public ValidationException(String msg) { - super(msg); - } - - public ValidationException(Throwable cause) { - super(cause); - } - - } - +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; +public class XmlConfigChanger { + public static final String ROOT_NODE_NAME = "configuration"; + public static final String NAME_NODE_NAME = "name"; + public static final String PROPERTY_NODE_NAME = "property"; + public static final String VALUE_NODE_NAME = "value"; + private static final String EMPTY_TOKEN = "%EMPTY%"; + private static final String EMPTY_TOKEN_VALUE = ""; + Properties installProperties = new Properties(); + private File inpFile; + private File outFile; + private File confFile; + private File propFile; + private Document doc; + + public static void main(String[] args) { + XmlConfigChanger xmlConfigChanger = new XmlConfigChanger(); + xmlConfigChanger.parseConfig(args); + try { + xmlConfigChanger.run(); + } catch (Throwable t) { + System.err.println("*************************************************************************"); + System.err.println("******* ERROR: unable to process xml configuration changes due to error:" + t.getMessage()); + t.printStackTrace(); + System.err.println("*************************************************************************"); + System.exit(1); + } + } + + @SuppressWarnings("static-access") + public void parseConfig(String[] args) { + Options options = new Options(); + + Option inputOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("input").withDescription("Input xml file name").create('i'); + options.addOption(inputOption); + + Option outputOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("output").withDescription("Output xml file name").create('o'); + options.addOption(outputOption); + + Option configOption = OptionBuilder.hasArgs(1).isRequired().withLongOpt("config").withDescription("Config file name").create('c'); + options.addOption(configOption); + + Option installPropOption = OptionBuilder.hasArgs(1).isRequired(false).withLongOpt("installprop").withDescription("install.properties").create('p'); + options.addOption(installPropOption); + + CommandLineParser parser = new BasicParser(); + CommandLine cmd = null; + try { + cmd = parser.parse(options, args); + } catch (ParseException e) { + String header = "ERROR: " + e; + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); + throw new RuntimeException(e); + } + + String inputFileName = cmd.getOptionValue('i'); + this.inpFile = new File(inputFileName); + if (!this.inpFile.canRead()) { + String header = "ERROR: Input file [" + this.inpFile.getAbsolutePath() + "] can not be read."; + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); + throw new RuntimeException(header); + } + + String outputFileName = cmd.getOptionValue('o'); + this.outFile = new File(outputFileName); + if (this.outFile.exists()) { + String header = "ERROR: Output file [" + this.outFile.getAbsolutePath() + "] already exists. Specify a filepath for creating new output file for the input [" + this.inpFile.getAbsolutePath() + "]"; + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); + throw new RuntimeException(header); + } + + String configFileName = cmd.getOptionValue('c'); + this.confFile = new File(configFileName); + if (!this.confFile.canRead()) { + String header = "ERROR: Config file [" + this.confFile.getAbsolutePath() + "] can not be read."; + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); + throw new RuntimeException(header); + } + + String installPropFileName = (cmd.hasOption('p') ? cmd.getOptionValue('p') : null); + if (installPropFileName != null) { + this.propFile = new File(installPropFileName); + if (!this.propFile.canRead()) { + String header = "ERROR: Install Property file [" + this.propFile.getAbsolutePath() + "] can not be read."; + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp("java " + XmlConfigChanger.class.getName(), header, options, null, true); + throw new RuntimeException(header); + } + } + } + + public void run() throws ParserConfigurationException, SAXException, IOException, TransformerException { + loadInstallProperties(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + DocumentBuilder builder = factory.newDocumentBuilder(); + doc = builder.parse(inpFile); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(confFile)); + + String line = null; + + @SuppressWarnings("unused") + int lineNo = 0; + Properties variables = new Properties(); + while ((line = reader.readLine()) != null) { + lineNo++; + line = line.trim(); + if (line.isEmpty()) { + continue; + } + if (line.startsWith("#")) { + continue; + } + if (line.contains("#")) { + int len = line.indexOf("#"); + line = line.substring(0, len); + } + String[] tokens = line.split("\\s+"); + String propName = tokens[0]; + String propValue = null; + try { + if (propnameContainsVariables(propName)) { + propName = replaceProp(propName, variables); + } + propValue = replaceProp(tokens[1], installProperties); + } catch (ValidationException e) { + throw new RuntimeException(e); + } + + String actionType = tokens[2]; + String options = (tokens.length > 3 ? tokens[3] : null); + boolean createIfNotExists = (options != null && options.contains("create-if-not-exists")); + + if ("add".equals(actionType)) { + addProperty(propName, propValue); + } else if ("mod".equals(actionType)) { + modProperty(propName, propValue, createIfNotExists); + } else if ("del".equals(actionType)) { + delProperty(propName); + } else if ("append".equals(actionType)) { + String curVal = getProperty(propName); + if (curVal == null) { + if (createIfNotExists) { + addProperty(propName, propValue); + } + } else { + String appendDelimitor = (tokens.length > 4 ? tokens[4] : " "); + if (!curVal.contains(propValue)) { + String newVal = null; + if (curVal.length() == 0) { + newVal = propValue; + } else { + newVal = curVal + appendDelimitor + propValue; + } + modProperty(propName, newVal, createIfNotExists); + } + } + } else if ("delval".equals(actionType)) { + String curVal = getProperty(propName); + if (curVal != null) { + String appendDelimitor = (tokens.length > 4 ? tokens[4] : " "); + if (curVal.contains(propValue)) { + String[] valTokens = curVal.split(appendDelimitor); + StringBuilder sb = new StringBuilder(); + for (String v : valTokens) { + if (!v.equals(propValue)) { + if (sb.length() > 0) { + sb.append(appendDelimitor); + } + sb.append(v); + } + } + String newVal = sb.toString(); + modProperty(propName, newVal, createIfNotExists); + } + } + } else if ("var".equals(actionType)) { + variables.put(propName, propValue); + } else { + throw new RuntimeException("Unknown Command Found: [" + actionType + "], Supported Types: add modify del append"); + } + } + + TransformerFactory tfactory = TransformerFactory.newInstance(); + tfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); + Transformer transformer = tfactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); + + DOMSource source = new DOMSource(doc); + FileOutputStream out = new FileOutputStream(outFile); + StreamResult result = new StreamResult(out); + transformer.transform(source, result); + out.close(); + } finally { + if (reader != null) { + reader.close(); + } + } + } + + /** + * Check if prop name contains a substitution variable embedded in it, e.g. %VAR_NAME%. + * + * @param propName + * @return true if propname contains at least 2 '%' characters in it, else false + */ + private boolean propnameContainsVariables(String propName) { + if (propName != null) { + int first = propName.indexOf('%'); + if (first != -1) { + // indexof is safe even if 2nd argument is beyond size of string, i.e. if 1st percent was the last character of the string. + int second = propName.indexOf('%', first + 1); + if (second != -1) { + return true; + } + } + } + return false; + } + + private void addProperty(String propName, String val) { + NodeList nl = doc.getElementsByTagName(ROOT_NODE_NAME); + Node rootConfig = nl.item(0); + rootConfig.appendChild(createNewElement(propName, val)); + } + + private void modProperty(String propName, String val, boolean createIfNotExists) { + Node node = findProperty(propName); + if (node != null) { + NodeList cnl = node.getChildNodes(); + for (int j = 0; j < cnl.getLength(); j++) { + String nodeName = cnl.item(j).getNodeName(); + if (nodeName.equals(VALUE_NODE_NAME)) { + if (cnl.item(j).hasChildNodes()) { + cnl.item(j).getChildNodes().item(0).setNodeValue(val); + } else { + Node propValueNode = cnl.item(j); + Node txtNode = doc.createTextNode(val); + propValueNode.appendChild(txtNode); + txtNode.setNodeValue(val); + } + return; + } + } + } + if (createIfNotExists) { + addProperty(propName, val); + } + } + + private String getProperty(String propName) { + String ret = null; + try { + Node node = findProperty(propName); + if (node != null) { + NodeList cnl = node.getChildNodes(); + for (int j = 0; j < cnl.getLength(); j++) { + String nodeName = cnl.item(j).getNodeName(); + if (nodeName.equals(VALUE_NODE_NAME)) { + Node valueNode = null; + if (cnl.item(j).hasChildNodes()) { + valueNode = cnl.item(j).getChildNodes().item(0); + } + if (valueNode == null) { // Value Node is defined with + ret = ""; + } else { + ret = valueNode.getNodeValue(); + } + break; + } + } + } + } catch (Throwable t) { + throw new RuntimeException("getProperty(" + propName + ") failed.", t); + } + return ret; + } + + private void delProperty(String propName) { + Node node = findProperty(propName); + if (node != null) { + node.getParentNode().removeChild(node); + } + } + + private Node findProperty(String propName) { + Node ret = null; + try { + NodeList nl = doc.getElementsByTagName(PROPERTY_NODE_NAME); + + for (int i = 0; i < nl.getLength(); i++) { + NodeList cnl = nl.item(i).getChildNodes(); + boolean found = false; + for (int j = 0; j < cnl.getLength(); j++) { + String nodeName = cnl.item(j).getNodeName(); + if (nodeName.equals(NAME_NODE_NAME)) { + String pName = cnl.item(j).getChildNodes().item(0).getNodeValue(); + found = pName.equals(propName); + if (found) { + break; + } + } + } + if (found) { + ret = nl.item(i); + break; + } + } + } catch (Throwable t) { + throw new RuntimeException("findProperty(" + propName + ") failed.", t); + } + return ret; + } + + private Element createNewElement(String propName, String val) { + Element ret = null; + + try { + if (doc != null) { + ret = doc.createElement(PROPERTY_NODE_NAME); + Node propNameNode = doc.createElement(NAME_NODE_NAME); + Node txtNode = doc.createTextNode(propName); + propNameNode.appendChild(txtNode); + propNameNode.setNodeValue(propName); + ret.appendChild(propNameNode); + + Node propValueNode = doc.createElement(VALUE_NODE_NAME); + txtNode = doc.createTextNode(val); + propValueNode.appendChild(txtNode); + propValueNode.setNodeValue(propName); + ret.appendChild(propValueNode); + } + } catch (Throwable t) { + throw new RuntimeException("createNewElement(" + propName + ") with value [" + val + "] failed.", t); + } + + return ret; + } + + private void loadInstallProperties() { + if (propFile != null) { + try (FileInputStream in = new FileInputStream(propFile)) { + installProperties.load(in); + } catch (IOException ioe) { + System.err.println("******* ERROR: load file failure. The reason: " + ioe.getMessage()); + ioe.printStackTrace(); + } + } + // To support environment variable, we will add all environment variables to the Properties + installProperties.putAll(System.getenv()); + } + + private String replaceProp(String propValue, Properties prop) throws ValidationException { + StringBuilder tokensb = new StringBuilder(); + StringBuilder retsb = new StringBuilder(); + boolean isToken = false; + + for (char c : propValue.toCharArray()) { + if (c == '%') { + if (isToken) { + String token = tokensb.toString(); + String tokenValue = (token.length() == 0 ? "%" : prop.getProperty(token)); + if (tokenValue == null || tokenValue.trim().isEmpty()) { + throw new ValidationException("ERROR: configuration token [" + token + "] is not defined in the file: [" + (propFile != null ? propFile.getAbsolutePath() : "{no install.properties file specified using -p option}") + "]"); + } else { + if (EMPTY_TOKEN.equals(tokenValue)) { + retsb.append(EMPTY_TOKEN_VALUE); + } else { + retsb.append(tokenValue); + } + } + isToken = false; + } else { + isToken = true; + tokensb.setLength(0); + } + } else if (isToken) { + tokensb.append(String.valueOf(c)); + } else { + retsb.append(String.valueOf(c)); + } + } + + if (isToken) { + throw new ValidationException("ERROR: configuration has a token defined without end-token [" + propValue + "] in the file: [" + (propFile != null ? propFile.getAbsolutePath() : "{no install.properties file specified using -p option}") + "]"); + } + + return retsb.toString(); + } + + class ValidationException extends Exception { + public ValidationException(String msg) { + super(msg); + } + + public ValidationException(Throwable cause) { + super(cause); + } + } }
