/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.management.internal.cli.parser.preprocessor; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.geode.internal.lang.SystemUtils; import org.apache.geode.management.internal.cli.parser.SyntaxConstants; /** * The methods in this class will be used by the {@link Preprocessor} class to perform various * trivial operations * * @since GemFire 7.0 */ public class PreprocessorUtils { public static TrimmedInput simpleTrim(String input) { if (input != null) { // First remove the trailing white spaces, we do not need those if (!containsOnlyWhiteSpaces(input)) { input = StringUtils.stripEnd(input, null); } String output = input.trim(); return new TrimmedInput(output, input.length() - output.length()); } else { return null; } } /** * * This function will trim the given input string. It will not only remove the spaces and tabs at * the end but also compress multiple spaces and tabs to a single space * * @param input The input string on which the trim operation needs to be performed * @return String */ public static TrimmedInput trim(final String input) { return trim(input, true); } /** * * This function will trim the given input string. It will not only remove the spaces and tabs at * the end but also compress multiple spaces and tabs to a single space * * @param input The input string on which the trim operation needs to be performed * @param retainLineSeparator whether to retain the line separator. * * @return String */ public static TrimmedInput trim(final String input, final boolean retainLineSeparator) { if (input != null) { String inputCopy = input; StringBuffer output = new StringBuffer(); // First remove the trailing white spaces, we do not need those inputCopy = StringUtils.stripEnd(inputCopy, null); // As this parser is for optionParsing, we also need to remove // the trailing optionSpecifiers provided it has previous // options. Remove the trailing LONG_OPTION_SPECIFIERs // in a loop. It is necessary to check for previous options for // the case of non-mandatory arguments. // "^(.*)(\\s-+)$" - something that ends with a space followed by a series of hyphens. while (Pattern.matches("^(.*)(\\s-+)$", inputCopy)) { inputCopy = StringUtils.removeEnd(inputCopy, SyntaxConstants.SHORT_OPTION_SPECIFIER); // Again we need to trim the trailing white spaces // As we are in a loop inputCopy = StringUtils.stripEnd(inputCopy, null); } // Here we made use of the String class function trim to remove the // space and tabs if any at the // beginning and the end of the string int noOfSpacesRemoved = 0; { int length = inputCopy.length(); inputCopy = inputCopy.trim(); noOfSpacesRemoved += length - inputCopy.length(); } // Now we need to compress the multiple spaces and tabs to single space // and tabs but we also need to ignore the white spaces inside the // quotes and parentheses StringBuffer buffer = new StringBuffer(); boolean startWhiteSpace = false; for (int i = 0; i < inputCopy.length(); i++) { char ch = inputCopy.charAt(i); buffer.append(ch); if (PreprocessorUtils.isWhitespace(ch)) { if (PreprocessorUtils.isSyntaxValid(buffer.toString())) { if (startWhiteSpace) { noOfSpacesRemoved++; } else { startWhiteSpace = true; if (ch == '\n') { if (retainLineSeparator) { output.append("\n"); } } else { output.append(" "); } } buffer.delete(0, buffer.length()); } else { output.append(ch); } } else { startWhiteSpace = false; output.append(ch); } } return new TrimmedInput(output.toString(), noOfSpacesRemoved); } else { return null; } } /** * This function just does the simple job of removing white spaces from the given input string * * @param input The input String from which the spaces need to be removed * @return String */ public static String removeWhiteSpaces(String input) { if (input != null) { input = trim(input).getString(); StringBuffer output = new StringBuffer(); for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); if (PreprocessorUtils.isWhitespace(ch)) { continue; } else { output.append(ch); } } return output.toString(); } else { return null; } } /** * * This function will check for the validity of the input provided. * * For e.g; '" input"' is valid but '" input' is not a valid input same is the case with input * like a JSON string * * @param input The input string which needs to be checked for proper syntax * @return Boolean */ public static Boolean isSyntaxValid(String input) { if (input != null) { // We will need two different stacks one for double quotation // and the other one for checking brackets Stack<Character> stack = new Stack<Character>(); if (input.length() > 0) { for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); if ('\\' == ch) { // It means that this is an escape sequence // So skip the next character as well i++; continue; } if (isValueEnclosingChar(ch)) { // First check whether the enclosing character // is a double quotation. if (EnclosingCharacters.DOUBLE_QUOTATION == ch) { Character popped = stack.pop(); if (popped == EnclosingCharacters.DOUBLE_QUOTATION) { // Everything is normal } else { // We just push both the characters onto the stack if (popped != null) { stack.push(popped); } stack.push(ch); } } else if (EnclosingCharacters.SINGLE_QUOTATION == ch) { Character popped = stack.pop(); if (popped == EnclosingCharacters.SINGLE_QUOTATION) { // Everything is normal } else { // We just push both the characters onto the stack if (popped != null) { stack.push(popped); } stack.push(ch); } } else { if (isOpeningBracket(ch)) { // If this a opening bracket then just push it onto // the stack stack.push(ch); } else { // This means that it is a closing bracket. // Now pop a character form the stack and check // whether both // the brackets match each other Character popped = stack.pop(); if (matches(popped, ch)) { // Everything is normal } else { return false; } } } } } } if (stack.isEmpty()) { return true; } else { return false; } } else { return false; } } private static boolean matches(Character popped, char ch) { if (popped != null) { outer: { if (isOpeningBracket(popped)) { if (EnclosingCharacters.OPENING_SQUARE_BRACKET == popped) { if (EnclosingCharacters.CLOSING_SQUARE_BRACKET == ch) { return true; } else { break outer; } } if (EnclosingCharacters.OPENING_CIRCULAR_BRACKET == popped) { if (EnclosingCharacters.CLOSING_CIRCULAR_BRACKET == ch) { return true; } else { break outer; } } if (EnclosingCharacters.OPENING_CURLY_BRACE == popped) { if (EnclosingCharacters.CLOSING_CURLY_BRACE == ch) { return true; } else { break outer; } } } } return false; } else { return false; } } // Not used at present @SuppressWarnings("unused") private static boolean isClosingBracket(char ch) { if (EnclosingCharacters.CLOSING_SQUARE_BRACKET == ch || EnclosingCharacters.CLOSING_CIRCULAR_BRACKET == ch || EnclosingCharacters.CLOSING_CURLY_BRACE == ch) { return true; } else { return false; } } private static boolean isOpeningBracket(char ch) { if (EnclosingCharacters.OPENING_SQUARE_BRACKET == ch || EnclosingCharacters.OPENING_CIRCULAR_BRACKET == ch || EnclosingCharacters.OPENING_CURLY_BRACE == ch) { return true; } else { return false; } } private static boolean isValueEnclosingChar(char ch) { if (EnclosingCharacters.OPENING_SQUARE_BRACKET == ch || EnclosingCharacters.CLOSING_SQUARE_BRACKET == ch || EnclosingCharacters.OPENING_CIRCULAR_BRACKET == ch || EnclosingCharacters.CLOSING_CIRCULAR_BRACKET == ch || EnclosingCharacters.OPENING_CURLY_BRACE == ch || EnclosingCharacters.CLOSING_CURLY_BRACE == ch || EnclosingCharacters.DOUBLE_QUOTATION == ch || EnclosingCharacters.SINGLE_QUOTATION == ch) { return true; } return false; } public static boolean containsOnlyWhiteSpaces(String input) { if (input != null) { for (int i = 0; i < input.length(); i++) { if (!PreprocessorUtils.isWhitespace(input.charAt(i))) { return false; } } return true; } else { return false; } } public static boolean isWhitespace(char ch) { if (ch == ' ' || ch == '\t' || ch == '\n' || (ch == '\r' && SystemUtils.isWindows())) { return true; } return false; } }