org.jetbrains.idea.maven.utils.MavenUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.jetbrains.idea.maven.utils.MavenUtil.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * 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.jetbrains.idea.maven.utils;

import gnu.trove.THashSet;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.zip.CRC32;

import javax.annotation.Nonnull;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import javax.annotation.Nullable;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.model.MavenPlugin;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.server.MavenServerManager;
import org.jetbrains.idea.maven.server.MavenServerUtil;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import com.intellij.codeInsight.actions.ReformatCodeProcessor;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.execution.configurations.ParametersList;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.JarUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.DisposeAwareRunnable;
import com.intellij.util.Function;
import com.intellij.util.SystemProperties;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import consulo.awt.TargetAWT;
import consulo.java.module.extension.JavaModuleExtension;
import consulo.vfs.util.ArchiveVfsUtil;
import icons.MavenIcons;

public class MavenUtil {
    public static final String MAVEN_NOTIFICATION_GROUP = "Maven";
    public static final String SETTINGS_XML = "settings.xml";
    public static final String DOT_M2_DIR = ".m2";
    public static final String PROP_USER_HOME = "user.home";
    public static final String ENV_M2_HOME = "M2_HOME";
    public static final String M2_DIR = "m2";
    public static final String BIN_DIR = "bin";
    public static final String CONF_DIR = "conf";
    public static final String M2_CONF_FILE = "m2.conf";
    public static final String REPOSITORY_DIR = "repository";
    public static final String LIB_DIR = "lib";

    @SuppressWarnings("unchecked")
    private static final Pair<Pattern, String>[] SUPER_POM_PATHS = new Pair[] {
            Pair.create(Pattern.compile("maven-\\d+\\.\\d+\\.\\d+-uber\\.jar"),
                    "org/apache/maven/project/" + MavenConstants.SUPER_POM_XML),
            Pair.create(Pattern.compile("maven-model-builder-\\d+\\.\\d+\\.\\d+\\.jar"),
                    "org/apache/maven/model/" + MavenConstants.SUPER_POM_XML) };

    private static volatile Map<String, String> ourPropertiesFromMvnOpts;

    public static Map<String, String> getPropertiesFromMavenOpts() {
        Map<String, String> res = ourPropertiesFromMvnOpts;
        if (res == null) {
            String mavenOpts = System.getenv("MAVEN_OPTS");
            if (mavenOpts != null) {
                ParametersList mavenOptsList = new ParametersList();
                mavenOptsList.addParametersString(mavenOpts);
                res = mavenOptsList.getProperties();
            } else {
                res = Collections.emptyMap();
            }

            ourPropertiesFromMvnOpts = res;
        }

        return res;
    }

    public static void invokeLater(Project p, Runnable r) {
        invokeLater(p, ModalityState.defaultModalityState(), r);
    }

    public static void invokeLater(final Project p, final ModalityState state, final Runnable r) {
        if (isNoBackgroundMode()) {
            r.run();
        } else {
            ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state);
        }
    }

    public static void invokeAndWait(Project p, Runnable r) {
        invokeAndWait(p, ModalityState.defaultModalityState(), r);
    }

    public static void invokeAndWait(final Project p, final ModalityState state, final Runnable r) {
        if (isNoBackgroundMode()) {
            r.run();
        } else {
            if (ApplicationManager.getApplication().isDispatchThread()) {
                r.run();
            } else {
                ApplicationManager.getApplication().invokeAndWait(DisposeAwareRunnable.create(r, p), state);
            }
        }
    }

    public static void smartInvokeAndWait(final Project p, final ModalityState state, final Runnable r) {
        if (isNoBackgroundMode() || ApplicationManager.getApplication().isDispatchThread()) {
            r.run();
        } else {
            final Semaphore semaphore = new Semaphore();
            semaphore.down();
            DumbService.getInstance(p).smartInvokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        r.run();
                    } finally {
                        semaphore.up();
                    }
                }
            }, state);
            semaphore.waitFor();
        }
    }

    public static void invokeAndWaitWriteAction(Project p, final Runnable r) {
        invokeAndWait(p, new Runnable() {
            @Override
            public void run() {
                ApplicationManager.getApplication().runWriteAction(r);
            }
        });
    }

    public static void runDumbAware(final Project project, final Runnable r) {
        if (DumbService.isDumbAware(r)) {
            r.run();
        } else {
            DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project));
        }
    }

    public static void runWhenInitialized(final Project project, final Runnable r) {
        if (project.isDisposed()) {
            return;
        }

        if (isNoBackgroundMode()) {
            r.run();
            return;
        }

        if (!project.isInitialized()) {
            StartupManager.getInstance(project)
                    .registerPostStartupActivity(DisposeAwareRunnable.create(r, project));
            return;
        }

        runDumbAware(project, r);
    }

    public static boolean isNoBackgroundMode() {
        return (ApplicationManager.getApplication().isUnitTestMode()
                || ApplicationManager.getApplication().isHeadlessEnvironment());
    }

    public static boolean isInModalContext() {
        if (isNoBackgroundMode()) {
            return false;
        }
        return LaterInvocator.isInModalContext();
    }

    public static void showError(Project project, String title, Throwable e) {
        MavenLog.LOG.warn(title, e);
        Notifications.Bus.notify(
                new Notification(MAVEN_NOTIFICATION_GROUP, title, e.getMessage(), NotificationType.ERROR), project);
    }

    public static File getPluginSystemDir(String folder) {
        // PathManager.getSystemPath() may return relative path
        return new File(PathManager.getSystemPath(), "Maven" + "/" + folder).getAbsoluteFile();
    }

    @Nullable
    public static VirtualFile findProfilesXmlFile(@javax.annotation.Nullable VirtualFile pomFile) {
        if (pomFile == null) {
            return null;
        }
        VirtualFile parent = pomFile.getParent();
        if (parent == null) {
            return null;
        }
        return parent.findChild(MavenConstants.PROFILES_XML);
    }

    @javax.annotation.Nullable
    public static File getProfilesXmlIoFile(VirtualFile pomFile) {
        if (pomFile == null) {
            return null;
        }
        VirtualFile parent = pomFile.getParent();
        if (parent == null) {
            return null;
        }
        return new File(parent.getPath(), MavenConstants.PROFILES_XML);
    }

    public static <T, U> List<T> collectFirsts(List<Pair<T, U>> pairs) {
        List<T> result = new ArrayList<T>(pairs.size());
        for (Pair<T, ?> each : pairs) {
            result.add(each.first);
        }
        return result;
    }

    public static <T, U> List<U> collectSeconds(List<Pair<T, U>> pairs) {
        List<U> result = new ArrayList<U>(pairs.size());
        for (Pair<T, U> each : pairs) {
            result.add(each.second);
        }
        return result;
    }

    public static List<String> collectPaths(List<VirtualFile> files) {
        return ContainerUtil.map(files, new Function<VirtualFile, String>() {
            @Override
            public String fun(VirtualFile file) {
                return file.getPath();
            }
        });
    }

    public static List<VirtualFile> collectFiles(Collection<MavenProject> projects) {
        return ContainerUtil.map(projects, new Function<MavenProject, VirtualFile>() {
            @Override
            public VirtualFile fun(MavenProject project) {
                return project.getFile();
            }
        });
    }

    public static <T> boolean equalAsSets(final Collection<T> collection1, final Collection<T> collection2) {
        return toSet(collection1).equals(toSet(collection2));
    }

    private static <T> Collection<T> toSet(final Collection<T> collection) {
        return (collection instanceof Set ? collection : new THashSet<T>(collection));
    }

    public static <T, U> List<Pair<T, U>> mapToList(Map<T, U> map) {
        return ContainerUtil.map2List(map.entrySet(), new Function<Map.Entry<T, U>, Pair<T, U>>() {
            @Override
            public Pair<T, U> fun(Map.Entry<T, U> tuEntry) {
                return Pair.create(tuEntry.getKey(), tuEntry.getValue());
            }
        });
    }

    public static String formatHtmlImage(URL url) {
        return "<img src=\"" + url + "\"> ";
    }

    public static void runOrApplyMavenProjectFileTemplate(Project project, VirtualFile file,
            @Nonnull MavenId projectId, boolean interactive) throws IOException {
        runOrApplyMavenProjectFileTemplate(project, file, projectId, null, null, interactive);
    }

    public static void runOrApplyMavenProjectFileTemplate(Project project, VirtualFile file,
            @Nonnull MavenId projectId, MavenId parentId, VirtualFile parentFile, boolean interactive)
            throws IOException {
        Properties properties = new Properties();
        Properties conditions = new Properties();
        properties.setProperty("GROUP_ID", projectId.getGroupId());
        properties.setProperty("ARTIFACT_ID", projectId.getArtifactId());
        properties.setProperty("VERSION", projectId.getVersion());
        if (parentId != null) {
            conditions.setProperty("HAS_PARENT", "true");
            properties.setProperty("PARENT_GROUP_ID", parentId.getGroupId());
            properties.setProperty("PARENT_ARTIFACT_ID", parentId.getArtifactId());
            properties.setProperty("PARENT_VERSION", parentId.getVersion());

            if (parentFile != null) {
                VirtualFile modulePath = file.getParent();
                VirtualFile parentModulePath = parentFile.getParent();

                if (!Comparing.equal(modulePath.getParent(), parentModulePath)) {
                    String relativePath = VfsUtil.getPath(file, parentModulePath, '/');
                    if (relativePath != null) {
                        if (relativePath.endsWith("/")) {
                            relativePath = relativePath.substring(0, relativePath.length() - 1);
                        }

                        conditions.setProperty("HAS_RELATIVE_PATH", "true");
                        properties.setProperty("PARENT_RELATIVE_PATH", relativePath);
                    }
                }
            }
        }
        runOrApplyFileTemplate(project, file, MavenFileTemplateGroupFactory.MAVEN_PROJECT_XML_TEMPLATE, properties,
                conditions, interactive);
    }

    public static void runFileTemplate(Project project, VirtualFile file, String templateName) throws IOException {
        runOrApplyFileTemplate(project, file, templateName, new Properties(), new Properties(), true);
    }

    private static void runOrApplyFileTemplate(Project project, VirtualFile file, String templateName,
            Properties properties, Properties conditions, boolean interactive) throws IOException {
        FileTemplateManager manager = FileTemplateManager.getInstance();
        FileTemplate fileTemplate = manager.getJ2eeTemplate(templateName);
        Properties allProperties = manager.getDefaultProperties();
        if (!interactive) {
            allProperties.putAll(properties);
        }
        allProperties.putAll(conditions);
        String text = fileTemplate.getText(allProperties);
        Pattern pattern = Pattern.compile("\\$\\{(.*)\\}");
        Matcher matcher = pattern.matcher(text);
        StringBuffer builder = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(builder, "\\$" + matcher.group(1).toUpperCase() + "\\$");
        }
        matcher.appendTail(builder);
        text = builder.toString();

        TemplateImpl template = (TemplateImpl) TemplateManager.getInstance(project).createTemplate("", "", text);
        for (int i = 0; i < template.getSegmentsCount(); i++) {
            if (i == template.getEndSegmentNumber()) {
                continue;
            }
            String name = template.getSegmentName(i);
            String value = "\"" + properties.getProperty(name, "") + "\"";
            template.addVariable(name, value, value, true);
        }

        if (interactive) {
            OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file);
            Editor editor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
            editor.getDocument().setText("");
            TemplateManager.getInstance(project).startTemplate(editor, template);
        } else {
            VfsUtil.saveText(file, template.getTemplateText());

            PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
            if (psiFile != null) {
                new ReformatCodeProcessor(project, psiFile, null, false).run();
            }
        }
    }

    public static <T extends Collection<Pattern>> T collectPattern(String text, T result) {
        String antPattern = FileUtil.convertAntToRegexp(text.trim());
        try {
            result.add(Pattern.compile(antPattern));
        } catch (PatternSyntaxException ignore) {
        }
        return result;
    }

    public static boolean isIncluded(String relativeName, List<Pattern> includes, List<Pattern> excludes) {
        boolean result = false;
        for (Pattern each : includes) {
            if (each.matcher(relativeName).matches()) {
                result = true;
                break;
            }
        }
        if (!result) {
            return false;
        }
        for (Pattern each : excludes) {
            if (each.matcher(relativeName).matches()) {
                return false;
            }
        }
        return true;
    }

    public static void run(Project project, String title, final MavenTask task)
            throws MavenProcessCanceledException {
        final Exception[] canceledEx = new Exception[1];
        final RuntimeException[] runtimeEx = new RuntimeException[1];
        final Error[] errorEx = new Error[1];

        ProgressManager.getInstance().run(new Task.Modal(project, title, true) {
            @Override
            public void run(@Nonnull ProgressIndicator i) {
                try {
                    task.run(new MavenProgressIndicator(i));
                } catch (MavenProcessCanceledException e) {
                    canceledEx[0] = e;
                } catch (ProcessCanceledException e) {
                    canceledEx[0] = e;
                } catch (RuntimeException e) {
                    runtimeEx[0] = e;
                } catch (Error e) {
                    errorEx[0] = e;
                }
            }
        });
        if (canceledEx[0] instanceof MavenProcessCanceledException) {
            throw (MavenProcessCanceledException) canceledEx[0];
        }
        if (canceledEx[0] instanceof ProcessCanceledException) {
            throw new MavenProcessCanceledException();
        }

        if (runtimeEx[0] != null) {
            throw runtimeEx[0];
        }
        if (errorEx[0] != null) {
            throw errorEx[0];
        }
    }

    public static MavenTaskHandler runInBackground(final Project project, final String title,
            final boolean cancellable, final MavenTask task) {
        final MavenProgressIndicator indicator = new MavenProgressIndicator();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (project.isDisposed()) {
                    return;
                }

                try {
                    task.run(indicator);
                } catch (MavenProcessCanceledException ignore) {
                    indicator.cancel();
                } catch (ProcessCanceledException ignore) {
                    indicator.cancel();
                }
            }
        };

        if (isNoBackgroundMode()) {
            runnable.run();
            return new MavenTaskHandler() {
                @Override
                public void waitFor() {
                }
            };
        } else {
            final Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(runnable);
            final MavenTaskHandler handler = new MavenTaskHandler() {
                @Override
                public void waitFor() {
                    try {
                        future.get();
                    } catch (InterruptedException e) {
                        MavenLog.LOG.error(e);
                    } catch (ExecutionException e) {
                        MavenLog.LOG.error(e);
                    }
                }
            };
            invokeLater(project, new Runnable() {
                @Override
                public void run() {
                    if (future.isDone()) {
                        return;
                    }
                    new Task.Backgroundable(project, title, cancellable) {
                        @Override
                        public void run(@Nonnull ProgressIndicator i) {
                            indicator.setIndicator(i);
                            handler.waitFor();
                        }
                    }.queue();
                }
            });
            return handler;
        }
    }

    @javax.annotation.Nullable
    public static File resolveMavenHomeDirectory(@javax.annotation.Nullable String overrideMavenHome) {
        if (!isEmptyOrSpaces(overrideMavenHome)) {
            return MavenServerManager.getInstance().getMavenHomeFile(overrideMavenHome);
        }

        String m2home = System.getenv(ENV_M2_HOME);
        if (!isEmptyOrSpaces(m2home)) {
            final File homeFromEnv = new File(m2home);
            if (isValidMavenHome(homeFromEnv)) {
                return homeFromEnv;
            }
        }

        String mavenHome = System.getenv("MAVEN_HOME");
        if (!isEmptyOrSpaces(mavenHome)) {
            final File mavenHomeFile = new File(mavenHome);
            if (isValidMavenHome(mavenHomeFile)) {
                return mavenHomeFile;
            }
        }

        String userHome = SystemProperties.getUserHome();
        if (!isEmptyOrSpaces(userHome)) {
            final File underUserHome = new File(userHome, M2_DIR);
            if (isValidMavenHome(underUserHome)) {
                return underUserHome;
            }
        }

        if (SystemInfo.isMac) {
            File home = fromBrew();
            if (home != null) {
                return home;
            }

            if ((home = fromMacSystemJavaTools()) != null) {
                return home;
            }
        } else if (SystemInfo.isLinux) {
            File home = new File("/usr/share/maven");
            if (isValidMavenHome(home)) {
                return home;
            }

            home = new File("/usr/share/maven2");
            if (isValidMavenHome(home)) {
                return home;
            }
        }

        return MavenServerManager.getInstance().getMavenHomeFile(MavenServerManager.BUNDLED_MAVEN_3);
    }

    @Nullable
    private static File fromMacSystemJavaTools() {
        final File symlinkDir = new File("/usr/share/maven");
        if (isValidMavenHome(symlinkDir)) {
            return symlinkDir;
        }

        // well, try to search
        final File dir = new File("/usr/share/java");
        final String[] list = dir.list();
        if (list == null || list.length == 0) {
            return null;
        }

        String home = null;
        final String prefix = "maven-";
        final int versionIndex = prefix.length();
        for (String path : list) {
            if (path.startsWith(prefix) && (home == null || StringUtil
                    .compareVersionNumbers(path.substring(versionIndex), home.substring(versionIndex)) > 0)) {
                home = path;
            }
        }

        if (home != null) {
            File file = new File(dir, home);
            if (isValidMavenHome(file)) {
                return file;
            }
        }

        return null;
    }

    @javax.annotation.Nullable
    private static File fromBrew() {
        final File brewDir = new File("/usr/local/Cellar/maven");
        final String[] list = brewDir.list();
        if (list == null || list.length == 0) {
            return null;
        }

        if (list.length > 1) {
            Arrays.sort(list, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return StringUtil.compareVersionNumbers(o2, o1);
                }
            });
        }

        final File file = new File(brewDir, list[0] + "/libexec");
        return isValidMavenHome(file) ? file : null;
    }

    public static boolean isEmptyOrSpaces(@javax.annotation.Nullable String str) {
        return str == null || str.length() == 0 || str.trim().length() == 0;
    }

    public static boolean isValidMavenHome(File home) {
        return getMavenConfFile(home).exists();
    }

    public static File getMavenConfFile(File mavenHome) {
        return new File(new File(mavenHome, BIN_DIR), M2_CONF_FILE);
    }

    @Nullable
    public static String getMavenVersion(@javax.annotation.Nullable File mavenHome) {
        if (mavenHome == null) {
            return null;
        }
        String[] libs = new File(mavenHome, "lib").list();

        if (libs != null) {
            for (String lib : libs) {
                if (lib.startsWith("maven-core-") && lib.endsWith(".jar")) {
                    String version = lib.substring("maven-core-".length(), lib.length() - ".jar".length());
                    if (StringUtil.contains(version, ".x")) {
                        Properties props = JarUtil.loadProperties(new File(mavenHome, "lib/" + lib),
                                "META-INF/maven/org.apache.maven/maven-core/pom.properties");
                        return props != null ? props.getProperty("version") : null;
                    } else {
                        return version;
                    }
                }
                if (lib.startsWith("maven-") && lib.endsWith("-uber.jar")) {
                    return lib.substring("maven-".length(), lib.length() - "-uber.jar".length());
                }
            }
        }
        return null;
    }

    @javax.annotation.Nullable
    public static String getMavenVersion(String mavenHome) {
        return getMavenVersion(new File(mavenHome));
    }

    public static boolean isMaven3(String mavenHome) {
        String version = getMavenVersion(mavenHome);
        return version != null && version.compareTo("3.0.0") >= 0;
    }

    @Nullable
    public static File resolveGlobalSettingsFile(@javax.annotation.Nullable String overriddenMavenHome) {
        File directory = resolveMavenHomeDirectory(overriddenMavenHome);
        return new File(new File(directory, CONF_DIR), SETTINGS_XML);
    }

    @Nonnull
    public static File resolveUserSettingsFile(@Nullable String overriddenUserSettingsFile) {
        if (!isEmptyOrSpaces(overriddenUserSettingsFile)) {
            return new File(overriddenUserSettingsFile);
        }
        return new File(resolveM2Dir(), SETTINGS_XML);
    }

    @Nonnull
    public static File resolveM2Dir() {
        return new File(SystemProperties.getUserHome(), DOT_M2_DIR);
    }

    @Nonnull
    public static File resolveLocalRepository(@javax.annotation.Nullable String overriddenLocalRepository,
            @javax.annotation.Nullable String overriddenMavenHome,
            @javax.annotation.Nullable String overriddenUserSettingsFile) {
        File result = null;
        if (!isEmptyOrSpaces(overriddenLocalRepository)) {
            result = new File(overriddenLocalRepository);
        }
        if (result == null) {
            result = doResolveLocalRepository(resolveUserSettingsFile(overriddenUserSettingsFile),
                    resolveGlobalSettingsFile(overriddenMavenHome));
        }
        try {
            return result.getCanonicalFile();
        } catch (IOException e) {
            return result;
        }
    }

    @Nonnull
    public static File doResolveLocalRepository(@javax.annotation.Nullable File userSettingsFile,
            @javax.annotation.Nullable File globalSettingsFile) {
        if (userSettingsFile != null) {
            final String fromUserSettings = getRepositoryFromSettings(userSettingsFile);
            if (!StringUtil.isEmpty(fromUserSettings)) {
                return new File(fromUserSettings);
            }
        }

        if (globalSettingsFile != null) {
            final String fromGlobalSettings = getRepositoryFromSettings(globalSettingsFile);
            if (!StringUtil.isEmpty(fromGlobalSettings)) {
                return new File(fromGlobalSettings);
            }
        }

        return new File(resolveM2Dir(), REPOSITORY_DIR);
    }

    @Nullable
    public static String getRepositoryFromSettings(final File file) {
        try {
            byte[] bytes = FileUtil.loadFileBytes(file);
            return expandProperties(
                    MavenJDOMUtil.findChildValueByPath(MavenJDOMUtil.read(bytes, null), "localRepository", null));
        } catch (IOException e) {
            return null;
        }
    }

    public static String expandProperties(String text) {
        if (StringUtil.isEmptyOrSpaces(text)) {
            return text;
        }
        Properties props = MavenServerUtil.collectSystemProperties();
        for (Map.Entry<Object, Object> each : props.entrySet()) {
            Object val = each.getValue();
            text = text.replace("${" + each.getKey() + "}",
                    val instanceof CharSequence ? (CharSequence) val : val.toString());
        }
        return text;
    }

    @javax.annotation.Nullable
    public static VirtualFile resolveSuperPomFile(@javax.annotation.Nullable File mavenHome) {
        VirtualFile result = null;
        if (mavenHome != null) {
            result = doResolveSuperPomFile(new File(mavenHome, LIB_DIR));
        }
        return result == null ? doResolveSuperPomFile(MavenServerManager.getMavenLibDirectory()) : result;
    }

    @Nullable
    public static VirtualFile doResolveSuperPomFile(@Nonnull File mavenHome) {
        File[] files = mavenHome.listFiles();
        if (files == null) {
            return null;
        }

        for (File library : files) {

            for (Pair<Pattern, String> path : SUPER_POM_PATHS) {
                if (path.first.matcher(library.getName()).matches()) {
                    VirtualFile libraryVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(library);
                    if (libraryVirtualFile == null) {
                        continue;
                    }

                    VirtualFile root = ArchiveVfsUtil.getJarRootForLocalFile(libraryVirtualFile);
                    if (root == null) {
                        continue;
                    }

                    VirtualFile pomFile = root.findFileByRelativePath(path.second);
                    if (pomFile != null) {
                        return pomFile;
                    }
                }
            }
        }

        return null;
    }

    public static List<LookupElement> getPhaseVariants(MavenProjectsManager manager) {
        Set<String> goals = new HashSet<String>();
        goals.addAll(MavenConstants.PHASES);

        for (MavenProject mavenProject : manager.getProjects()) {
            for (MavenPlugin plugin : mavenProject.getPlugins()) {
                MavenPluginInfo pluginInfo = MavenArtifactUtil.readPluginInfo(manager.getLocalRepository(),
                        plugin.getMavenId());
                if (pluginInfo != null) {
                    for (MavenPluginInfo.Mojo mojo : pluginInfo.getMojos()) {
                        goals.add(mojo.getDisplayName());
                    }
                }
            }
        }

        List<LookupElement> res = new ArrayList<LookupElement>(goals.size());
        for (String goal : goals) {
            res.add(LookupElementBuilder.create(goal).withIcon(TargetAWT.to(MavenIcons.Phase)));
        }

        return res;
    }

    public interface MavenTaskHandler {
        void waitFor();
    }

    public static int crcWithoutSpaces(@Nonnull InputStream in) throws IOException {
        try {
            final CRC32 crc = new CRC32();

            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();

            parser.parse(in, new DefaultHandler() {

                boolean textContentOccur = false;
                int spacesCrc;

                private void putString(@javax.annotation.Nullable String string) {
                    if (string == null) {
                        return;
                    }

                    for (int i = 0, end = string.length(); i < end; i++) {
                        crc.update(string.charAt(i));
                    }
                }

                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes)
                        throws SAXException {
                    textContentOccur = false;

                    crc.update(1);
                    putString(qName);

                    for (int i = 0; i < attributes.getLength(); i++) {
                        putString(attributes.getQName(i));
                        putString(attributes.getValue(i));
                    }
                }

                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    textContentOccur = false;

                    crc.update(2);
                    putString(qName);
                }

                private void processTextOrSpaces(char[] ch, int start, int length) {
                    for (int i = start, end = start + length; i < end; i++) {
                        char a = ch[i];

                        if (Character.isWhitespace(a)) {
                            if (textContentOccur) {
                                spacesCrc = spacesCrc * 31 + a;
                            }
                        } else {
                            if (textContentOccur && spacesCrc != 0) {
                                crc.update(spacesCrc);
                                crc.update(spacesCrc >> 8);
                            }

                            crc.update(a);

                            textContentOccur = true;
                            spacesCrc = 0;
                        }
                    }
                }

                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    processTextOrSpaces(ch, start, length);
                }

                @Override
                public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
                    processTextOrSpaces(ch, start, length);
                }

                @Override
                public void processingInstruction(String target, String data) throws SAXException {
                    putString(target);
                    putString(data);
                }

                @Override
                public void skippedEntity(String name) throws SAXException {
                    putString(name);
                }

                @Override
                public void error(SAXParseException e) throws SAXException {
                    crc.update(100);
                }
            });

            return (int) crc.getValue();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            return -1;
        }
    }

    public static int crcWithoutSpaces(@Nonnull VirtualFile xmlFile) throws IOException {
        InputStream inputStream = xmlFile.getInputStream();
        try {
            return crcWithoutSpaces(inputStream);
        } finally {
            inputStream.close();
        }
    }

    public static String getSdkPath(@javax.annotation.Nullable Sdk sdk) {
        if (sdk == null) {
            return null;
        }

        VirtualFile homeDirectory = sdk.getHomeDirectory();
        if (homeDirectory == null) {
            return null;
        }

        if (!"jre".equals(homeDirectory.getName())) {
            VirtualFile jreDir = homeDirectory.findChild("jre");
            if (jreDir != null) {
                homeDirectory = jreDir;
            }
        }

        return homeDirectory.getPath();
    }

    @javax.annotation.Nullable
    public static String getModuleJreHome(@Nonnull MavenProjectsManager mavenProjectsManager,
            @Nonnull MavenProject mavenProject) {
        return getSdkPath(getModuleJdk(mavenProjectsManager, mavenProject));
    }

    @javax.annotation.Nullable
    public static String getModuleJavaVersion(@Nonnull MavenProjectsManager mavenProjectsManager,
            @Nonnull MavenProject mavenProject) {
        Sdk sdk = getModuleJdk(mavenProjectsManager, mavenProject);
        if (sdk == null) {
            return null;
        }

        return sdk.getVersionString();
    }

    @javax.annotation.Nullable
    public static Sdk getModuleJdk(@Nonnull MavenProjectsManager mavenProjectsManager,
            @Nonnull MavenProject mavenProject) {
        Module module = mavenProjectsManager.findModule(mavenProject);
        if (module == null) {
            return null;
        }

        return ModuleUtilCore.getSdk(module, JavaModuleExtension.class);
    }

    @Nonnull
    public static <K, V extends Map> V getOrCreate(Map map, K key) {
        Map res = (Map) map.get(key);
        if (res == null) {
            res = new HashMap();
            map.put(key, res);
        }

        return (V) res;
    }

    public static String getArtifactName(String packaging, Module module, boolean exploded) {
        return module.getName() + ":" + packaging + (exploded ? " exploded" : "");
    }

    public static String getEjbClientArtifactName(Module module) {
        return module.getName() + ":ejb-client";
    }

    public static String getIdeaVersionToPassToMavenProcess() {
        return ApplicationInfoImpl.getShadowInstance().getMajorVersion() + "."
                + ApplicationInfoImpl.getShadowInstance().getMinorVersion();
    }
}