org.jetbrains.idea.maven.utils.library.RepositoryAttachHandler.java Source code

Java tutorial

Introduction

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

Source

/*
 * Copyright 2000-2010 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.library;

import com.intellij.CommonBundle;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.NewLibraryConfiguration;
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryEditor;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.PairProcessor;
import com.intellij.util.Processor;
import com.intellij.util.SmartList;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jetbrains.idea.maven.execution.SoutMavenConsole;
import org.jetbrains.idea.maven.importing.MavenExtraArtifactType;
import org.jetbrains.idea.maven.model.*;
import org.jetbrains.idea.maven.project.MavenEmbeddersManager;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.server.MavenEmbedderWrapper;
import org.jetbrains.idea.maven.services.MavenRepositoryServicesManager;
import org.jetbrains.idea.maven.utils.MavenLog;
import org.jetbrains.idea.maven.utils.MavenProcessCanceledException;
import org.jetbrains.idea.maven.utils.MavenProgressIndicator;
import org.jetbrains.idea.maven.utils.RepositoryAttachDialog;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Gregory.Shrago
 */
public class RepositoryAttachHandler {

    @Nullable
    public static NewLibraryConfiguration chooseLibraryAndDownload(final @Nonnull Project project,
            final @Nullable String initialFilter, JComponent parentComponent) {
        final RepositoryAttachDialog dialog = new RepositoryAttachDialog(project, false, initialFilter);
        dialog.setTitle("Download Library From Maven Repository");
        dialog.show();
        if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) {
            return null;
        }

        final String copyTo = dialog.getDirectoryPath();
        final String coord = dialog.getCoordinateText();
        final boolean attachJavaDoc = dialog.getAttachJavaDoc();
        final boolean attachSources = dialog.getAttachSources();
        final SmartList<MavenExtraArtifactType> extraTypes = new SmartList<MavenExtraArtifactType>();
        if (attachSources)
            extraTypes.add(MavenExtraArtifactType.SOURCES);
        if (attachJavaDoc)
            extraTypes.add(MavenExtraArtifactType.DOCS);
        final Ref<NewLibraryConfiguration> result = Ref.create(null);
        resolveLibrary(project, coord, extraTypes, dialog.getRepositories(), new Processor<List<MavenArtifact>>() {
            public boolean process(final List<MavenArtifact> artifacts) {
                if (!artifacts.isEmpty()) {
                    AccessToken accessToken = WriteAction.start();
                    try {
                        final List<OrderRoot> roots = createRoots(artifacts, copyTo);
                        result.set(new NewLibraryConfiguration(coord, RepositoryLibraryType.getInstance(),
                                new RepositoryLibraryProperties(coord)) {
                            @Override
                            public void addRoots(@Nonnull LibraryEditor editor) {
                                editor.addRoots(roots);
                            }
                        });
                    } finally {
                        accessToken.finish();
                    }

                    final StringBuilder sb = new StringBuilder();
                    final String title = "The following files were downloaded:";
                    sb.append("<ol>");
                    for (MavenArtifact each : artifacts) {
                        sb.append("<li>");
                        sb.append(each.getFile().getName());
                        final String scope = each.getScope();
                        if (scope != null) {
                            sb.append(" (");
                            sb.append(scope);
                            sb.append(")");
                        }
                        sb.append("</li>");
                    }
                    sb.append("</ol>");
                    Notifications.Bus.notify(
                            new Notification("Repository", title, sb.toString(), NotificationType.INFORMATION),
                            project);
                }
                return true;
            }
        });

        NewLibraryConfiguration configuration = result.get();
        if (configuration == null) {
            Messages.showErrorDialog(parentComponent, "No files were downloaded for " + coord,
                    CommonBundle.getErrorTitle());
        }
        return configuration;
    }

    private static List<OrderRoot> createRoots(Collection<MavenArtifact> artifacts, String copyTo) {
        final List<OrderRoot> result = new ArrayList<OrderRoot>();
        final VirtualFileManager manager = VirtualFileManager.getInstance();
        for (MavenArtifact each : artifacts) {
            try {
                File repoFile = each.getFile();
                File toFile = repoFile;
                if (copyTo != null) {
                    toFile = new File(copyTo, repoFile.getName());
                    if (repoFile.exists()) {
                        FileUtil.copy(repoFile, toFile);
                    }
                }
                // search for jar file first otherwise lib root won't be found!
                manager.refreshAndFindFileByUrl(
                        VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(toFile.getPath())));
                final String url = VfsUtil.getUrlForLibraryRoot(toFile);
                final VirtualFile file = manager.refreshAndFindFileByUrl(url);
                if (file != null) {
                    OrderRootType rootType;
                    if (MavenExtraArtifactType.DOCS.getDefaultClassifier().equals(each.getClassifier())) {
                        rootType = OrderRootType.DOCUMENTATION;
                    } else if (MavenExtraArtifactType.SOURCES.getDefaultClassifier().equals(each.getClassifier())) {
                        rootType = OrderRootType.SOURCES;
                    } else {
                        rootType = OrderRootType.CLASSES;
                    }
                    result.add(new OrderRoot(file, rootType));
                }
            } catch (MalformedURLException e) {
                MavenLog.LOG.warn(e);
            } catch (IOException e) {
                MavenLog.LOG.warn(e);
            }
        }
        return result;
    }

    public static void searchArtifacts(final Project project, String coord,
            final PairProcessor<Collection<Pair<MavenArtifactInfo, MavenRepositoryInfo>>, Boolean> resultProcessor) {
        if (coord == null || coord.length() == 0)
            return;
        final MavenArtifactInfo template;
        if (coord.indexOf(':') == -1 && Character.isUpperCase(coord.charAt(0))) {
            template = new MavenArtifactInfo(null, null, null, "jar", null, coord, null);
        } else {
            template = new MavenArtifactInfo(getMavenId(coord), "jar", null);
        }
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Maven", false) {

            public void run(@Nonnull ProgressIndicator indicator) {
                String[] urls = MavenRepositoryServicesManager.getServiceUrls();
                boolean tooManyResults = false;
                final AtomicBoolean proceedFlag = new AtomicBoolean(true);

                for (int i = 0, length = urls.length; i < length; i++) {
                    if (!proceedFlag.get())
                        break;
                    final List<Pair<MavenArtifactInfo, MavenRepositoryInfo>> resultList = new ArrayList<Pair<MavenArtifactInfo, MavenRepositoryInfo>>();
                    try {
                        String serviceUrl = urls[i];
                        final List<MavenArtifactInfo> artifacts;
                        artifacts = MavenRepositoryServicesManager.findArtifacts(template, serviceUrl);
                        if (!artifacts.isEmpty()) {
                            if (!proceedFlag.get())
                                break;
                            final List<MavenRepositoryInfo> repositories = MavenRepositoryServicesManager
                                    .getRepositories(serviceUrl);
                            final HashMap<String, MavenRepositoryInfo> map = new HashMap<String, MavenRepositoryInfo>();
                            for (MavenRepositoryInfo repository : repositories) {
                                map.put(repository.getId(), repository);
                            }
                            for (MavenArtifactInfo artifact : artifacts) {
                                if (artifact == null) {
                                    tooManyResults = true;
                                } else {
                                    resultList.add(Pair.create(artifact, map.get(artifact.getRepositoryId())));
                                }
                            }
                        }
                    } catch (Exception e) {
                        MavenLog.LOG.error(e);
                    } finally {
                        if (!proceedFlag.get())
                            break;
                        final Boolean aBoolean = i == length - 1 ? tooManyResults : null;
                        ApplicationManager.getApplication().invokeLater(new Runnable() {
                            public void run() {
                                proceedFlag.set(resultProcessor.process(resultList, aBoolean));
                            }
                        }, new Condition() {
                            @Override
                            public boolean value(Object o) {
                                return !proceedFlag.get();
                            }
                        });
                    }
                }
            }
        });
    }

    public static void searchRepositories(final Project project, final Collection<String> nexusUrls,
            final Processor<Collection<MavenRepositoryInfo>> resultProcessor) {
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Maven", false) {

            public void run(@Nonnull ProgressIndicator indicator) {
                final Ref<List<MavenRepositoryInfo>> result = Ref
                        .create(Collections.<MavenRepositoryInfo>emptyList());
                try {
                    final ArrayList<MavenRepositoryInfo> repoList = new ArrayList<MavenRepositoryInfo>();
                    for (String nexusUrl : nexusUrls) {
                        final List<MavenRepositoryInfo> repositories;
                        try {
                            repositories = MavenRepositoryServicesManager.getRepositories(nexusUrl);
                        } catch (Exception ex) {
                            MavenLog.LOG.warn("Accessing Service at: " + nexusUrl, ex);
                            continue;
                        }
                        repoList.addAll(repositories);
                    }
                    result.set(repoList);
                } catch (Exception e) {
                    MavenLog.LOG.error(e);
                } finally {
                    ApplicationManager.getApplication().invokeLater(new Runnable() {
                        public void run() {
                            resultProcessor.process(result.get());
                        }
                    });
                }
            }
        });
    }

    private static void resolveLibrary(final Project project, final String coord,
            final List<MavenExtraArtifactType> extraTypes, final Collection<MavenRepositoryInfo> repositories,
            final Processor<List<MavenArtifact>> resultProcessor) {
        final MavenId mavenId = getMavenId(coord);
        final Task task = new Task.Modal(project, "Maven", false) {
            public void run(@Nonnull ProgressIndicator indicator) {
                doResolveInner(project, mavenId, extraTypes, repositories, resultProcessor, indicator);
            }
        };
        ProgressManager.getInstance().run(task);
    }

    private static void doResolveInner(Project project, MavenId mavenId, List<MavenExtraArtifactType> extraTypes,
            Collection<MavenRepositoryInfo> repositories, final Processor<List<MavenArtifact>> resultProcessor,
            ProgressIndicator indicator) {
        boolean cancelled = false;
        final Collection<MavenArtifact> result = new LinkedHashSet<MavenArtifact>();
        MavenEmbeddersManager manager = MavenProjectsManager.getInstance(project).getEmbeddersManager();
        MavenEmbedderWrapper embedder = manager.getEmbedder(MavenEmbeddersManager.FOR_DOWNLOAD);
        try {
            embedder.customizeForResolve(new SoutMavenConsole(), new MavenProgressIndicator(indicator));
            final List<MavenRemoteRepository> remoteRepositories = convertRepositories(repositories);
            final List<MavenArtifact> firstResult = embedder.resolveTransitively(
                    Collections.singletonList(new MavenArtifactInfo(mavenId, "jar", null)), remoteRepositories);
            for (MavenArtifact artifact : firstResult) {
                if (!artifact.isResolved())
                    continue;
                if (MavenConstants.SCOPE_TEST.equals(artifact.getScope()))
                    continue;
                result.add(artifact);
            }
            // download docs & sources
            if (!extraTypes.isEmpty()) {
                final HashSet<String> allowedClassifiers = new HashSet<String>();
                final Collection<MavenArtifactInfo> resolve = new LinkedHashSet<MavenArtifactInfo>();
                for (MavenExtraArtifactType extraType : extraTypes) {
                    allowedClassifiers.add(extraType.getDefaultClassifier());
                    resolve.add(new MavenArtifactInfo(mavenId, extraType.getDefaultExtension(),
                            extraType.getDefaultClassifier()));
                    for (MavenArtifact artifact : firstResult) {
                        if (MavenConstants.SCOPE_TEST.equals(artifact.getScope()))
                            continue;
                        resolve.add(new MavenArtifactInfo(artifact.getMavenId(), extraType.getDefaultExtension(),
                                extraType.getDefaultClassifier()));
                    }
                }
                final List<MavenArtifact> secondResult = embedder
                        .resolveTransitively(new ArrayList<MavenArtifactInfo>(resolve), remoteRepositories);
                for (MavenArtifact artifact : secondResult) {
                    if (!artifact.isResolved())
                        continue;
                    if (MavenConstants.SCOPE_TEST.equals(artifact.getScope()))
                        continue;
                    if (!allowedClassifiers.contains(artifact.getClassifier()))
                        continue;
                    result.add(artifact);
                }
            }
        } catch (MavenProcessCanceledException e) {
            cancelled = true;
        } finally {
            manager.release(embedder);
            if (!cancelled) {
                ApplicationManager.getApplication().invokeAndWait(new Runnable() {
                    public void run() {
                        resultProcessor.process(new ArrayList<MavenArtifact>(result));
                    }
                }, indicator.getModalityState());
            }
        }
    }

    private static List<MavenRemoteRepository> convertRepositories(Collection<MavenRepositoryInfo> infos) {
        List<MavenRemoteRepository> result = new ArrayList<MavenRemoteRepository>(infos.size());
        for (MavenRepositoryInfo each : infos) {
            if (each.getUrl() != null) {
                result.add(
                        new MavenRemoteRepository(each.getId(), each.getName(), each.getUrl(), null, null, null));
            }
        }
        return result;
    }

    public static MavenId getMavenId(final String coord) {
        final String[] parts = coord.split(":");
        return new MavenId(parts.length > 0 ? parts[0] : null, parts.length > 1 ? parts[1] : null,
                parts.length > 2 ? parts[2] : null);
    }
}