| /* |
| * 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.netbeans.modules.maven.runjar; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| import java.util.logging.Logger; |
| import java.util.regex.Pattern; |
| import org.netbeans.api.annotations.common.NonNull; |
| import org.netbeans.modules.maven.NbMavenProjectImpl; |
| import org.netbeans.modules.maven.api.customizer.ModelHandle2; |
| import org.netbeans.modules.maven.customizer.RunJarPanel; |
| import org.netbeans.modules.maven.execute.ActionToGoalUtils; |
| import org.netbeans.modules.maven.execute.model.ActionToGoalMapping; |
| import org.netbeans.modules.maven.execute.model.NetbeansActionMapping; |
| import org.netbeans.spi.project.ActionProvider; |
| |
| /** |
| * |
| * @author sdedic |
| */ |
| public final class MavenExecuteUtils { |
| /** |
| * Hint for the default PrereqqCheckeers that explicit parameters have been already processed. |
| * Will not be propagated to maven process. |
| */ |
| public static final String RUN_EXPLICIT_PROCESSED = "NbIde.ExplicitParametersApplied"; // NOI18N |
| |
| /** |
| * Name of the property for VM arguments. |
| * @since 2.144 |
| */ |
| public static final String RUN_VM_PARAMS = "exec.vmArgs"; //NOI18N |
| |
| /** |
| * Name of the property to pass main class. ${packageClassName} works as well. |
| * @since 2.144 |
| */ |
| public static final String RUN_MAIN_CLASS = "exec.mainClass"; //NOI18N |
| |
| /** |
| * Name of the property for application arguments. |
| * @since 2.144 |
| */ |
| public static final String RUN_APP_PARAMS = "exec.appArgs"; //NOI18N |
| |
| /** |
| * Name of the property that collects the entire command line. |
| */ |
| public static final String RUN_PARAMS = "exec.args"; //NOI18N |
| |
| /** |
| * Name of the property for working directory passed to th exec plugin |
| */ |
| public static final String RUN_WORKDIR = "exec.workingdir"; //NOI18N |
| |
| private static final String RUN_VM_PARAMS_TOKEN = "${" + RUN_VM_PARAMS + "}"; //NOI18N |
| private static final String RUN_APP_PARAMS_TOKEN = "${" + RUN_APP_PARAMS + "}"; //NOI18N |
| private static final String RUN_MAIN_CLASS_TOKEN = "${" + RUN_MAIN_CLASS + "}"; //NOI18N |
| static final String PACKAGE_CLASS_NAME_TOKEN = "${packageClassName}"; //NOI18N |
| |
| public static final String EXEC_ARGS_CLASSPATH_TOKEN = "-classpath %classpath"; // NOI18N |
| public static final String DEFAULT_EXEC_ARGS_CLASSPATH = EXEC_ARGS_CLASSPATH_TOKEN + " ${packageClassName}"; // NOI18N |
| static final String DEFAULT_DEBUG_PARAMS = "-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}"; //NOI18N |
| static final String DEFAULT_EXEC_ARGS_CLASSPATH2 = "${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}"; // NOI18N |
| |
| public static final String ENV_PREFIX = "Env."; // NOI18N |
| public static final String ENV_REMOVED = new String("null"); // A special instance for env vars to be removed. // NOI18N |
| |
| /** |
| * ID of the 'profile' action. |
| */ |
| public static final String PROFILE_CMD = "profile"; // NOI18N |
| |
| /** |
| * A helper that can update action mappings based on changes |
| * made on the helper instance. Use {@link #createExecutionEnvHelper} |
| * to make an instance. |
| */ |
| public static final class ExecutionEnvHelper { |
| private final ActionToGoalMapping goalMappings; |
| private final NbMavenProjectImpl project; |
| |
| private String oldAllParams; |
| private String oldVmParams; |
| private String oldAppParams; |
| private String oldWorkDir; |
| private String oldMainClass; |
| |
| private boolean currentRun; |
| private boolean currentDebug; |
| private boolean currentProfile; |
| |
| private String vmParams; |
| private String appParams; |
| private String workDir; |
| private String mainClass; |
| |
| private NetbeansActionMapping run; |
| private NetbeansActionMapping debug; |
| private NetbeansActionMapping profile; |
| |
| private boolean mergedConfig; |
| private boolean modified; |
| |
| ExecutionEnvHelper( |
| NbMavenProjectImpl project, |
| NetbeansActionMapping run, |
| NetbeansActionMapping debug, |
| NetbeansActionMapping profile, |
| ActionToGoalMapping goalMappings) { |
| this.project = project; |
| this.goalMappings = goalMappings; |
| this.run = run; |
| this.debug = debug; |
| this.profile = profile; |
| } |
| |
| private String fallbackParams(String paramName, boolean stripDebug) { |
| String val = run != null ? run.getProperties().get(paramName) : null; |
| if (val == null && debug != null) { |
| val = debug.getProperties().get(paramName); |
| if (val != null && stripDebug) { |
| val = String.join(" ", extractDebugJVMOptions(val)); |
| } |
| } |
| if (val == null && profile != null) { |
| val = profile.getProperties().get(paramName); |
| } |
| return val == null ? "" : val.trim(); // NOI18N |
| } |
| |
| private String appendIfNotEmpty(String a, String b) { |
| if (a == null || a.isEmpty()) { |
| return b; |
| } |
| if (b == null || b.isEmpty()) { |
| return a; |
| } |
| return a + " " + b; |
| } |
| |
| public ActionToGoalMapping getGoalMappings() { |
| return goalMappings; |
| } |
| |
| public boolean isModified() { |
| return modified; |
| } |
| |
| public boolean isValid() { |
| return currentRun && currentDebug && currentProfile; |
| } |
| |
| public boolean isCurrentRun() { |
| return currentRun; |
| } |
| |
| public boolean isCurrentDebug() { |
| return currentDebug; |
| } |
| |
| public boolean isCurrentProfile() { |
| return currentProfile; |
| } |
| |
| public void setMainClass(String mainClass) { |
| this.mainClass = mainClass; |
| } |
| |
| public void setVmParams(String vmParams) { |
| this.vmParams = vmParams; |
| } |
| |
| public void setAppParams(String appParams) { |
| this.appParams = appParams; |
| } |
| |
| public NbMavenProjectImpl getProject() { |
| return project; |
| } |
| |
| public String getWorkDir() { |
| return oldWorkDir; |
| } |
| |
| public void setWorkDir(String workDir) { |
| this.workDir = workDir; |
| } |
| |
| public String getMainClass() { |
| return mainClass; |
| } |
| |
| public NetbeansActionMapping getRun() { |
| return run; |
| } |
| |
| public NetbeansActionMapping getProfile() { |
| return profile; |
| } |
| |
| public String getAllParams() { |
| return oldAllParams; |
| } |
| |
| public String getVmParams() { |
| return vmParams; |
| } |
| |
| public String getAppParams() { |
| return appParams; |
| } |
| |
| private NetbeansActionMapping getMapping(String a) { |
| NetbeansActionMapping m = ActionToGoalUtils.getDefaultMapping(a, project); |
| return m; |
| } |
| |
| /** |
| * Loads and parses values from the project's nbactions.xml |
| */ |
| public void loadFromProject() { |
| NetbeansActionMapping m; |
| |
| if (run == null) { |
| run = getMapping(ActionProvider.COMMAND_RUN); |
| } |
| if (debug == null) { |
| debug = getMapping(ActionProvider.COMMAND_DEBUG); |
| } |
| if (profile == null) { |
| profile = getMapping(PROFILE_CMD); |
| } |
| |
| currentRun = checkNewMapping(run); |
| currentDebug = checkNewMapping(debug); |
| currentProfile = checkNewMapping(profile); |
| |
| oldWorkDir = fallbackParams(RUN_WORKDIR, false); |
| oldAllParams = fallbackParams(RUN_PARAMS, false); |
| oldVmParams = fallbackParams(RUN_VM_PARAMS, true); |
| oldAppParams = fallbackParams(RUN_APP_PARAMS, false); |
| oldMainClass = fallbackParams(RUN_MAIN_CLASS, false); |
| |
| mergedConfig = (oldVmParams.isEmpty() && oldAppParams.isEmpty() && oldMainClass.isEmpty()); |
| |
| appendVMParamsFromOldParams(); |
| addAppParamsFromOldParams(); |
| loadMainClass(); |
| |
| workDir = oldWorkDir; |
| vmParams = oldVmParams; |
| appParams = oldAppParams; |
| mainClass = oldMainClass; |
| } |
| |
| private String eraseTokens(String original, boolean withNewlines, String... tokens) { |
| StringBuilder sb = new StringBuilder(); |
| for (String p : tokens) { |
| if (sb.length() > 0) { |
| sb.append("|"); |
| } |
| sb.append(Pattern.quote(p)); |
| if (withNewlines) { |
| sb.append("\\n?"); |
| } |
| } |
| return original.replaceAll(sb.toString(), "").trim(); |
| } |
| |
| private void appendVMParamsFromOldParams() { |
| String oldSplitVMParams = splitJVMParams(oldAllParams, true); |
| if (!oldSplitVMParams.isEmpty()) { |
| // try to get VM arguments out of all exec.args, but ignore -classpath added automatically, and |
| // exec.vmArgs present / added by default. |
| oldSplitVMParams = eraseTokens(oldSplitVMParams, true, "-classpath %classpath", RUN_VM_PARAMS_TOKEN); |
| oldVmParams = appendIfNotEmpty(oldVmParams, oldSplitVMParams); |
| } |
| } |
| |
| private void addAppParamsFromOldParams() { |
| String p = splitParams(oldAllParams); |
| if (!p.isEmpty()) { |
| p = eraseTokens(p, false, RUN_APP_PARAMS_TOKEN); |
| oldAppParams = appendIfNotEmpty(oldAppParams, p); |
| } |
| } |
| |
| private void loadMainClass() { |
| if (oldMainClass.trim().isEmpty()) { |
| oldMainClass = splitMainClass(oldAllParams); |
| // splitMainClass is never null |
| } |
| if (PACKAGE_CLASS_NAME_TOKEN.equals(oldMainClass) || RUN_MAIN_CLASS_TOKEN.equals(oldMainClass)) { |
| oldMainClass = ""; |
| } |
| } |
| |
| private boolean checkNewMapping(NetbeansActionMapping map) { |
| if (map == null || map.getGoals() == null) { |
| return false; //#164323 |
| } |
| Iterator it = map.getGoals().iterator(); |
| while (it.hasNext()) { |
| String goal = (String) it.next(); |
| if (goal.matches("org\\.codehaus\\.mojo\\:exec-maven-plugin\\:(.)+\\:exec") //NOI18N |
| || goal.indexOf("exec:exec") > -1) { //NOI18N |
| if (map.getProperties() != null) { |
| if (map.getProperties().containsKey("exec.args")) { |
| String execArgs = map.getProperties().get("exec.args"); |
| if (execArgs.contains("-classpath")) { |
| return true; |
| } |
| } |
| if (map.getProperties().containsKey("exec.vmArgs")) { |
| String execArgs = map.getProperties().get("exec.vmArgs"); |
| if (execArgs.contains("-classpath")) { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| public void applyToMappings() { |
| if (!(currentRun || currentDebug || currentProfile)) { |
| return; |
| } |
| |
| if (currentRun) { |
| updateAction(run, ""); |
| } |
| if (currentDebug) { |
| updateAction(debug, DEFAULT_DEBUG_PARAMS); |
| } |
| if (currentProfile) { |
| updateAction(profile, ""); |
| } |
| } |
| |
| private void updateAction(NetbeansActionMapping mapping, String debuVMArgs) { |
| boolean changed = false; |
| |
| if (!oldWorkDir.equals(workDir)) { |
| mapping.addProperty(RUN_WORKDIR, workDir); |
| changed = true; |
| } |
| if (!oldAppParams.equals(appParams)) { |
| mapping.addProperty(RUN_APP_PARAMS, appParams); |
| changed = true; |
| } |
| String newMainClass = this.mainClass; |
| if (newMainClass.trim().length() == 0) { |
| newMainClass = PACKAGE_CLASS_NAME_TOKEN; |
| } |
| if (!oldMainClass.equals(newMainClass)) { |
| mapping.addProperty(RUN_MAIN_CLASS, newMainClass); |
| changed = true; |
| } |
| if (!workDir.equals(oldWorkDir)) { |
| mapping.addProperty(RUN_WORKDIR, workDir); |
| changed = true; |
| } |
| String oneLineVMParams = vmParams.replace('\n', ' '); |
| String newVMParams = appendIfNotEmpty(oneLineVMParams, debuVMArgs); |
| if (!oldVmParams.equals(newVMParams)) { |
| mapping.addProperty(RUN_VM_PARAMS, newVMParams); |
| changed = true; |
| } |
| |
| if (changed) { |
| // define the properties, if not defined ... |
| Map<String, String> props = mapping.getProperties(); |
| if (mapping.getProperties().get(RUN_VM_PARAMS) == null) { |
| mapping.addProperty(RUN_VM_PARAMS, vmParams); |
| } |
| if (mapping.getProperties().get(RUN_APP_PARAMS) == null) { |
| mapping.addProperty(RUN_APP_PARAMS, appParams); |
| } |
| if (mapping.getProperties().get(RUN_MAIN_CLASS) == null) { |
| mapping.addProperty(RUN_MAIN_CLASS, newMainClass); |
| } |
| mapping.addProperty(RUN_PARAMS, |
| "${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}" |
| ); |
| } |
| |
| if (changed) { |
| ModelHandle2.setUserActionMapping(mapping, goalMappings); |
| modified = true; |
| } |
| } |
| } |
| |
| /** |
| * Splits a command line, pays respect to quoting and newlines. |
| * @param line original line |
| * @return line split into individual arguments. |
| */ |
| public static String[] splitCommandLine(String line) { |
| if (line == null) { |
| return new String[0]; |
| } |
| String l = line.trim(); |
| if (l.isEmpty()) { |
| return new String[0]; |
| } |
| List<String> result = new ArrayList<>(); |
| for (String part : propertySplitter(l, true)) { |
| result.add(part); |
| } |
| return result.toArray(new String[result.size()]); |
| } |
| |
| private static boolean isNullOrEmpty(String s) { |
| return s == null || s.trim().isEmpty(); |
| } |
| |
| /** |
| * Checks that the mapping does not specify custom exec arguments. If |
| * the exec.args is set to {@link #DEFAULT_EXEC_ARGS_CLASSPATH}, the |
| * `packageClassName' has not been set (= unspecified). |
| * If the exec.args is set tp {@link #DEFAULT_EXEC_ARGS_CLASSPATH2}, then |
| * none of the referenced properties can provide a value (the exec.args itself |
| * is not changed by the IDE, just the referenced properties). |
| * <p> |
| * Other values of `exec.args' means user customizations. |
| * <p> |
| * Returns {@code null}, if there are user customizations. Returns the value of |
| * exec.args (the default string) so the caller can retain the parameter |
| * passing style. |
| * |
| * @param mapp action mapping. |
| * @return |
| */ |
| public static String doesNotSpecifyCustomExecArgs(NetbeansActionMapping mapp) { |
| return doesNotSpecifyCustomExecArgs(true, mapp.getProperties()); |
| } |
| |
| private static boolean equalsOrIncludes(boolean exact, String text, String toFind) { |
| if (exact) { |
| return text.equals(toFind); |
| } else { |
| return text.contains(toFind); |
| } |
| } |
| |
| /** |
| * The inexact match is used from RunJarStartupArgs |
| */ |
| public static String doesNotSpecifyCustomExecArgs(boolean exact, Map<? extends String, ? extends String> props) { |
| String execArgs = props.get(RUN_PARAMS); |
| String replacedMainClass = props.get(RUN_MAIN_CLASS); |
| String template; |
| boolean secondTry = replacedMainClass != null && execArgs.contains(PACKAGE_CLASS_NAME_TOKEN); |
| |
| template = DEFAULT_EXEC_ARGS_CLASSPATH; |
| if (equalsOrIncludes(exact, execArgs, template)) { |
| return template; |
| } |
| if (secondTry) { |
| template = template.replace(PACKAGE_CLASS_NAME_TOKEN, replacedMainClass); |
| if (equalsOrIncludes(exact, execArgs, template)) { |
| return template; |
| } |
| } |
| template = DEFAULT_EXEC_ARGS_CLASSPATH2; |
| if (!equalsOrIncludes(exact, execArgs, template)) { |
| if (!secondTry) { |
| return null; |
| } |
| template = template.replace(PACKAGE_CLASS_NAME_TOKEN, replacedMainClass); |
| if (!equalsOrIncludes(exact, execArgs, template)) { |
| return null; |
| } |
| } |
| |
| if (!exact) { |
| return template; |
| } |
| |
| // none of the properties refrenced in DEFAULT_EXEC_ARGS_CLASSPATH2 is defined: |
| if (isNullOrEmpty(props.get(RUN_APP_PARAMS)) && |
| isNullOrEmpty(props.get(RUN_VM_PARAMS))) { |
| |
| String mainClass = props.get(RUN_MAIN_CLASS); |
| if (mainClass == null || |
| "".equals(mainClass) || |
| MavenExecuteUtils.PACKAGE_CLASS_NAME_TOKEN.equals(mainClass)) { |
| return template; |
| } |
| } |
| return null; |
| } |
| |
| public static boolean isEnvRemovedValue(String value) { |
| return value == ENV_REMOVED; // It's crutial to test the instance identity |
| } |
| |
| /** |
| * Creates a helper to edit the mapping instances. Individual settings can be |
| * inspected by getters and changed by setters on the helper, changes can be then |
| * applied back to the mappings. |
| * @param project the target project |
| * @param run run action mapping |
| * @param debug debug action mapping |
| * @param profile profile action mapping |
| * @param goalMappings the mapping registry |
| * @return |
| */ |
| public static ExecutionEnvHelper createExecutionEnvHelper( |
| NbMavenProjectImpl project, |
| NetbeansActionMapping run, |
| NetbeansActionMapping debug, |
| NetbeansActionMapping profile, |
| ActionToGoalMapping goalMappings) { |
| return new ExecutionEnvHelper(project, run, debug, profile, goalMappings); |
| } |
| |
| /** |
| * Joins parameters into a single string. Quotes as necessary if parameters contain |
| * spaces. Checks for already quoted or escaped parameters. |
| * @param params List of parameters. |
| * @return single command line. |
| */ |
| public static String joinParameters(String... params) { |
| if (params == null) { |
| return ""; // NOI18N |
| } |
| return joinParameters(Arrays.asList(params)); |
| } |
| |
| private static boolean isQuoteChar(char c) { |
| return c == '\'' || c == '"'; |
| } |
| |
| public static List<String> escapeParameters(List<String> params) { |
| List<String> ret = new ArrayList<>(); |
| for (String s : params) { |
| if (s == null) { |
| continue; |
| } |
| if (s.length() > 1) { |
| char c = s.charAt(0); |
| if (isQuoteChar(c) && s.charAt(s.length() - 1) == c) { |
| ret.add(s); |
| continue; |
| } |
| } |
| // note: does not care about escaped spaces. |
| if (!s.contains(" ")) { |
| ret.add(s.replace("'", "\\'").replace("\"", "\\\"")); |
| } else { |
| ret.add("\"" + s.replace("\"", "\\\"") + "\""); |
| } |
| } |
| return ret; |
| } |
| |
| public static String joinParameters(List<String> params) { |
| return String.join(" ", escapeParameters(params)); |
| } |
| |
| public static List<String> extractDebugJVMOptions(String argLine) { |
| Iterable<String> split = propertySplitter(argLine, true); |
| List<String> toRet = new ArrayList<String>(); |
| for (String arg : split) { |
| if ("-Xdebug".equals(arg)) { //NOI18N |
| continue; |
| } |
| if ("-Djava.compiler=none".equals(arg)) { //NOI18N |
| continue; |
| } |
| if ("-Xnoagent".equals(arg)) { //NOI18N |
| continue; |
| } |
| if (arg.startsWith("-Xrunjdwp")) { //NOI18N |
| continue; |
| } |
| if (arg.equals("-agentlib:jdwp")) { //NOI18N |
| continue; |
| } |
| if (arg.startsWith("-agentlib:jdwp=")) { //NOI18N |
| continue; |
| } |
| if (arg.trim().length() == 0) { |
| continue; |
| } |
| toRet.add(arg); |
| } |
| return toRet; |
| } |
| |
| |
| /** |
| * used by quickrun configuration. |
| * @param argline |
| * @return |
| */ |
| public static String[] splitAll(String argline, boolean filterClassPath) { |
| String jvm = argline == null ? null : splitJVMParams(argline, false); |
| String mainClazz = argline == null ? null : splitMainClass(argline); |
| String args = argline == null ? null : splitParams(argline); |
| if (filterClassPath && jvm != null && jvm.contains("-classpath %classpath")) { |
| jvm = jvm.replace("-classpath %classpath", ""); |
| } |
| if (mainClazz != null && mainClazz.equals("${packageClassName}")) { |
| mainClazz = ""; |
| } |
| return new String[] { |
| (jvm != null ? jvm : ""), |
| (mainClazz != null ? mainClazz : ""), |
| (args != null ? args : "") |
| }; |
| } |
| |
| public static String splitJVMParams(String line) { |
| return splitJVMParams(line, false); |
| } |
| |
| @NonNull |
| public static String splitJVMParams(String line, boolean newLines) { |
| PropertySplitter ps = new PropertySplitter(line); |
| ps.setSeparator(' '); //NOI18N |
| String s = ps.nextPair(); |
| String jvms = ""; //NOI18N |
| while (s != null) { |
| if (s.startsWith("-") || /* #199411 */s.startsWith("\"-") || s.contains("%classpath")) { //NOI18N |
| if(s.contains("%classpath")) { |
| jvms = jvms + " " + s; |
| } else { |
| jvms = jvms + (jvms.isEmpty() ? "" : (newLines ? "\n" : " ")) + s; |
| } |
| } else if (s.equals(PACKAGE_CLASS_NAME_TOKEN) || s.equals(RUN_MAIN_CLASS_TOKEN) || s.matches("[\\w]+[\\.]{0,1}[\\w\\.]*")) { //NOI18N |
| break; |
| } else { |
| jvms = jvms + " " + s; |
| } |
| s = ps.nextPair(); |
| } |
| return jvms.trim(); |
| } |
| |
| @NonNull |
| public static String splitMainClass(String line) { |
| PropertySplitter ps = new PropertySplitter(line); |
| ps.setSeparator(' '); //NOI18N |
| String s = ps.nextPair(); |
| while (s != null) { |
| if (s.startsWith("-") || s.contains("%classpath")) { //NOI18N |
| s = ps.nextPair(); |
| continue; |
| } else if (s.equals(PACKAGE_CLASS_NAME_TOKEN) || s.equals(RUN_MAIN_CLASS_TOKEN) || s.matches("[\\w]+[\\.]{0,1}[\\w\\.]*")) { //NOI18N |
| return s; |
| } else { |
| Logger.getLogger(RunJarPanel.class.getName()).fine("failed splitting main class from=" + line); //NOI18N |
| } |
| s = ps.nextPair(); |
| } |
| return ""; //NOI18N |
| } |
| |
| @NonNull |
| public static String splitParams(String line) { |
| int argsIndex = line.indexOf(RunJarStartupArgs.USER_PROGRAM_ARGS_MARKER); |
| if (argsIndex > -1) { |
| return line.substring(argsIndex + RunJarStartupArgs.USER_PROGRAM_ARGS_MARKER.length()).trim(); |
| } |
| String main = splitMainClass(line); |
| if (main.isEmpty()) { |
| return ""; |
| } |
| int i = line.indexOf(main); |
| if (i > -1) { |
| return line.substring(i + main.length()).trim(); |
| } |
| return ""; //NOI18N |
| } |
| /** |
| * Splits the line into sequence of arguments, respects quoting. |
| * @param line the line as a string |
| * @return arguments in an iterable |
| */ |
| public static Iterable<String> propertySplitter(String line) { |
| return propertySplitter(line, true); |
| } |
| |
| public static Iterable<String> propertySplitter(String line, boolean outputQuotes) { |
| class SplitIt implements Iterator<String> { |
| private final PropertySplitter spl = new PropertySplitter(line); |
| private String nextPair; |
| |
| public SplitIt() { |
| spl.setSeparator(' '); |
| spl.setOutputQuotes(outputQuotes); |
| } |
| |
| @Override |
| public boolean hasNext() { |
| if (nextPair == null) { |
| nextPair = spl.nextPair(); |
| } |
| return nextPair != null; |
| } |
| |
| @Override |
| public String next() { |
| String s; |
| if (nextPair == null) { |
| nextPair = spl.nextPair(); |
| } |
| s = nextPair; |
| nextPair = null; |
| if (s != null) { |
| return s; |
| } else { |
| throw new NoSuchElementException(); |
| } |
| } |
| } |
| return new Iterable<String>() { |
| @Override |
| public Iterator<String> iterator() { |
| return new SplitIt(); |
| } |
| }; |
| } |
| } |