All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.maven.runjar.RunJarStartupArgs Maven / Gradle / Ivy

The newest version!
/*
 * 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.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
import org.netbeans.api.extexecution.startup.StartupExtender;
import org.netbeans.api.project.Project;
import org.netbeans.modules.maven.ActionProviderImpl;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.modules.maven.api.execute.ActiveJ2SEPlatformProvider;
import org.netbeans.modules.maven.api.execute.ExecutionContext;
import org.netbeans.modules.maven.api.execute.LateBoundPrerequisitesChecker;
import org.netbeans.modules.maven.api.execute.RunConfig;
import org.netbeans.modules.maven.execute.BeanRunConfig;
import org.netbeans.modules.maven.execute.ModelRunConfig;
import org.netbeans.spi.project.ActionProvider;
import org.netbeans.spi.project.ProjectServiceProvider;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;

@ProjectServiceProvider(service=LateBoundPrerequisitesChecker.class, projectType="org-netbeans-modules-maven/" + NbMavenProject.TYPE_JAR)
public class RunJarStartupArgs implements LateBoundPrerequisitesChecker {
    /**
     * Marker that separates VM args main class name from 'user specified arguments', whatever that
     * means for a selected goal.
     * If not present, then any injected arguments will be appended at the end of 'exec.args' property. If
     * present, the action context can replace the arguments.
     * @since 2.143
     */
    public static final String USER_PROGRAM_ARGS_MARKER = "%args"; // NOI18N
    
    /**
     * Splits a command line, pays respect to quoting and newlines.
     * @param line original line
     * @return line split into individual arguments.
     */
    private static String[] splitCommandLine(String line) {
        if (line == null) {
            return new String[0];
        }
        String l = line.trim();
        if (l.isEmpty()) {
            return new String[0];
        }
        List result = new ArrayList<>();
        for (String part : MavenExecuteUtils.propertySplitter(l, true)) {
            result.add(part);
        }
        return result.toArray(new String[0]);
    }
    
    @Override public boolean checkRunConfig(RunConfig config, ExecutionContext con) {
        String actionName = config.getActionName();
        StartupExtender.StartMode mode;
        if (ActionProvider.COMMAND_RUN.equals(actionName) || ActionProviderImpl.COMMAND_RUN_MAIN.equals(actionName)) {
            mode = StartupExtender.StartMode.NORMAL;
        } else if (ActionProvider.COMMAND_DEBUG.equals(actionName) || ActionProviderImpl.COMMAND_DEBUG_MAIN.equals(actionName)) {
            mode = StartupExtender.StartMode.DEBUG;
        } else if (ActionProvider.COMMAND_PROFILE.equals(actionName) || ActionProvider.COMMAND_PROFILE_SINGLE.equals(actionName) || ActionProviderImpl.COMMAND_PROFILE_MAIN.equals(actionName)) {
            mode = StartupExtender.StartMode.PROFILE;
        } else if (ActionProvider.COMMAND_PROFILE_TEST_SINGLE.equals(actionName)) {
            mode = StartupExtender.StartMode.TEST_PROFILE;
        } else {
            // XXX could also set argLine for COMMAND_TEST and relatives (StartMode.TEST_*); need not be specific to TYPE_JAR
            return true;
        }
        boolean isTestScope = false;
        Map props = config.getProperties();
        boolean vmArgsPresent = props.containsKey(MavenExecuteUtils.RUN_VM_PARAMS);
        boolean appArgsPresent = props.containsKey(MavenExecuteUtils.RUN_APP_PARAMS);
        boolean execArgsPresent = props.containsKey(MavenExecuteUtils.RUN_PARAMS);
        
        List fixedArgs = new ArrayList();
        if (execArgsPresent || vmArgsPresent || appArgsPresent) {
            // define exec.vmArgs and exec.appArgs
            InstanceContent ic = new InstanceContent();
            Project p = config.getProject();
            if (p != null) {
                ic.add(p);
                ActiveJ2SEPlatformProvider pp = p.getLookup().lookup(ActiveJ2SEPlatformProvider.class);
                if (pp != null) {
                    ic.add(pp.getJavaPlatform());
                }
            }
            for (StartupExtender group : StartupExtender.getExtenders(new AbstractLookup(ic), mode)) {
                fixedArgs.addAll(group.getRawArguments());
            }
        }
        
        boolean splitParameters = vmArgsPresent || appArgsPresent;
        List joinedArgs = new ArrayList<>(fixedArgs);
        
        ExplicitProcessParameters changedParams = null;
        List vmArgsValue;
        List appArgsValue;
        
        ExplicitProcessParameters injectParams = ExplicitProcessParameters.buildExplicitParameters(config.getActionContext());

        if (splitParameters) {
            vmArgsValue = new ArrayList<>(Arrays.asList(splitCommandLine(props.get(MavenExecuteUtils.RUN_VM_PARAMS))));
            appArgsValue = new ArrayList<>(Arrays.asList(splitCommandLine(props.get(MavenExecuteUtils.RUN_APP_PARAMS))));
        } else {
            String val = props.get(MavenExecuteUtils.RUN_PARAMS);
            // split the 'exec.args' property to main and user arguments; userArgs will be null
            // if no user arguments are present or the marker is not found
            String[] argParts = MavenExecuteUtils.splitAll(val, false);

            vmArgsValue = new ArrayList<>(Arrays.asList(splitCommandLine(argParts[0])));
            String[] mainClass = splitCommandLine(argParts[1]);
            appArgsValue = new ArrayList<>(Arrays.asList(splitCommandLine(argParts[2])));

            if (mainClass.length == 0) {
                // accept userargs, since we don't know where the division is, make it fixed in the processing.
                joinedArgs.addAll(appArgsValue);
                appArgsValue = Collections.emptyList();
            } else {
                joinedArgs.addAll(Arrays.asList(mainClass));
            }

            // patch: if there's -classpath %classpath in the vmArgsValue, move it at the start of fixedArgs
            int at = vmArgsValue.indexOf("-classpath");
            if (at >= 0 && vmArgsValue.size() > at + 1 && "%classpath".equals(vmArgsValue.get(at + 1))) {
                List toMove = vmArgsValue.subList(at, at + 2);
                joinedArgs.subList(0, 0).addAll(toMove);
                toMove.clear();
            }
        }

        // RunConfig may have merged in POM VM args and command, but indicated that using "exec.args.merged" property
        // there can be prefix (= vm args) and suffix (app args) that may need to be replaced.
        // Also run the scan when there's no apparent vmArg or appArg - maybe they are configured directly into the 
        // exec.args property by the user - but recognize only the basic pattern; action mapping must be adjusted for more complex setups.
        if ("true".equals(config.getProperties().get(ModelRunConfig.EXEC_MERGED)) ||
            (vmArgsValue.isEmpty() && appArgsValue.isEmpty())) {
            String cmdLine = props.get(MavenExecuteUtils.RUN_PARAMS);
            if (cmdLine != null) {
                String template = MavenExecuteUtils.doesNotSpecifyCustomExecArgs(false, config.getProperties());
                // the template should be never null, as EXEC_MERGED can be set only if doesNotSpecifyCustomExecArgs already returned true...
                int templateIndex = template == null ? -1 : cmdLine.indexOf(template);
                if (templateIndex > 0) {
                    String prefix = cmdLine.substring(0, templateIndex);
                    String suffix = cmdLine.substring(templateIndex + template.length());

                    // for !splitParameters, vmArgs & args were populated above
                    if (splitParameters) {
                        vmArgsValue.addAll(0, Arrays.asList(splitCommandLine(prefix.trim())));
                        appArgsValue.addAll(0, Arrays.asList(splitCommandLine(suffix.trim())));
                    }
                    // replace back the template, since we handle the VM (prefix) and app (postfix)
                    config.setProperty(MavenExecuteUtils.RUN_PARAMS, template);
                }
            }
        }
        
        List vmArgs = new ArrayList<>(fixedArgs);
        if (!(fixedArgs.isEmpty() && injectParams.isEmpty())) {
            changedParams = ExplicitProcessParameters.
                builder().launcherArgs(vmArgsValue).
                // include user arguments, if any
                args(appArgsValue).
                // allow to append or override from context injectors.
                combine(
                    injectParams
                ).build();
            
            if (!splitParameters) {
                // the original cmdline was split between vmArgsValue appArgsValue and joinedArgs, so
                // any customizations shoudl remain preserved.
                String newParams = String.join(" ", changedParams.getAllArguments(joinedArgs));
                config.setProperty(MavenExecuteUtils.RUN_PARAMS, newParams);
            }
            
            vmArgs.addAll(changedParams.getLauncherArguments());
            config.setProperty(MavenExecuteUtils.RUN_VM_PARAMS, 
                    MavenExecuteUtils.joinParameters(vmArgs));
            config.setProperty(MavenExecuteUtils.RUN_APP_PARAMS, 
                    MavenExecuteUtils.joinParameters(changedParams.getArguments()));
        } else {
            vmArgs.addAll(vmArgsValue);
            config.setProperty(MavenExecuteUtils.RUN_VM_PARAMS, 
                    MavenExecuteUtils.joinParameters(vmArgs));
            config.setProperty(MavenExecuteUtils.RUN_APP_PARAMS, 
                    MavenExecuteUtils.joinParameters(appArgsValue));
        }
        File workingDirectory = injectParams.getWorkingDirectory();
        if (workingDirectory != null) {
            config.setProperty(MavenExecuteUtils.RUN_WORKDIR,
                    workingDirectory.getAbsolutePath());
        }
        Map environmentVariables = injectParams.getEnvironmentVariables();
        for (Map.Entry env : environmentVariables.entrySet()) {
            String value = env.getValue();
            if (value == null) {
                // The environment variable is to be removed when the value is null
                value = MavenExecuteUtils.ENV_REMOVED;
            }
            config.setProperty(MavenExecuteUtils.ENV_PREFIX + env.getKey(), value);
        }

        if ("test".equals(props.get("exec.classpathScope"))) {
            isTestScope = true;
        }
        if (isTestScope) { //#230190
            String[] goals = config.getGoals().toArray(new String[0]);
            for (int i = 0; i < goals.length;i++) {
                if ("process-classes".equals(goals[i])) {
                    goals[i] = "process-test-classes";
                }
            }
            ((BeanRunConfig)config).setGoals(new ArrayList(Arrays.asList(goals)));
        }
        config.setProperty(MavenExecuteUtils.RUN_EXPLICIT_PROCESSED, "true");
        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy