IDEA-110149 Merge Generate toString, JarFinder plugins into IDEA core

This commit is contained in:
peter
2013-07-12 14:28:46 +02:00
parent dcef55656f
commit 3f3e6baeaf
18 changed files with 1011 additions and 39 deletions
+1 -1
View File
@@ -83,6 +83,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir
"InspectionGadgetsAnalysis",
"InspectionGadgetsPlugin",
"IntentionPowerPackPlugin",
"generate-tostring",
].flatten()
ant.patternset(id: "resources.included") {
@@ -251,7 +252,6 @@ public def layoutCommunityPlugins(String home) {
module("ant-jps-plugin")
}
}
layoutPlugin("ToString", "generate-tostring", "toString")
layoutPlugin("uiDesigner", "ui-designer", "uiDesigner") {
dir("jps") {
jar("ui-designer-jps-plugin.jar") {
@@ -0,0 +1,273 @@
package com.intellij.jarFinder;
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.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.ui.configuration.PathUIUtils;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
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.*;
import java.net.HttpURLConnection;
import java.util.*;
import java.util.regex.Pattern;
/**
* @author Sergey Evdokimov
*/
public class InternetAttachSourceProvider implements AttachSourcesProvider {
private static final Logger LOG = Logger.getInstance("#com.intellij.jarFinder.SonatypeAttachSourceProvider");
private static final Pattern ARTIFACT_IDENTIFIER = Pattern.compile("[A-Za-z0-9\\.\\-_]+");
@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;
}
@NotNull
@Override
public Collection<AttachSourcesAction> getActions(List<LibraryOrderEntry> orderEntries, final PsiFile psiFile) {
VirtualFile jar = getJarByPsiFile(psiFile);
if (jar == null) return Collections.emptyList();
final String jarName = jar.getNameWithoutExtension();
int index = jarName.lastIndexOf('-');
if (index == -1) return Collections.emptyList();
final String version = jarName.substring(index + 1);
final String artifactId = jarName.substring(0, index);
if (!ARTIFACT_IDENTIFIER.matcher(version).matches() || !ARTIFACT_IDENTIFIER.matcher(artifactId).matches()) {
return Collections.emptyList();
}
final Set<Library> libraries = new HashSet<Library>();
for (LibraryOrderEntry orderEntry : orderEntries) {
ContainerUtil.addIfNotNull(libraries, orderEntry.getLibrary());
}
if (libraries.isEmpty()) return Collections.emptyList();
final String sourceFileName = jarName + "-sources.jar";
for (Library library : libraries) {
for (VirtualFile file : library.getFiles(OrderRootType.SOURCES)) {
if (file.getPath().contains(sourceFileName)) {
if (isRootInExistingFile(file)) {
return Collections.emptyList(); // Sources already attached, but source-jar doesn't contain current class.
}
}
}
}
final File libSourceDir = getLibrarySourceDir();
final File sourceFile = new File(libSourceDir, sourceFileName);
if (sourceFile.exists()) {
return Collections.<AttachSourcesAction>singleton(new LightAttachSourcesAction() {
@Override
public String getName() {
return "Attach downloaded source";
}
@Override
public String getBusyText() {
return getName();
}
@Override
public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
attachSourceJar(sourceFile, libraries);
return new ActionCallback.Done();
}
});
}
return Collections.<AttachSourcesAction>singleton(new LightAttachSourcesAction() {
@Override
public String getName() {
return "Search in internet...";
}
@Override
public String getBusyText() {
return "Searching...";
}
@Override
public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
final Task task = new Task.Modal(psiFile.getProject(), "Searching source...", true) {
// Don't move initialization of searchers to static context of top level class, to avoid unnecessary initialization of searcher's classes
private SourceSearcher[] mySearchers = new SourceSearcher[]{new MavenCentralSourceSearcher(), new SonatypeSourceSearcher()};
@Override
public void run(@NotNull final ProgressIndicator indicator) {
String artifactUrl = null;
for (SourceSearcher searcher : mySearchers) {
try {
artifactUrl = searcher.findSourceJar(indicator, artifactId, version);
}
catch (SourceSearchException e) {
showMessage("Downloading failed", e.getMessage(), NotificationType.ERROR);
continue;
}
if (artifactUrl != null) break;
}
if (artifactUrl == null) {
showMessage("Source not found", "Sources for: " + jarName + ".jar not found", NotificationType.WARNING);
return;
}
libSourceDir.mkdirs();
if (!libSourceDir.exists()) {
showMessage("Downloading failed", "Failed to create directory to store sources: " + libSourceDir, NotificationType.ERROR);
return;
}
try {
HttpURLConnection urlConnection = HttpConfigurable.getInstance().openHttpConnection(artifactUrl);
int contentLength = urlConnection.getContentLength();
File tmpDownload = File.createTempFile("download", ".tmp", libSourceDir);
OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpDownload));
try {
InputStream in = urlConnection.getInputStream();
indicator.setText("Downloading sources...");
indicator.setIndeterminate(false);
try {
NetUtils.copyStreamContent(indicator, in, out, contentLength);
}
finally {
in.close();
}
}
finally {
out.close();
}
if (!sourceFile.exists()) {
if (!tmpDownload.renameTo(sourceFile)) {
LOG.warn("Failed to rename file " + tmpDownload + " to " + sourceFileName);
}
}
}
catch (IOException e) {
showMessage("Downloading failed", "Connection problem. See log for more details.", NotificationType.ERROR);
}
}
@Override
public void onSuccess() {
attachSourceJar(sourceFile, libraries);
}
private void showMessage(final String title, final String message, final NotificationType notificationType) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
new Notification("Source searcher",
title,
message,
notificationType)
.notify(getProject());
}
});
}
};
task.queue();
return new ActionCallback.Done();
}
});
}
private static boolean isRootInExistingFile(VirtualFile root) {
if (root.getFileSystem() instanceof JarFileSystem) {
VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(root);
if (jar == null) return false;
jar.refresh(false, false);
return root.isValid();
}
return true;
}
public static void attachSourceJar(@NotNull File sourceJar, @NotNull Collection<Library> libraries) {
AccessToken accessToken = WriteAction.start();
try {
VirtualFile srcFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(sourceJar);
if (srcFile == null) return;
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(srcFile);
if (jarRoot == null) return;
VirtualFile[] roots = PathUIUtils.scanAndSelectDetectedJavaSourceRoots(null, new VirtualFile[]{jarRoot});
if (roots.length == 0) {
roots = new VirtualFile[]{jarRoot};
}
for (Library library : libraries) {
Library.ModifiableModel model = library.getModifiableModel();
List<VirtualFile> alreadyExistingFiles = Arrays.asList(model.getFiles(OrderRootType.SOURCES));
for (VirtualFile root : roots) {
if (!alreadyExistingFiles.contains(root)) {
model.addRoot(root, OrderRootType.SOURCES);
}
}
model.commit();
}
}
finally {
accessToken.finish();
}
}
public static File getLibrarySourceDir() {
String path = System.getProperty("idea.library.source.dir");
if (path != null) {
return new File(path);
}
return new File(SystemProperties.getUserHome(), ".ideaLibSources");
}
}
+1
View File
@@ -36,6 +36,7 @@
<orderEntry type="module" module-name="external-system-api" />
<orderEntry type="library" name="asm4" level="project" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="library" name="Xerces" level="project" />
</component>
<component name="copyright">
<Base>
@@ -0,0 +1,301 @@
package com.intellij.jarFinder;
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
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.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.components.JBList;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.NotNullFunction;
import com.intellij.util.PlatformIcons;
import com.intellij.util.download.DownloadableFileDescription;
import com.intellij.util.download.DownloadableFileService;
import org.apache.xerces.parsers.DOMParser;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Konstantin Bulenkov
*/
public abstract class FindJarFix<T extends PsiElement> implements IntentionAction, Iconable {
private static final String CLASS_ROOT_URL = "http://findjar.com/class/";
private static final String CLASS_PAGE_EXT = ".html";
private static final String SERVICE_URL = "http://findjar.com";
private static final String LINK_TAG_NAME = "a";
private static final String LINK_ATTR_NAME = "href";
protected final T myRef;
protected final Module myModule;
protected JComponent myEditorComponent;
public FindJarFix(T ref) {
myRef = ref;
myModule = ModuleUtil.findModuleForPsiElement(ref);
}
@NotNull
@Override
public String getText() {
return "Find jar on web";
}
@NotNull
@Override
public String getFamilyName() {
return "Family name";
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myRef.isValid()
&& JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, file.getResolveScope()) != null
&& myModule != null
&& isFqnsOk(project, getPossibleFqns(myRef));
}
private static boolean isFqnsOk(Project project, List<String> fqns) {
if (fqns.isEmpty()) return false;
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
for (String fqn : fqns) {
if (facade.findClass(fqn, scope) != null) return false;
}
return true;
}
@Override
public void invoke(@NotNull Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
final List<String> fqns = getPossibleFqns(myRef);
myEditorComponent = editor.getComponent();
if (fqns.size() > 1) {
final JBList listOfFqns = new JBList(fqns);
JBPopupFactory.getInstance()
.createListPopupBuilder(listOfFqns)
.setTitle("Select Qualified Name")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
final Object value = listOfFqns.getSelectedValue();
if (value instanceof String) {
findJarsForFqn(((String)value), editor);
}
}
}).createPopup().showInBestPositionFor(editor);
}
else if (fqns.size() == 1) {
findJarsForFqn(fqns.get(0), editor);
}
}
private void findJarsForFqn(final String fqn, final Editor editor) {
final Map<String, String> libs = new HashMap<String, String>();
final Runnable runnable = new Runnable() {
public void run() {
try {
final DOMParser parser = new DOMParser();
parser.parse(CLASS_ROOT_URL + fqn.replace('.', '/') + CLASS_PAGE_EXT);
final Document doc = parser.getDocument();
if (doc != null) {
final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME);
for (int i = 0; i < links.getLength(); i++) {
final Node link = links.item(i);
final String libName = link.getTextContent();
final NamedNodeMap attributes = link.getAttributes();
if (attributes != null) {
final Node href = attributes.getNamedItem(LINK_ATTR_NAME);
if (href != null) {
final String pathToJar = href.getTextContent();
if (pathToJar != null && (pathToJar.startsWith("/jar/") || pathToJar.startsWith("/class/../"))) {
libs.put(libName, SERVICE_URL + pathToJar);
}
}
}
}
}
}
catch (IOException ignore) {//
}
catch (SAXException e) {//
}
}
};
final Task.Modal task = new Task.Modal(editor.getProject(), "Looking for libraries", true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(true);
runnable.run();
}
@Override
public void onSuccess() {
super.onSuccess();
if (libs.isEmpty()) {
HintManager.getInstance().showInformationHint(editor, "No libraries found for '" + fqn + "'");
} else {
final ArrayList<String> variants = new ArrayList<String>(libs.keySet());
Collections.sort(variants, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
final JBList libNames = new JBList(variants);
libNames.installCellRenderer(new NotNullFunction<Object, JComponent>() {
@NotNull
@Override
public JComponent fun(Object o) {
return new JLabel(o.toString(), PlatformIcons.JAR_ICON, SwingConstants.LEFT);
}
});
if (libs.size() == 1) {
final String jarName = libs.keySet().iterator().next();
final String url = libs.get(jarName);
initiateDownload(url, jarName);
} else {
JBPopupFactory.getInstance()
.createListPopupBuilder(libNames)
.setTitle("Select a jar file")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
final Object value = libNames.getSelectedValue();
if (value instanceof String) {
final String jarName = (String)value;
final String url = libs.get(jarName);
if (url != null) {
initiateDownload(url, jarName);
}
}
}
})
.createPopup().showInBestPositionFor(editor);
}
}
}
};
ProgressManager.getInstance().run(task);
}
private void initiateDownload(String url, String jarName) {
DOMParser parser = new DOMParser();
try {
parser.parse(url);
final Document doc = parser.getDocument();
if (doc != null) {
final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME);
if (links != null) {
for (int i = 0; i < links.getLength(); i++) {
final Node item = links.item(i);
if (item != null) {
final NamedNodeMap attributes = item.getAttributes();
if (attributes != null) {
final Node link = attributes.getNamedItem(LINK_ATTR_NAME);
if (link != null) {
final String jarUrl = link.getTextContent();
if (jarUrl != null && jarUrl.endsWith(jarName)) {
downloadJar(jarUrl, jarName);
}
}
}
}
}
}
}
}
catch (SAXException e) {//
}
catch (IOException e) {//
}
}
private void downloadJar(String jarUrl, String jarName) {
final Project project = myModule.getProject();
final String dirPath = PropertiesComponent.getInstance(project).getValue("findjar.last.used.dir");
VirtualFile toSelect = dirPath == null ? null : LocalFileSystem.getInstance().findFileByIoFile(new File(dirPath));
final VirtualFile file = FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFolderDescriptor(), project, toSelect);
if (file != null) {
PropertiesComponent.getInstance(project).setValue("findjar.last.used.dir", file.getPath());
final DownloadableFileService downloader = DownloadableFileService.getInstance();
final DownloadableFileDescription description = downloader.createFileDescription(jarUrl, jarName);
final VirtualFile[] jars = downloader.createDownloader(Arrays.asList(description), project, myEditorComponent, jarName)
.toDirectory(file.getPath()).download();
if (jars != null && jars.length == 1) {
AccessToken token = WriteAction.start();
try {
OrderEntryFix.addJarToRoots(jars[0].getPresentableUrl(), myModule, myRef);
}
finally {
token.finish();
}
}
}
}
protected abstract Collection<String> getFqns(@NotNull T ref);
protected List<String> getPossibleFqns(T ref) {
Collection<String> fqns = getFqns(ref);
List<String> res = new ArrayList<String>(fqns.size());
for (String fqn : fqns) {
if (fqn.startsWith("java.") || fqn.startsWith("javax.swing.")) {
continue;
}
final int index = fqn.lastIndexOf('.');
if (index == -1) {
continue;
}
final String className = fqn.substring(index + 1);
if (className.length() == 0 || Character.isLowerCase(className.charAt(0))) {
continue;
}
res.add(fqn);
}
return res;
}
@Override
public boolean startInWriteAction() {
return false;
}
@Override
public Icon getIcon(int flags) {
return PlatformIcons.WEB_ICON;
}
}
@@ -0,0 +1,22 @@
package com.intellij.jarFinder;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import org.jetbrains.annotations.NotNull;
/**
* @author Konstantin Bulenkov
*/
public class FindJarQuickFixProvider extends UnresolvedReferenceQuickFixProvider<PsiJavaCodeReferenceElement> {
@Override
public void registerFixes(PsiJavaCodeReferenceElement ref, QuickFixActionRegistrar registrar) {
registrar.register(new JavaFindJarFix(ref));
}
@NotNull
@Override
public Class<PsiJavaCodeReferenceElement> getReferenceClass() {
return PsiJavaCodeReferenceElement.class;
}
}
@@ -0,0 +1,78 @@
package com.intellij.jarFinder;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiImportStaticStatementImpl;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author Sergey Evdokimov
*/
public class JavaFindJarFix extends FindJarFix<PsiQualifiedReferenceElement> {
public JavaFindJarFix(PsiQualifiedReferenceElement ref) {
super(ref);
}
@Override
protected Collection<String> getFqns(@NotNull PsiQualifiedReferenceElement ref) {
final PsiImportStatementBase importStatement = PsiTreeUtil.getParentOfType(ref.getElement(), PsiImportStatementBase.class);
//from static imports
if (importStatement != null) {
if (importStatement instanceof PsiImportStatement) {
final String importFQN = ((PsiImportStatement)importStatement).getQualifiedName();
if (importFQN != null && !importFQN.endsWith("*")) {
return Collections.singleton(importFQN);
}
}
else if (importStatement instanceof PsiImportStaticStatementImpl) {
final PsiJavaCodeReferenceElement classRef = ((PsiImportStaticStatementImpl)importStatement).getClassReference();
if (classRef != null) {
final String importFQN = classRef.getQualifiedName();
if (importFQN != null) {
return Collections.singleton(importFQN);
}
}
}
return Collections.emptyList();
}
final PsiElement qualifier = ref.getQualifier();
if (qualifier instanceof PsiQualifiedReference) {
//PsiQualifiedReference r = (PsiQualifiedReference)qualifier;
//TODO[kb] get fqn from expressions like org.unresolvedPackage.MyClass.staticMethodCall(...);
return Collections.emptyList();
}
final String className = ref.getReferenceName();
PsiFile file = ref.getContainingFile().getOriginalFile();
if (className != null && file instanceof PsiJavaFile) {
final PsiImportList importList = ((PsiJavaFile)file).getImportList();
if (importList != null) {
final PsiImportStatementBase statement = importList.findSingleImportStatement(className);
if (statement instanceof PsiImportStatement) {
final String importFQN = ((PsiImportStatement)statement).getQualifiedName();
if (importFQN != null) {
return Collections.singleton(importFQN);
}
}
else {
List<String> res = new ArrayList<String>();
// iterate through *
for (PsiImportStatementBase imp : importList.getAllImportStatements()) {
if (imp.isOnDemand() && imp instanceof PsiImportStatement) {
res.add(((PsiImportStatement)imp).getQualifiedName() + "." + className);
}
}
return res;
}
}
}
return Collections.emptyList();
}
}
@@ -0,0 +1,70 @@
package com.intellij.jarFinder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
/**
* @author Sergey Evdokimov
*/
public class MavenCentralSourceSearcher extends SourceSearcher {
private static final Logger LOG = Logger.getInstance(MavenCentralSourceSearcher.class);
@Nullable
@Override
protected String findSourceJar(@NotNull ProgressIndicator indicator,
@NotNull String artifactId,
@NotNull String version) throws SourceSearchException {
try {
indicator.setIndeterminate(true);
indicator.setText("Connecting to http://search.maven.org");
indicator.checkCanceled();
String url = "http://search.maven.org/solrsearch/select?rows=3&wt=xml&q=a:%22" + artifactId + "%22%20AND%20v:%22" + version + "%22%20AND%20l:%22sources%22";
Document document = readDocumentCancelable(indicator, url);
indicator.checkCanceled();
List<Element> artifactList = (List<Element>)XPath.newInstance("/response/result/doc/str[@name='g']").selectNodes(document);
if (artifactList.isEmpty()) {
return null;
}
Element element;
if (artifactList.size() == 1) {
element = artifactList.get(0);
}
else {
// TODO handle
return null;
}
String groupId = element.getValue();
String downloadUrl = "http://search.maven.org/remotecontent?filepath=" + groupId.replace('.', '/') + '/' + artifactId + '/' + version + '/' + artifactId + '-' + version + "-sources.jar";
return downloadUrl;
}
catch (JDOMException e) {
LOG.warn(e);
throw new SourceSearchException("Failed to parse response from server. See log for more details.");
}
catch (IOException e) {
indicator.checkCanceled(); // Cause of IOException may be canceling of operation.
LOG.warn(e);
throw new SourceSearchException("Connection problem. See log for more details.");
}
}
}
@@ -0,0 +1,87 @@
package com.intellij.jarFinder;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Pair;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
/**
* @author Sergey Evdokimov
*/
public class SonatypeSourceSearcher extends SourceSearcher {
private static final Logger LOG = Logger.getInstance(SonatypeSourceSearcher.class);
@Nullable
@Override
public String findSourceJar(@NotNull final ProgressIndicator indicator, @NotNull String artifactId, @NotNull String version)
throws SourceSearchException {
try {
indicator.setIndeterminate(true);
indicator.setText("Connecting to https://oss.sonatype.org");
indicator.checkCanceled();
String url = "https://oss.sonatype.org/service/local/lucene/search?collapseresults=true&c=sources&a=" + artifactId + "&v=" + version;
Document document = readDocumentCancelable(indicator, url);
indicator.checkCanceled();
List<Element> artifactList = (List<Element>)XPath.newInstance("/searchNGResponse/data/artifact").selectNodes(document);
if (artifactList.isEmpty()) {
return null;
}
Element element;
if (artifactList.size() == 1) {
element = artifactList.get(0);
}
else {
// TODO handle
return null;
}
List<Element> artifactHintList =
(List<Element>)XPath.newInstance("artifactHits/artifactHit/artifactLinks/artifactLink/classifier[text()='sources']/../../..")
.selectNodes(element);
if (artifactHintList.isEmpty()) {
return null;
}
String groupId = element.getChildTextTrim("groupId");
String repositoryId = artifactHintList.get(0).getChildTextTrim("repositoryId");
String downloadUrl = "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=" +
repositoryId +
"&g=" +
groupId +
"&a=" +
artifactId +
"&v=" +
version +
"&e=jar&c=sources";
return downloadUrl;
}
catch (JDOMException e) {
LOG.warn(e);
throw new SourceSearchException("Failed to parse response from server. See log for more details.");
}
catch (IOException e) {
indicator.checkCanceled(); // Cause of IOException may be canceling of operation.
LOG.warn(e);
throw new SourceSearchException("Connection problem. See log for more details.");
}
}
}
@@ -0,0 +1,77 @@
package com.intellij.jarFinder;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.net.HttpConfigurable;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
/**
* @author Sergey Evdokimov
*/
public abstract class SourceSearcher {
/**
* @param indicator
* @param artifactId
* @param version
* @return groupId of found artifact and url.
*/
@Nullable
protected abstract String findSourceJar(@NotNull final ProgressIndicator indicator, @NotNull String artifactId, @NotNull String version) throws SourceSearchException;
protected static Document readDocumentCancelable(final ProgressIndicator indicator, String url) throws JDOMException, IOException {
final HttpURLConnection urlConnection = HttpConfigurable.getInstance().openHttpConnection(url);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
//noinspection InfiniteLoopStatement
while (true) {
if (indicator.isCanceled()) {
urlConnection.disconnect();
}
//noinspection BusyWait
Thread.sleep(100);
}
}
catch (InterruptedException ignored) {
}
}
});
t.start();
try {
urlConnection.setRequestProperty("accept", "application/xml");
InputStream inputStream = urlConnection.getInputStream();
try {
return new SAXBuilder().build(inputStream);
}
finally {
inputStream.close();
}
}
finally {
t.interrupt();
}
}
}
class SourceSearchException extends Exception {
SourceSearchException(String message) {
super(message);
}
}
@@ -1,33 +0,0 @@
<idea-plugin url="http://code.google.com/p/generate-tostring" version="3">
<name>GenerateToString</name>
<description>Adds a new action 'toString()' in the generate menu (alt + ins). The action generates a toString()
method that dumps the classes fields. Java body code is generated using Velocity Macro and you can change this
to fit your needs. Full documentation included (Click hyperlink from Settings).
</description>
<version>5.0</version>
<vendor email="cib_rejse@yahoo.dk" url="http://generate-tostring.googlecode.com">Claus Ibsen</vendor>
<actions>
<action id="Actions.ActionsPlugin.GenerateToString"
class="org.jetbrains.generate.tostring.GenerateToStringAction" text="to_String()"
description="Generate toString() method">
<add-to-group group-id="GenerateGroup" anchor="after" relative-to-action="GenerateEquals"/>
</action>
</actions>
<extensions defaultExtensionNs="com.intellij">
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
<applicationService serviceInterface="org.jetbrains.generate.tostring.template.TemplatesManager"
serviceImplementation="org.jetbrains.generate.tostring.template.TemplatesManager"/>
<applicationService serviceInterface="org.jetbrains.generate.tostring.GenerateToStringContext"
serviceImplementation="org.jetbrains.generate.tostring.GenerateToStringContext"/>
<localInspection language="JAVA" shortName="ClassHasNoToStringMethod" displayName="Class does not override 'toString()' method"
groupName="toString() issues" enabledByDefault="false" level="WARNING"
implementationClass="org.jetbrains.generate.tostring.inspection.ClassHasNoToStringMethodInspection"/>
<localInspection language="JAVA" shortName="FieldNotUsedInToString" displayName="Field not used in 'toString()' method" groupName="toString() issues"
enabledByDefault="false" level="WARNING" runForWholeFile="true"
implementationClass="org.jetbrains.generate.tostring.inspection.FieldNotUsedInToStringInspection"/>
</extensions>
</idea-plugin>
@@ -2,11 +2,6 @@
<body>
<h2>Generate toString() plugin</h2>
<h3>Plugin home page</h3>
The plugin is hosted at Google code where there is an official issue tracker and wiki pages with more information.
<br/>
Plugin home page: <a href="http://code.google.com/p/generate-tostring/">generate-tostring</a>
<h3>Introduction</h3>
GenerateToString is a action plugin for IDEA that is used to create or update java classes <code>toString()</code> method.
The reason is valuebeans usually needs to dump their field values for debug purpose, and it's tedious to write
+1
View File
@@ -1415,6 +1415,7 @@
<debugger.positionManagerFactory order="after groovyPositionManager"
implementation="org.jetbrains.plugins.groovy.springloaded.SpringLoadedPositionManagerFactory"/>
<codeStyle.ReferenceAdjuster language="Groovy" implementationClass="org.jetbrains.plugins.groovy.codeStyle.GrReferenceAdjuster"/>
<codeInsight.unresolvedReferenceQuickFixProvider implementation="org.jetbrains.plugins.groovy.jarFinder.GroovyFindJarQuickFixProvider"/>
</extensions>
<extensions defaultExtensionNs="com.intellij.debugger">
@@ -0,0 +1,59 @@
package org.jetbrains.plugins.groovy.jarFinder;
import com.intellij.jarFinder.FindJarFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiQualifiedReference;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import java.util.Collection;
import java.util.Collections;
/**
* @author Sergey Evdokimov
*/
public class GroovyFindJarFix extends FindJarFix<GrReferenceElement> {
public GroovyFindJarFix(GrReferenceElement ref) {
super(ref);
}
@Override
protected Collection<String> getFqns(@NotNull GrReferenceElement ref) {
GrImportStatement importStatement = PsiTreeUtil.getParentOfType(ref.getElement(), GrImportStatement.class);
//from static imports
if (importStatement != null) {
GrCodeReferenceElement reference = importStatement.getImportReference();
if (reference != null) {
return Collections.singleton(reference.getText());
}
return Collections.emptyList();
}
if (ref.getQualifier() != null) return Collections.emptyList();
final String className = ref.getReferenceName();
if (className == null) return Collections.emptyList();
PsiFile file = ref.getContainingFile().getOriginalFile();
if (!(file instanceof GroovyFile)) return Collections.emptyList();
GrImportStatement[] importList = ((GroovyFile)file).getImportStatements();
for (GrImportStatement imp : importList) {
if (className.equals(imp.getImportedName())) {
GrCodeReferenceElement importReference = imp.getImportReference();
if (importReference == null) return Collections.emptyList();
return Collections.singleton(importReference.getText());
}
}
return Collections.emptyList();
}
}
@@ -0,0 +1,24 @@
package org.jetbrains.plugins.groovy.jarFinder;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
/**
* @author Sergey Evdokimov
*/
public class GroovyFindJarQuickFixProvider extends UnresolvedReferenceQuickFixProvider<GrReferenceElement> {
@Override
public void registerFixes(GrReferenceElement ref, QuickFixActionRegistrar registrar) {
registrar.register(new GroovyFindJarFix(ref));
}
@NotNull
@Override
public Class<GrReferenceElement> getReferenceClass() {
return GrReferenceElement.class;
}
}
+1
View File
@@ -15,6 +15,7 @@
<orderEntry type="module" module-name="InspectionGadgetsPlugin" />
<orderEntry type="module" module-name="IntentionPowerPackPlugin" />
<orderEntry type="module" module-name="remote-servers-impl" exported="" scope="RUNTIME" />
<orderEntry type="module" module-name="generate-tostring" />
</component>
<component name="copyright">
<Base>
+13
View File
@@ -1444,6 +1444,19 @@
<weigher order="first" key="completion" id="methodsChainsCompletionContributor"
implementationClass="com.intellij.codeInsight.completion.methodChains.completion.MethodsChainsWeigher"/>
<applicationService serviceInterface="org.jetbrains.generate.tostring.template.TemplatesManager"
serviceImplementation="org.jetbrains.generate.tostring.template.TemplatesManager"/>
<applicationService serviceInterface="org.jetbrains.generate.tostring.GenerateToStringContext"
serviceImplementation="org.jetbrains.generate.tostring.GenerateToStringContext"/>
<localInspection language="JAVA" shortName="ClassHasNoToStringMethod" displayName="Class does not override 'toString()' method"
groupName="toString() issues" enabledByDefault="false" level="WARNING"
implementationClass="org.jetbrains.generate.tostring.inspection.ClassHasNoToStringMethodInspection"/>
<localInspection language="JAVA" shortName="FieldNotUsedInToString" displayName="Field not used in 'toString()' method" groupName="toString() issues"
enabledByDefault="false" level="WARNING" runForWholeFile="true"
implementationClass="org.jetbrains.generate.tostring.inspection.FieldNotUsedInToStringInspection"/>
<codeInsight.unresolvedReferenceQuickFixProvider implementation="com.intellij.jarFinder.FindJarQuickFixProvider"/>
</extensions>
<actions>
+1
View File
@@ -11,6 +11,7 @@
<action id="GenerateSetter" class="com.intellij.codeInsight.generation.actions.GenerateSetterAction"/>
<action id="GenerateGetterAndSetter" class="com.intellij.codeInsight.generation.actions.GenerateGetterAndSetterAction"/>
<action id="GenerateEquals" class="com.intellij.codeInsight.generation.actions.GenerateEqualsAction"/>
<action id="Actions.ActionsPlugin.GenerateToString" class="org.jetbrains.generate.tostring.GenerateToStringAction" text="to_String()" description="Generate toString() method"/>
<action id="GenerateCreateUI" class="com.intellij.codeInsight.generation.actions.GenerateCreateUIAction"/>
<add-to-group group-id="GenerateGroup" anchor="first"/>
</group>
@@ -283,6 +283,8 @@
<editorNotificationProvider implementation="com.intellij.codeInsight.daemon.impl.AttachSourcesNotificationProvider"/>
<editorNotificationProvider implementation="com.intellij.codeInsight.daemon.impl.SetupSDKNotificationProvider"/>
<attachSourcesProvider implementation="com.intellij.jarFinder.InternetAttachSourceProvider"/>
<checkoutListener implementation="com.intellij.openapi.vcs.checkout.ProjectCheckoutListener"/>
<checkoutListener implementation="com.intellij.openapi.vcs.checkout.ProjectDirCheckoutListener"/>
<checkoutListener implementation="com.intellij.openapi.vcs.checkout.ProjectImporterCheckoutListener"/>