diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java new file mode 100644 index 000000000000..66f20b29131b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java @@ -0,0 +1,217 @@ +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.net.URL; +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 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) { + 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 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 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); + + HttpConfigurable.getInstance().prepareURL(myUrl); + + indicator.checkCanceled(); + + HttpURLConnection urlConnection = (HttpURLConnection)new URL(myUrl).openConnection(); + + 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; + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/IvyAttachSourceProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/IvyAttachSourceProvider.java index 4ec17edf8f4f..2284a3177856 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/IvyAttachSourceProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/IvyAttachSourceProvider.java @@ -1,35 +1,21 @@ package org.jetbrains.plugins.groovy.ivy; -import com.intellij.codeInsight.AttachSourcesProvider; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.lang.properties.psi.Property; 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.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.util.text.StringUtil; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.util.ArrayUtil; -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.net.URL; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -37,46 +23,10 @@ import java.util.List; /** * @author Sergey Evdokimov */ -public class IvyAttachSourceProvider implements AttachSourcesProvider { +public class IvyAttachSourceProvider extends AbstractAttachSourceProvider { private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.ivy.IvyAttachSourceProvider"); - @Nullable - private 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 - private static Library getLibraryFromOrderEntriesList(List 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; - } - - private static void addSourceFile(@Nullable VirtualFile jarRoot, @NotNull Library library) { - if (jarRoot != null) { - Library.ModifiableModel model = library.getModifiableModel(); - model.addRoot(jarRoot, OrderRootType.SOURCES); - model.commit(); - } - } - @Nullable private static String extractUrl(PropertiesFile properties, String artifactName) { String prefix = "artifact:" + artifactName + "#source#jar#"; @@ -131,7 +81,7 @@ public class IvyAttachSourceProvider implements AttachSourcesProvider { return Collections.emptyList(); // Sources already attached. } - return Collections.singleton(new AttachExistingSourceAction(jarRoot, library)); + return Collections.singleton(new AttachExistingSourceAction(jarRoot, library, "Attache sources from Ivy repository") ); } } @@ -141,148 +91,30 @@ public class IvyAttachSourceProvider implements AttachSourcesProvider { final String url = extractUrl((PropertiesFile)propertiesFileFile, artifactName); if (StringUtil.isEmptyOrSpaces(url)) return Collections.emptyList(); - return Collections.singleton(new AttachSourcesAction() { + return Collections.singleton(new DownloadSourcesAction(psiFile.getProject(), "Downloading Ivy Sources", url) { @Override - public String getName() { - return "Download Sources"; - } - - @Override - public String getBusyText() { - return "Downloading Sources..."; - } - - @Override - public ActionCallback perform(List orderEntriesContainingFile) { - - final ActionCallback callback = new ActionCallback(); - - Task task = new Task.Backgroundable(psiFile.getProject(), "Downloading sources...", true) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - final ByteArrayOutputStream out; - - try { - LOG.info("Downloading sources jar: " + url); - - HttpConfigurable.getInstance().prepareURL(url); - - indicator.checkCanceled(); - - HttpURLConnection urlConnection = (HttpURLConnection)new URL(url).openConnection(); - - 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) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - new Notification("Downloading Ivy Sources", - "Downloading failed", - "Failed to download sources: " + url, - NotificationType.ERROR) - .notify(getProject()); - - callback.setDone(); - } - }); - return; - } - - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - AccessToken accessToken = WriteAction.start(); - try { - VirtualFile existingSourcesFolder = sources; - if (existingSourcesFolder == null) { - existingSourcesFolder = artifactDir.createChildDirectory(this, "sources"); - } - - VirtualFile srcFile = existingSourcesFolder.createChildData(this, sourceFileName); - srcFile.setBinaryContent(out.toByteArray()); - - addSourceFile(JarFileSystem.getInstance().getJarRootForLocalFile(srcFile), library); - } - catch (IOException e) { - new Notification("Downloading Ivy Sources", - "IO Error", - "Failed to save " + artifactDir.getPath() + "/sources/" + sourceFileName, - NotificationType.ERROR) - .notify(getProject()); - } - finally { - accessToken.finish(); - callback.setDone(); - } - } - }); + protected void storeFile(byte[] content) { + try { + VirtualFile existingSourcesFolder = sources; + if (existingSourcesFolder == null) { + existingSourcesFolder = artifactDir.createChildDirectory(this, "sources"); } - @Override - public void onCancel() { - callback.setRejected(); - } - }; + VirtualFile srcFile = existingSourcesFolder.createChildData(this, sourceFileName); + srcFile.setBinaryContent(content); - task.queue(); - - return callback; + addSourceFile(JarFileSystem.getInstance().getJarRootForLocalFile(srcFile), library); + } + catch (IOException e) { + new Notification(myMessageGroupId, + "IO Error", + "Failed to save " + artifactDir.getPath() + "/sources/" + sourceFileName, + NotificationType.ERROR) + .notify(myProject); + LOG.warn(e); + } } }); } - private static class AttachExistingSourceAction implements AttachSourcesAction { - - private final VirtualFile mySrcFile; - private final Library myLibrary; - - private AttachExistingSourceAction(VirtualFile srcFile, Library library) { - mySrcFile = srcFile; - myLibrary = library; - } - - @Override - public String getName() { - return "Attache sources from Ivy repository"; - } - - @Override - public String getBusyText() { - return getName(); - } - - @Override - public ActionCallback perform(List 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; - } - } }