001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.exec.impl;
018
019 import java.util.ArrayList;
020 import java.util.List;
021 import java.util.StringTokenizer;
022
023 /**
024 * Utility class for parsing, used by the Camel Exec component.<br>
025 * Note: the class should be dropped, when the the commons-exec library
026 * implements similar functionality.
027 */
028 public final class ExecParseUtils {
029
030 public static final String WHITESPACE = " ";
031
032 public static final String QUOTE_CHAR = "\"";
033
034 private ExecParseUtils() {
035 }
036
037 /**
038 * Splits the input line string by {@link #WHITESPACE}. Supports quoting the
039 * white-spaces with a {@link #QUOTE_CHAR}. A quote itself can also be
040 * enclosed within #{@link #QUOTE_CHAR}#{@link #QUOTE_CHAR}. More than two
041 * double-quotes in a sequence is not allowed. Nested quotes are not
042 * allowed.<br>
043 * E.g. The string
044 * <code>"arg 1" arg2<code> will return the tokens <code>arg 1</code>,
045 * <code>arg2</code><br>
046 * The string
047 * <code>""arg 1"" "arg2" arg 3<code> will return the tokens <code>"arg 1"</code>
048 * , <code>arg2</code>,<code>arg</code> and <code>3</code> <br>
049 *
050 * @param input the input to split.
051 * @return a not-null list of tokens
052 */
053 public static List<String> splitToWhiteSpaceSeparatedTokens(String input) {
054 if (input == null) {
055 return new ArrayList<String>();
056 }
057 StringTokenizer tokenizer = new StringTokenizer(input.trim(), QUOTE_CHAR + WHITESPACE, true);
058 List<String> tokens = new ArrayList<String>();
059
060 StringBuilder quotedText = new StringBuilder();
061
062 while (tokenizer.hasMoreTokens()) {
063 String token = tokenizer.nextToken();
064 if (QUOTE_CHAR.equals(token)) {
065 // if we have a quote, add the next tokens to the quoted text
066 // until the quoting has finished
067 quotedText.append(QUOTE_CHAR);
068 String buffer = quotedText.toString();
069 if (isSingleQuoted(buffer) || isDoubleQuoted(buffer)) {
070 tokens.add(buffer.substring(1, buffer.length() - 1));
071 quotedText = new StringBuilder();
072 }
073 } else if (WHITESPACE.equals(token)) {
074 // a white space, if in quote, add the white space, otherwise
075 // skip it
076 if (quotedText.length() > 0) {
077 quotedText.append(WHITESPACE);
078 }
079 } else {
080 if (quotedText.length() > 0) {
081 quotedText.append(token);
082 } else {
083 tokens.add(token);
084 }
085 }
086 }
087 if (quotedText.length() > 0) {
088 throw new IllegalArgumentException("Invalid quoting found in args " + quotedText);
089 }
090 return tokens;
091 }
092
093 /**
094 * Tests if the input is enclosed within {@link #QUOTE_CHAR} characters
095 *
096 * @param input a not null String
097 * @return true if the regular expression is matched
098 */
099 protected static boolean isSingleQuoted(String input) {
100 if (input == null || input.trim().length() == 0) {
101 return false;
102 }
103 return input.matches("(^" + QUOTE_CHAR + "{1}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{1})");
104 }
105
106 /**
107 * Tests if the input is enclosed within a double-{@link #QUOTE_CHAR} string
108 *
109 * @param input a not null String
110 * @return true if the regular expression is matched
111 */
112 protected static boolean isDoubleQuoted(String input) {
113 if (input == null || input.trim().length() == 0) {
114 return false;
115 }
116 return input.matches("(^" + QUOTE_CHAR + "{2}([^" + QUOTE_CHAR + "]+)" + QUOTE_CHAR + "{2})");
117 }
118 }