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

org.codehaus.mevenide.netbeans.execute.MavenJavaExecutor Maven / Gradle / Ivy

The newest version!
/* ==========================================================================
 * Copyright 2005 Mevenide Team
 *
 * Licensed 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.codehaus.mevenide.netbeans.execute;

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.mevenide.netbeans.api.execute.RunConfig;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.apache.maven.cli.CLIReportingUtils;
import org.apache.maven.embedder.ConfigurationValidationResult;
import org.apache.maven.embedder.DefaultConfiguration;
import org.apache.maven.embedder.MavenEmbedder;
import org.apache.maven.embedder.MavenEmbedderLogger;
import org.apache.maven.errors.DefaultCoreErrorReporter;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.settings.Activation;
import org.apache.maven.settings.ActivationProperty;
import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Repository;
import org.apache.maven.settings.RepositoryPolicy;
import org.codehaus.mevenide.netbeans.api.ProjectURLWatcher;
import org.codehaus.mevenide.netbeans.embedder.EmbedderFactory;
import org.codehaus.mevenide.netbeans.embedder.exec.ProgressTransferListener;
import org.codehaus.mevenide.netbeans.embedder.exec.MyLifecycleExecutor;
import org.codehaus.mevenide.netbeans.options.MavenExecutionSettings;
import org.netbeans.api.progress.aggregate.AggregateProgressFactory;
import org.netbeans.api.progress.aggregate.AggregateProgressHandle;
import org.netbeans.api.progress.aggregate.ProgressContributor;
import org.netbeans.api.project.FileOwnerQuery;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.InputOutput;

/**
 * support for executing maven, from the ide using embedder
 * @author  Milos Kleint ([email protected])
 */
public class MavenJavaExecutor extends AbstractMavenExecutor {
    private static final String BASEDIR = "basedir";
    private static final String PROFILE_PRIVATE = "netbeans-private";
    private static final String PROFILE_PUBLIC = "netbeans-public";
    
    private AggregateProgressHandle handle;
    private OutputHandler out;
    
    private Logger LOGGER = Logger.getLogger(MavenJavaExecutor.class.getName());
    
    private volatile boolean finishing = false;
    
    
    public MavenJavaExecutor(RunConfig conf) {
        super(conf);
        handle = AggregateProgressFactory.createHandle(conf.getTaskDisplayName(), new ProgressContributor[0], this, null);
        ProgressContributor backupContrib = AggregateProgressFactory.createProgressContributor("backup"); //NOI18N
        handle.addContributor(backupContrib);
    }
    
    
    /**
     * not to be called directrly.. use execute();
     */
    public void run() {
        finishing = false;
        final Properties origanalProperties = config.getProperties();
        InputOutput ioput = getInputOutput();
        actionStatesAtStart();
        String basedir = System.getProperty(BASEDIR);//NOI18N
        handle.start();
        processInitialMessage();
        MavenExecutionRequest req = new DefaultMavenExecutionRequest();
        try {
            MavenEmbedder embedder;
            ProgressTransferListener.setAggregateHandle(handle);
            out = new OutputHandler(ioput, config.getProject(), handle, config);
            IOBridge.pushSystemInOutErr(out);
            boolean debug = config.isShowDebug();
            req.setShowErrors(debug || config.isShowError());
            if (debug) {
                req.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
                out.setThreshold(MavenEmbedderLogger.LEVEL_DEBUG);
            } else {
                req.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_INFO);
                out.setThreshold(MavenEmbedderLogger.LEVEL_INFO);
            }
            
            File userSettingsPath = MavenEmbedder.DEFAULT_USER_SETTINGS_FILE;
            File globalSettingsPath = InstalledFileLocator.getDefault().locate("maven2/settings.xml", null, false);//NOI18N
            DefaultConfiguration settConfig = new DefaultConfiguration();
            settConfig.setGlobalSettingsFile(globalSettingsPath);
            if (userSettingsPath.exists()) {
                settConfig.setUserSettingsFile(userSettingsPath);
            }
            ConfigurationValidationResult setres = MavenEmbedder.validateConfiguration(settConfig);
            if (!setres.isValid()) {
                if (setres.getUserSettingsException() != null) {
                    CLIReportingUtils.showError("Error reading user settings: ", setres.getUserSettingsException(), req.isShowErrors(), new DefaultCoreErrorReporter(), out);//NOI18N - part of maven output
                }
                if (setres.getUserSettingsException() != null) {
                    CLIReportingUtils.showError("Error reading global settings: ", setres.getGlobalSettingsException(), req.isShowErrors(), new DefaultCoreErrorReporter(), out);//NOI18N - part of maven output
                }
                return;
            }
            
            embedder = EmbedderFactory.createExecuteEmbedder(out);
            super.buildPlan.setEmbedder(embedder);
            if (config.getProject() != null) {
                try {
                    checkDebuggerListening(config, out);
                } catch (MojoExecutionException ex) {
                    LOGGER.log(Level.FINE, ex.getMessage(), ex);
                } catch (MojoFailureException ex) {
                    LOGGER.log(Level.FINE, ex.getMessage(), ex);
                }
            }
            File repoRoot = InstalledFileLocator.getDefault().locate("m2-repository", null, false);//NOI18N
            //TODO we should get completely rid of this..
            Profile myProfile = new Profile();
            if (repoRoot != null) {
                //can happen when users don't install the repository module.
                myProfile.setId(PROFILE_PUBLIC);//NOI18N
                Repository repo = new Repository();
                repo.setUrl("file://" + repoRoot.getAbsolutePath());//NOI18N
                repo.setId("netbeansIDE-repo-internal");//NOI18N
                RepositoryPolicy snap = new RepositoryPolicy();
                snap.setEnabled(false);
                repo.setSnapshots(snap);
                repo.setName("NetBeans IDE internal Repository hosting plugins that are executable in NetBeans IDE only.");//NOI18N
                myProfile.addPluginRepository(repo);
                Activation act = new Activation();
                ActivationProperty prop = new ActivationProperty();
                prop.setName("netbeans.execution");//NOI18N
                prop.setValue("true");//NOI18N
                act.setProperty(prop);
                myProfile.setActivation(act);
            }
            //TODO we need to reenact the custom dynamic profile.
//            Settings settings = embedder.buildSettings( userSettingsPath,
//                    globalSettingsPath,
//                    MavenExecutionSettings.getDefault().getPluginUpdatePolicy());
//            if (repoRoot != null) {
//                settings.addProfile(myProfile);
//            }
//            settings.setUsePluginRegistry(MavenExecutionSettings.getDefault().isUsePluginRegistry());
//            //MEVENIDE-407
//            if (settings.getLocalRepository() == null) {
//                settings.setLocalRepository(new File(userLoc, "repository").getAbsolutePath());//NOI18N
//            }
//            if (MavenExecutionSettings.getDefault().isSynchronizeProxy()) {
//            }
            
            req.addActiveProfiles(config.getActivatedProfiles());
            
            // TODO remove explicit activation
            req.addActiveProfile(PROFILE_PUBLIC).addActiveProfile(PROFILE_PRIVATE);
            //            req.activateDefaultEventMonitor();
            if (config.isOffline() != null) {
                req.setOffline(config.isOffline().booleanValue());
            }
            req.setInteractiveMode(config.isInteractive());
//TODO            req.setSettings(settings);
            req.setGoals(config.getGoals());
            //mavenCLI adds all System.getProperties() in there as well..
            Properties props = new Properties();
            EmbedderFactory.fillEnvVars(props);
            props.putAll(excludeNetBeansProperties(System.getProperties()));
            props.putAll(config.getProperties());
            props.setProperty("netbeans.execution", "true");//NOI18N
            
            req.setProperties(props);
            req.setBaseDirectory(config.getExecutionDirectory());
            File pom = new File(config.getExecutionDirectory(), "pom.xml");//NOI18N
            if (pom.exists()) {
                req.setPomFile(pom.getAbsolutePath());
            }
//TODO??            req.setLocalRepositoryPath(embedder.getSettings().getLocalRepository());
            req.addEventMonitor(out);
            req.setTransferListener(new ProgressTransferListener());
            //            req.setReactorActive(true);
            
            req.setReactorFailureBehavior(MavenExecutionSettings.getDefault().getFailureBehaviour());
            req.setStartTime(new Date());
            req.setGlobalChecksumPolicy(MavenExecutionSettings.getDefault().getChecksumPolicy());
            
            req.setUpdateSnapshots(config.isUpdateSnapshots());
            req.setRecursive(config.isRecursive());
            MavenExecutionResult res = embedder.execute(req);
            CLIReportingUtils.logResult(req, res, out);
            if (res.hasExceptions()) {
                //TODO something?
            }
//        } catch (MavenExecutionException ex) {
//            LOGGER.log(Level.FINE, ex.getMessage(), ex);
//        } catch (SettingsConfigurationException ex) {
//            LOGGER.log(Level.FINE, ex.getMessage(), ex);
        } catch (RuntimeException re) {
            CLIReportingUtils.showError("Runtime Exception thrown during execution", re, req.isShowErrors(), req.getErrorReporter(), out);//NOI18N - part of maven output
            LOGGER.log(Level.FINE, re.getMessage(), re);
        } catch (ThreadDeath death) {
//            cancel();
            CLIReportingUtils.showError("Killed.", new Exception(""), false, req.getErrorReporter(), out); //NOI18N - part of maven output
            shutdownOutput(ioput);
            ioput = null;
            throw death;
        } finally {
            finishing = true; //#103460
            out.buildFinished();
            shutdownOutput(ioput);
            handle.finish();
            handle = null;
            ProgressTransferListener.clearAggregateHandle();
            //SUREFIRE-94/MEVENIDE-412 the surefire plugin sets basedir environment variable, which breaks ant integration
            // in netbeans.
            if (basedir == null) {
                System.getProperties().remove(BASEDIR);
            } else {
                System.setProperty( BASEDIR,basedir);
            }
            //MEVENIDE-623 re add original Properties
            config.setProperties(origanalProperties);
            
            actionStatesAtFinish();
            EmbedderFactory.resetProjectEmbedder();
            final List fireList = MyLifecycleExecutor.getAffectedProjects();
            RequestProcessor.getDefault().post(new Runnable() { //#103460
                public void run() {
                    for (File elem: fireList) {
                        if (elem == null) {
                            // during archetype creation?
                            continue;
                        }
                        FileObject fo = FileUtil.toFileObject(FileUtil.normalizeFile(elem));
                        if (fo != null) {
                            //TODO have the firing based on open projects only..
                            ProjectURLWatcher.fireMavenProjectReload(FileOwnerQuery.getOwner(fo));
                        }
                    }
                }
            });
            doRemoveAllShutdownHooks();
        }
    }
    
    private void shutdownOutput(InputOutput ioput) {
        if (ioput == null) {
            return;
        }
        ioput.getOut().close();
        ioput.getErr().close();
        markFreeTab();
        IOBridge.restoreSystemInOutErr();
    }
    
    /** Number of milliseconds to wait before forcibly halting a runaway process. */
    private static final int STOP_TIMEOUT = 3000;    
    
    public boolean cancel() {
        if (out != null) {
            out.requestCancel(task);
            // Try stopping at a safe point.
            StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(MavenJavaExecutor.class, "MSG_stopping"));
            // But if that doesn't do it, double-check later...
            // Yes Thread.stop() is deprecated; that is why we try to avoid using it.
            RequestProcessor.getDefault().create(new Runnable() {
                public void run() {
                    if (!finishing) {
                        task.stop();
                    }
                }
            }).schedule(STOP_TIMEOUT);
        }
        return true;
    }
    
    


    /**
     * a brute force hack to workaround a severe issue with Maven Plugins 
     * registering shutdown hooks. The plugin's ThreadGroup was long gone and the
     * hooks thread was not capable of being run, halting the shutdown of the IDE
     * indefinitely.
     * The workaround involves use of reflection to get the list of shutdown hooks
     *  and remove/run all that appeared in the current threadgroup. The chances are
     * these stem from the plugins. (Use of shutdown hooks in the plugins should be punished
     * without mercy)
     */ 
    private void doRemoveAllShutdownHooks() {
        try     {
            java.lang.Class shutdown = java.lang.Class.forName("java.lang.Shutdown"); //NOI18N
            java.lang.reflect.Field fld = shutdown.getDeclaredField("hooks"); //NOI18N
            if (fld != null) {
                fld.setAccessible(true);
                Collection set = (Collection) fld.get(null);
                if (set != null) {
                    // objects are Shutdown.WrappedHook instances
                    for (Object wr : new ArrayList(set)) {
                        if (wr instanceof Runnable) {
                            // we'return in 1.6 and later.. it's all Runnables, not Threads..
                            // not possible to distinguish the maven shutdown hooks from the rest..
                            // but should not cause any trouble anymore..
                            break;
                        }
                         Field hookFld = wr.getClass().getDeclaredField("hook"); //NOI18N
                         hookFld.setAccessible(true);
                         Thread hook = (Thread) hookFld.get(wr);
                         if (hook.getThreadGroup() != null && hook.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
                             hook.start();
                             try {
                                 hook.join();
                             } catch (InterruptedException e) {
                                 
                             } finally {
                                 Runtime.getRuntime().removeShutdownHook(hook);
                             }
                         }
                    }
                }
            }
        }
        catch (Exception ex) {
            LOGGER.log(Level.INFO,
                "Error removing shutdown hook originated from Maven build. " + ex.getMessage(), //NOI18N
                ex);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy