blob: 3f2139c174a8c7e651aeb65d6860a33eb4ee2a08 [file] [log] [blame]
package org.jetbrains.plugins.groovy.ivy;
import com.intellij.codeInsight.AttachSourcesProvider;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.net.NetUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.List;
/**
* @author Sergey Evdokimov
*/
public abstract class AbstractAttachSourceProvider implements AttachSourcesProvider {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.ivy.AbstractAttachSourceProvider");
@Nullable
protected static VirtualFile getJarByPsiFile(PsiFile psiFile) {
VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return null;
VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(psiFile.getVirtualFile());
if (jar == null || !jar.getName().endsWith(".jar")) return null;
return jar;
}
@Nullable
protected static Library getLibraryFromOrderEntriesList(List<LibraryOrderEntry> orderEntries) {
if (orderEntries.isEmpty()) return null;
Library library = orderEntries.get(0).getLibrary();
if (library == null) return null;
for (int i = 1; i < orderEntries.size(); i++) {
if (!library.equals(orderEntries.get(i).getLibrary())) {
return null;
}
}
return library;
}
protected void addSourceFile(@Nullable VirtualFile jarRoot, @NotNull Library library) {
if (jarRoot != null) {
if (!Arrays.asList(library.getFiles(OrderRootType.SOURCES)).contains(jarRoot)) {
Library.ModifiableModel model = library.getModifiableModel();
model.addRoot(jarRoot, OrderRootType.SOURCES);
model.commit();
}
}
}
protected class AttachExistingSourceAction implements AttachSourcesAction {
private final String myName;
private final VirtualFile mySrcFile;
private final Library myLibrary;
public AttachExistingSourceAction(VirtualFile srcFile, Library library, String actionName) {
mySrcFile = srcFile;
myLibrary = library;
myName = actionName;
}
@Override
public String getName() {
return myName;
}
@Override
public String getBusyText() {
return getName();
}
@Override
public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
ApplicationManager.getApplication().assertIsDispatchThread();
ActionCallback callback = new ActionCallback();
callback.setDone();
if (!mySrcFile.isValid()) return callback;
if (myLibrary != getLibraryFromOrderEntriesList(orderEntriesContainingFile)) return callback;
AccessToken accessToken = WriteAction.start();
try {
addSourceFile(mySrcFile, myLibrary);
}
finally {
accessToken.finish();
}
return callback;
}
}
protected abstract class DownloadSourcesAction implements AttachSourcesAction {
protected final Project myProject;
protected final String myUrl;
protected final String myMessageGroupId;
public DownloadSourcesAction(Project project, String messageGroupId, String url) {
myProject = project;
myUrl = url;
myMessageGroupId = messageGroupId;
}
@Override
public String getName() {
return "Download Sources";
}
@Override
public String getBusyText() {
return "Downloading Sources...";
}
protected abstract void storeFile(byte[] content);
@Override
public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
final ActionCallback callback = new ActionCallback();
Task task = new Task.Backgroundable(myProject, "Downloading sources...", true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
final ByteArrayOutputStream out;
try {
LOG.info("Downloading sources JAR: " + myUrl);
indicator.checkCanceled();
HttpURLConnection urlConnection = HttpConfigurable.getInstance().openHttpConnection(myUrl);
int contentLength = urlConnection.getContentLength();
out = new ByteArrayOutputStream(contentLength > 0 ? contentLength : 100 * 1024);
InputStream in = urlConnection.getInputStream();
try {
NetUtils.copyStreamContent(indicator, in, out, contentLength);
}
finally {
in.close();
}
}
catch (IOException e) {
LOG.warn(e);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
new Notification(myMessageGroupId,
"Downloading failed",
"Failed to download sources: " + myUrl,
NotificationType.ERROR)
.notify(getProject());
callback.setDone();
}
});
return;
}
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
AccessToken accessToken = WriteAction.start();
try {
storeFile(out.toByteArray());
}
finally {
accessToken.finish();
callback.setDone();
}
}
});
}
@Override
public void onCancel() {
callback.setRejected();
}
};
task.queue();
return callback;
}
}
}