Package org.mevenide.idea.global

Source Code of org.mevenide.idea.global.MavenManager$HomeResetter

/* ==========================================================================
* Copyright 2003-2004 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.mevenide.idea.global;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.JDOMExternalizer;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.log4j.Level;
import org.jdom.Element;
import org.mevenide.idea.util.FileUtils;
import org.mevenide.idea.util.components.AbstractApplicationComponent;
import org.mevenide.idea.util.ui.UIUtils;

/**
* This application component manages global Maven settings for IDEA.
*
* <p>Currently, only the Maven home settings is defined. In the future, we can define here the
* amount of memory to allocate for Maven processes (e.g. -Xms and -Xmx) and others.</p>
*
* @author Arik
* @todo allow setting custom Maven home per project
*/
public class MavenManager extends AbstractApplicationComponent implements JDOMExternalizable {
    /**
     * Jelly scripts extensions.
     */
    private static final String[] JELLY_EXTENSIONS = new String[]{"jelly"};

    /**
     * Used to synchronize calls to {@link #setMavenHome(String)} and {@link
     * #setMavenHome(com.intellij.openapi.vfs.VirtualFile)}.
     */
    private final Lock LOCK = new ReentrantLock();

    /**
     * Runnable that resets the maven home to null.
     */
    private final Runnable HOME_RESETTER = new HomeResetter();

    /**
     * Extra command line options to send to the Maven process.
     */
    private String mavenOptions;

    /**
     * Whether to activate Maven in offline mode.
     */
    private boolean offline = false;

    /**
     * The file watcher.
     */
    private LocalFileSystem.WatchRequest mavenHomeWatcher = null;

    /**
     * Detects external removal of maven home, and refreshes listeners.
     */
    private final VirtualFileAdapter FS_LISTENER = new VirtualFileAdapter() {
        @Override
        public void fileDeleted(VirtualFileEvent event) {
            LOCK.lock();
            try {
                if (mavenHomeWatcher == null)
                    return;

                final VirtualFile mavenHome = getMavenHome();
                if (mavenHome == null)
                    return;

                final String url = extractUrl(event);
                if (url == null || url.trim().length() == 0)
                    LOG.trace("Unknown file delete event - exiting.");
                else if (url.equalsIgnoreCase(mavenHome.getUrl()))
                    ApplicationManager.getApplication().invokeLater(HOME_RESETTER);
            }
            finally {
                LOCK.unlock();
            }
        }
    };

    /**
     * Returns the command line options to send to the Maven process when invoked.
     *
     * <p>This is the equivalent of <code>MAVEN_OPTS</code> environment variable.</p>
     *
     * @return string
     */
    public String getMavenOptions() {
        return mavenOptions;
    }

    /**
     * Sets the command line options to send to the Maven process invocations.
     *
     * <p>Invoking this method will cause a property-change event.</p>
     *
     * @param pMavenOptions the new maven command line options
     */
    public void setMavenOptions(final String pMavenOptions) {
        final String oldOptions = mavenOptions;

        if (pMavenOptions != null && pMavenOptions.trim().length() == 0)
            mavenOptions = null;
        else
            mavenOptions = pMavenOptions;

        changeSupport.firePropertyChange("mavenOptions", oldOptions, mavenOptions);
    }

    /**
     * Returns whether Maven will be executed in offline mode.
     *
     * @return boolean
     */
    public boolean isOffline() {
        return offline;
    }

    /**
     * Sets the offline/online mode for Maven executions.
     *
     * @param pOffline {@code true} for online, {@code false} for offline
     */
    public void setOffline(final boolean pOffline) {
        final boolean oldOffline = offline;
        offline = pOffline;
        changeSupport.firePropertyChange("offline", oldOffline, offline);
    }

    /**
     * Returns the selected Maven home, or <code>null</code> if not set.
     *
     * @return file pointing to the Maven directory, or <code>null</code>
     */
    public VirtualFile getMavenHome() {
        return mavenHomeWatcher == null ? null : mavenHomeWatcher.getRoot();
    }

    /**
     * Sets the Maven home to the specified directory. Throws a {@link FileNotFoundException} if the
     * specified home points to a file or does not exist.
     *
     * <p>Invoking this method will cause a property-change event.</p>
     *
     * @param pMavenHome the new Maven home - may be <code>null</code>
     */
    public void setMavenHome(final String pMavenHome) throws IllegalMavenHomeException {
        LOCK.lock();
        try {
            final VirtualFile home;
            if (pMavenHome == null || pMavenHome.trim().length() == 0)
                home = null;
            else {
                final String path = pMavenHome.replace(File.separatorChar, '/');
                final String url = "file://" + path;

                //
                //find a virtual-file for the given path. We disable our file-
                //system listener here, because the refreshAndFindFileByUrl
                //method causes the listener to be invoked, which will call this
                //method, hence causing an infinite loop.
                //
                LOG.trace("setMavenHome(String): validating existance of " + pMavenHome);
                final VirtualFileManager vfm = VirtualFileManager.getInstance();
                vfm.removeVirtualFileListener(FS_LISTENER);
                home = FileUtils.find(url);
                vfm.addVirtualFileListener(FS_LISTENER);

                //
                //if the file could not be found, throw an exception
                //
                LOG.trace("setMavenHome(String): found " + home);
                if (home == null || !FileUtils.exists(home))
                    throw new IllegalMavenHomeException(RES.get("illegal.maven.home", pMavenHome));
            }

            setMavenHome(home);
        }
        finally {
            LOCK.unlock();
        }
    }

    /**
     * Sets the Maven home to the specified directory. Throws a {@link FileNotFoundException} if the
     * specified home points to a file or does not exist.
     *
     * <p>Invoking this method will cause a property-change event.</p>
     *
     * @param pMavenHome the new Maven home - may be <code>null</code>
     */
    public void setMavenHome(final VirtualFile pMavenHome) throws IllegalMavenHomeException {
        LOCK.lock();
        try {
            LOG.trace("setMavenHome(VirtualFile): validating " + pMavenHome);
            validateMavenHome(pMavenHome);
            LOG.trace("setMavenHome(VirtualFile): validation passed for " + pMavenHome);

            final VirtualFile oldMavenHome = getMavenHome();
            if (mavenHomeWatcher != null)
                LocalFileSystem.getInstance().removeWatchedRoot(mavenHomeWatcher);
            if (pMavenHome != null)
                mavenHomeWatcher = LocalFileSystem.getInstance().addRootToWatch(pMavenHome, false);
            else
                mavenHomeWatcher = null;
            changeSupport.firePropertyChange("mavenHome", oldMavenHome, getMavenHome());
        }
        finally {
            LOCK.unlock();
        }
    }

    /**
     * Tries to guess the Maven home installation from the system environment. Since environment
     * entries on Windows are case-insensitive, and on UNIX system are case-sensitive, the check is
     * done in a case-insensitive manner.
     *
     * @return the maven home, or {@code null} if could not be detected
     */
    public VirtualFile guessMavenHome() {
        final Map<String, String> env = System.getenv();
        for (String key : env.keySet()) {
            if (key.equalsIgnoreCase("MAVEN_HOME")) {
                final String value = System.getenv(key);
                final String path = value.replace(File.separatorChar, '/');
                final VirtualFile dir = LocalFileSystem.getInstance().findFileByPath(path);
                if (dir == null || !dir.isValid() || !FileUtils.exists(dir) || !dir.isDirectory())
                    return null;

                return dir;
            }
        }

        return null;
    }

    public void initComponent() {
        VirtualFileManager.getInstance().addVirtualFileListener(FS_LISTENER);

        //
        //disable http-client logger as it is quite verbose
        //
        final Logger logger = Logger.getInstance(HttpMethodBase.class.getName());
        logger.setLevel(Level.ERROR);

        //
        //register the ".jelly" file extension as an XML file
        //
        FileTypeManager.getInstance().registerFileType(StdFileTypes.XML, JELLY_EXTENSIONS);
    }

    @Override
    public void disposeComponent() {
        VirtualFileManager.getInstance().removeVirtualFileListener(FS_LISTENER);
    }

    /**
     * Reads configuration from external storage.
     *
     * @param pElement XML element to read configuration from
     *
     * @throws InvalidDataException if an error occurs
     */
    public void readExternal(final Element pElement) throws InvalidDataException {
        //
        //read maven home
        //
        String mavenHomeValue = JDOMExternalizer.readString(pElement, "mavenHome");
        try {
            setMavenHome(mavenHomeValue);
        }
        catch (IllegalMavenHomeException e) {
            UIUtils.showError(e);
        }

        //
        //read maven options
        //
        final String mavenOptionsValue = JDOMExternalizer.readString(pElement, "mavenOptions");
        setMavenOptions(mavenOptionsValue);

        //
        //read maven offline mode
        //
        final boolean offline;
        String offlineValue = JDOMExternalizer.readString(pElement, "offline");
        if (offlineValue != null)
            offline = JDOMExternalizer.readBoolean(pElement, "offline");
        else {
            offlineValue = System.getProperty("maven.online.mode");
            offline = offlineValue != null && offlineValue.equalsIgnoreCase("true");
        }
        setOffline(offline);
    }

    /**
     * Writes configuration to external storage.
     *
     * @param pElement XML element to write configuration to
     *
     * @throws WriteExternalException if an error occurs
     */
    public void writeExternal(final Element pElement) throws WriteExternalException {
        //
        //write maven home
        //
        final VirtualFile mavenHome = getMavenHome();
        if (mavenHome != null)
            JDOMExternalizer.write(pElement, "mavenHome", mavenHome.getPath());
        else
            JDOMExternalizer.write(pElement, "mavenHome", null);

        //
        //write maven options
        //
        JDOMExternalizer.write(pElement, "mavenOptions", mavenOptions);

        //
        //write offline mode
        //
        JDOMExternalizer.write(pElement, "offline", offline);
    }

    private void validateMavenHome(VirtualFile pMavenHome) throws IllegalMavenHomeException {
        if (pMavenHome == null)
            return;

        final String url = pMavenHome.getPresentableUrl();
        if (!pMavenHome.isValid() || !FileUtils.exists(pMavenHome))
            throw new IllegalMavenHomeException(RES.get("illegal.maven.home", url));

        if (!pMavenHome.isDirectory())
            throw new IllegalMavenHomeException(RES.get("file.must.be.dir", url));

        final VirtualFile mavenLib = pMavenHome.findFileByRelativePath("lib/maven.jar");
        if (mavenLib == null || !mavenLib.isValid() || !FileUtils.exists(mavenLib) || mavenLib.isDirectory())
            throw new IllegalMavenHomeException(RES.get("illegal.maven.home", url));
    }

    /**
     * Returns an instance of this component.
     *
     * @return Maven manager instance
     */
    public static MavenManager getInstance() {
        return ApplicationManager.getApplication().getComponent(MavenManager.class);
    }

    private String extractUrl(final VirtualFileEvent event) {
        final VirtualFile parent = event.getParent();
        if (parent != null) {
            final StringBuilder buf = new StringBuilder(parent.getUrl());
            if (buf.charAt(buf.length() - 1) != '/')
                buf.append('/');
            buf.append(event.getFileName());
            return buf.toString();
        }
        else if (event.getFile() != null)
            return event.getFile().getUrl();
        else {
            LOG.trace("Could not extract url from event.");
            return null;
        }
    }

    private class HomeResetter implements Runnable {
        public void run() {
            try {
                LOG.trace("Detected Maven home deletion - setting Maven home to null");
                setMavenHome((VirtualFile) null);
            }
            catch (IllegalMavenHomeException e) {
                LOG.error(e, e);
            }
        }
    }
}
TOP

Related Classes of org.mevenide.idea.global.MavenManager$HomeResetter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.