--- a/java.editor/nbproject/project.xml +++ a/java.editor/nbproject/project.xml @@ -236,7 +236,7 @@ 1 - 1.15 + 1.19 --- a/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionDoc.java +++ a/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionDoc.java @@ -46,6 +46,7 @@ import java.net.URL; import java.util.concurrent.Callable; +import java.util.concurrent.Future; import javax.lang.model.element.Element; import javax.swing.Action; import org.netbeans.api.java.source.CompilationController; @@ -77,6 +78,10 @@ return elementJavadoc.getText(); } + public Future getFutureText() { + return elementJavadoc.getTextAsync(); + } + public Action getGotoSourceAction() { return elementJavadoc.getGotoSourceAction(); } --- a/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionProvider.java +++ a/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionProvider.java @@ -51,6 +51,8 @@ import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import java.util.logging.Level; import javax.lang.model.SourceVersion; @@ -303,8 +305,18 @@ if (toolTip != null && toolTip.hasData()) resultSet.setToolTip(toolTip); } else if (queryType == DOCUMENTATION_QUERY_TYPE) { - if (documentation != null) + if (documentation instanceof JavaCompletionDoc) { + while (!isTaskCancelled()) { + try { + ((JavaCompletionDoc)documentation).getFutureText().get(250, TimeUnit.MILLISECONDS); + resultSet.setDocumentation(documentation); + break; + } catch (TimeoutException timeOut) {/*retry*/} + } + + } else if (documentation != null) { resultSet.setDocumentation(documentation); + } } if (anchorOffset > -1) resultSet.setAnchorOffset(anchorOffset); --- a/java.sourceui/apichanges.xml +++ a/java.sourceui/apichanges.xml @@ -109,7 +109,20 @@ - + + + Added asynchronous version of getText method into ElementJavadoc + + + + + + Added asynchronous version of getText into ElementJavadoc. + The getTextAsync returns a Future which blocks until the javadoc is downloaded. + + + + Adding cancelable version of ElementJavadoc.create --- a/java.sourceui/nbproject/project.properties +++ a/java.sourceui/nbproject/project.properties @@ -2,4 +2,4 @@ javac.compilerargs=-Xlint -Xlint:-serial javac.source=1.6 javadoc.arch=${basedir}/arch.xml -spec.version.base=1.18.0 +spec.version.base=1.19.0 --- a/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties +++ a/java.sourceui/src/org/netbeans/api/java/source/ui/Bundle.properties @@ -54,6 +54,7 @@ array_length_field_javadoc=Length of array. class_constant_javadoc=java.lang.Class constant. javadoc_content_not_found=Javadoc not found. Either Javadoc documentation for this item does not exist or you have not added specified Javadoc in the Java Platform Manager or the Library Manager. +LBL_HTTPJavadocDownload=Downloading HTTP Javadoc LBL_CancelAction=Cancel {0} MSG_WaitScan=Please wait, classpath scanning in progress... --- a/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java +++ a/java.sourceui/src/org/netbeans/api/java/source/ui/ElementJavadoc.java @@ -30,12 +30,17 @@ */ package org.netbeans.api.java.source.ui; +import com.sun.source.util.Trees; import java.awt.event.ActionEvent; import java.io.IOException; import java.lang.reflect.Modifier; import java.net.URI; import java.net.URL; import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -50,10 +55,10 @@ import javax.swing.Action; import com.sun.javadoc.*; import com.sun.javadoc.AnnotationDesc.ElementValuePair; -import com.sun.source.util.Trees; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; import org.netbeans.api.java.source.ClasspathInfo; import org.netbeans.api.java.source.CompilationController; import org.netbeans.api.java.source.CompilationInfo; @@ -63,11 +68,16 @@ import org.netbeans.api.java.source.JavaSource.Phase; import org.netbeans.api.java.source.SourceUtils; import org.netbeans.api.java.source.Task; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.netbeans.modules.java.preprocessorbridge.api.JavaSourceUtil; import org.netbeans.modules.java.source.JavadocHelper; +import org.netbeans.modules.java.source.usages.Pair; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; import org.openide.util.Exceptions; import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; import org.openide.xml.XMLUtil; /** Utility class for viewing Javadoc comments as HTML. @@ -78,6 +88,8 @@ private static final String API = "/api"; //NOI18N private static final Set LANGS; + + private static final RequestProcessor RP = new RequestProcessor(ElementJavadoc.class); static { Locale[] availableLocales = Locale.getAvailableLocales(); @@ -92,10 +104,8 @@ } private ClasspathInfo cpInfo; - private ElementUtilities eu; - private Trees trees; //private Doc doc; - private String content = null; + private Future content; private Hashtable> links = new Hashtable>(); private int linkCounter = 0; private URL docURL = null; @@ -143,6 +153,20 @@ * @return HTML text of the javadoc */ public String getText() { + try { + return content.get(); + } catch (InterruptedException ex) { + return null; + } catch (ExecutionException ex) { + return null; + } + } + + /** Gets the javadoc comment formated as HTML. + * @return {@link Future} of HTML text of the javadoc + * @since 1.19 + */ + public Future getTextAsync() { return content; } @@ -246,10 +270,9 @@ } private ElementJavadoc(CompilationInfo compilationInfo, Element element, URL url, final Callable cancel) { - this.trees = compilationInfo.getTrees(); - this.eu = compilationInfo.getElementUtilities(); + Pair context = Pair.of(compilationInfo.getTrees(), compilationInfo.getElementUtilities()); this.cpInfo = compilationInfo.getClasspathInfo(); - Doc doc = eu.javaDocFor(element); + Doc doc = context.second.javaDocFor(element); boolean localized = false; StringBuilder content = new StringBuilder(); JavadocHelper.TextStream page = null; @@ -282,7 +305,40 @@ } } } - this.content = content.append(prepareContent(doc, localized, page, cancel)).toString(); + try { + //Optimisitic no http + this.content = prepareContent(content, doc,localized, page, cancel, true, context); + } catch (RemoteJavadocException re) { + final FileObject fo = compilationInfo.getFileObject(); + final ElementHandle handle = ElementHandle.create(element); + final StringBuilder contentFin = content; + final boolean localizedFin = localized; + this.content = new FutureTask(new Callable(){ + @Override + public String call() throws Exception { + final JavaSourceUtil.Handle ch = JavaSourceUtil.createControllerHandle(fo, null); + final CompilationController c = (CompilationController) ch.getCompilationController(); + c.toPhase(Phase.RESOLVED); + final Element element = handle.resolve(c); + Pair context = Pair.of(c.getTrees(), c.getElementUtilities()); + Doc doc = context.second.javaDocFor(element); + JavadocHelper.TextStream page = JavadocHelper.getJavadoc(element, cancel); + return prepareContent(contentFin, doc,localizedFin, page, cancel, false, context).get(); + } + }); + RP.post(new Runnable() { + @Override + public void run() { + final ProgressHandle progress = ProgressHandleFactory.createHandle(NbBundle.getMessage(ElementJavadoc.class, "LBL_HTTPJavadocDownload")); + progress.start(); + try { + ((Runnable)ElementJavadoc.this.content).run(); + } finally { + progress.finish(); + } + } + }); + } } private ElementJavadoc(URL url) { @@ -329,25 +385,34 @@ /** * Creates javadoc content + * @header header of the generated HTML * @param eu element utilities to find out elements * @param doc javac javadoc model * @param useJavadoc preffer javadoc to sources * @return Javadoc content */ - private StringBuilder prepareContent(Doc doc, final boolean useJavadoc, JavadocHelper.TextStream page, Callable cancel) { - StringBuilder sb = new StringBuilder(); + private Future prepareContent( + final StringBuilder header, + final Doc doc, + final boolean useJavadoc, + final JavadocHelper.TextStream page, + final Callable cancel, + final boolean sync, Pair ctx) throws RemoteJavadocException { + + + final StringBuilder sb = new StringBuilder(header); if (doc != null) { if (doc instanceof ProgramElementDoc) { - sb.append(getContainingClassOrPackageHeader((ProgramElementDoc)doc)); + sb.append(getContainingClassOrPackageHeader((ProgramElementDoc)doc, ctx)); } if (doc.isMethod() || doc.isConstructor() || doc.isAnnotationTypeElement()) { - sb.append(getMethodHeader((ExecutableMemberDoc)doc)); + sb.append(getMethodHeader((ExecutableMemberDoc)doc, ctx)); } else if (doc.isField() || doc.isEnumConstant()) { - sb.append(getFieldHeader((FieldDoc)doc)); + sb.append(getFieldHeader((FieldDoc)doc, ctx)); } else if (doc.isClass() || doc.isInterface() || doc.isAnnotationType()) { - sb.append(getClassHeader((ClassDoc)doc)); + sb.append(getClassHeader((ClassDoc)doc, ctx)); } else if (doc instanceof PackageDoc) { - sb.append(getPackageHeader((PackageDoc)doc)); + sb.append(getPackageHeader((PackageDoc)doc, ctx)); } sb.append("

"); //NOI18N if (!useJavadoc) { @@ -454,14 +519,14 @@ inheritedReturnTags != null && inheritedReturnTags.isEmpty() || paramPos != null && !paramPos.isEmpty() || throwsTypes != null && !throwsTypes.isEmpty()) { - String s = inheritedDocFor(mdoc, mdoc.containingClass(), inheritedTags, inheritedReturnTags, - paramPos, inheritedParamTags, inheritedParamInlineTags, - throwsTypes, inheritedThrowsTags, inheritedThrowsInlineTags, cancel); - if (s != null) { - sb.append(s); - sb.append("

"); //NOI18N - return sb; - } + String s = inheritedDocFor(mdoc, mdoc.containingClass(), inheritedTags, inheritedReturnTags, + paramPos, inheritedParamTags, inheritedParamInlineTags, + throwsTypes, inheritedThrowsTags, inheritedThrowsInlineTags, cancel, sync, ctx); + if (s != null) { + sb.append(s); + sb.append("

"); //NOI18N + return new Now(sb.toString()); + } } if (inheritedTags != null && !inheritedTags.isEmpty()) { if (inlineTags.length == 0) { @@ -542,42 +607,55 @@ } } if (inlineTags.length > 0 || doc.tags().length > 0) { - sb.append(getDeprecatedTag(doc)); - sb.append(inlineTags(doc, inlineTags)); + sb.append(getDeprecatedTag(doc, ctx)); + sb.append(inlineTags(doc, inlineTags, ctx)); sb.append("

"); //NOI18N sb.append(getMethodTags(mdoc, returnTags, paramTags, - throwsTags, throwsInlineTags)); + throwsTags, throwsInlineTags, ctx)); sb.append("

"); //NOI18N - return sb; + return new Now(sb.toString()); } } else { if (inlineTags.length > 0 || doc.tags().length > 0) { - sb.append(getDeprecatedTag(doc)); - sb.append(inlineTags(doc, inlineTags)); + sb.append(getDeprecatedTag(doc, ctx)); + sb.append(inlineTags(doc, inlineTags, ctx)); sb.append("

"); //NOI18N - sb.append(getTags(doc)); + sb.append(getTags(doc, ctx)); sb.append("

"); //NOI18N - return sb; + return new Now(sb.toString()); } } } - String jdText = page != null ? HTMLJavadocParser.getJavadocText(page, false) : docURL != null ? HTMLJavadocParser.getJavadocText(docURL, false) : null; - if (jdText != null) - sb.append(jdText); - else - sb.append(NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found")); //NOI18N - sb.append("

"); //NOI18N - return sb; + + final Callable call = new Callable() { + @Override + public String call() throws Exception { + String jdText = page != null ? HTMLJavadocParser.getJavadocText(page, false) : docURL != null ? HTMLJavadocParser.getJavadocText(docURL, false) : null; + if (jdText != null) + sb.append(jdText); + else + sb.append(NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found")); //NOI18N + sb.append("

"); //NOI18N + return sb.toString(); + } + }; + final FutureTask task = new FutureTask(call); + if (sync) { + RP.post(task); + } else { + task.run(); + } + return task; } sb.append(NbBundle.getMessage(ElementJavadoc.class, "javadoc_content_not_found")); //NOI18N - return sb; + return new Now (sb.toString()); } - private CharSequence getContainingClassOrPackageHeader(ProgramElementDoc peDoc) { + private CharSequence getContainingClassOrPackageHeader(ProgramElementDoc peDoc, Pair ctx) { StringBuilder sb = new StringBuilder(); ClassDoc cls = peDoc.containingClass(); if (cls != null) { - Element e = eu.elementFor(cls); + Element e = ctx.second.elementFor(cls); if (e != null) { switch(e.getEnclosingElement().getKind()) { case ANNOTATION_TYPE: @@ -596,7 +674,7 @@ PackageDoc pkg = peDoc.containingPackage(); if (pkg != null) { sb.append(""); //NOI18N - createLink(sb, eu.elementFor(pkg), makeNameLineBreakable(pkg.name())); + createLink(sb, ctx.second.elementFor(pkg), makeNameLineBreakable(pkg.name())); sb.append(""); //NOI18N) } } @@ -606,10 +684,10 @@ return name.replace(".", /* ZERO WIDTH SPACE */".​"); } - private CharSequence getMethodHeader(ExecutableMemberDoc mdoc) { + private CharSequence getMethodHeader(ExecutableMemberDoc mdoc, Pair ctx) { StringBuilder sb = new StringBuilder(); sb.append("

"); //NOI18N - sb.append(getAnnotations(mdoc.annotations())); + sb.append(getAnnotations(mdoc.annotations(), ctx)); int len = sb.length(); sb.append(Modifier.toString(mdoc.modifierSpecifier() &~ Modifier.NATIVE)); len = sb.length() - len; @@ -621,7 +699,7 @@ } sb.append("<"); //NOI18N for (int i = 0; i < tvars.length; i++) { - len += appendType(sb, tvars[i], false, true, false); + len += appendType(sb, tvars[i], false, true, false, ctx); if (i < tvars.length - 1) { sb.append(","); //NOI18N len++; @@ -635,7 +713,7 @@ sb.append(' '); //NOI18N len++; } - len += appendType(sb, ((MethodDoc)mdoc).returnType(), false, false, false); + len += appendType(sb, ((MethodDoc)mdoc).returnType(), false, false, false, ctx); } String name = mdoc.name(); len += name.length(); @@ -645,9 +723,9 @@ len++; Parameter[] params = mdoc.parameters(); for(int i = 0; i < params.length; i++) { - sb.append(getAnnotations(params[i].annotations())); + sb.append(getAnnotations(params[i].annotations(), ctx)); boolean varArg = i == params.length - 1 && mdoc.isVarArgs(); - appendType(sb, params[i].type(), varArg, false, false); + appendType(sb, params[i].type(), varArg, false, false, ctx); sb.append(' ').append(params[i].name()); //NOI18N String dim = params[i].type().dimension(); if (dim.length() > 0) { @@ -665,7 +743,7 @@ if (exs.length > 0) { sb.append(" throws "); //NOI18N for (int i = 0; i < exs.length; i++) { - appendType(sb, exs[i], false, false, false); + appendType(sb, exs[i], false, false, false, ctx); if (i < exs.length - 1) sb.append(", "); //NOI18N } @@ -674,25 +752,25 @@ return sb; } - private CharSequence getFieldHeader(FieldDoc fdoc) { + private CharSequence getFieldHeader(FieldDoc fdoc, Pair ctx) { StringBuilder sb = new StringBuilder(); sb.append("

"); //NOI18N - sb.append(getAnnotations(fdoc.annotations())); + sb.append(getAnnotations(fdoc.annotations(), ctx)); int len = sb.length(); sb.append(fdoc.modifiers()); len = sb.length() - len; if (len > 0) sb.append(' '); //NOI18N - appendType(sb, fdoc.type(), false, false, false); + appendType(sb, fdoc.type(), false, false, false, ctx); sb.append(" ").append(fdoc.name()).append(""); //NOI18N sb.append("

"); //NOI18N return sb; } - private CharSequence getClassHeader(ClassDoc cdoc) { + private CharSequence getClassHeader(ClassDoc cdoc, Pair ctx) { StringBuilder sb = new StringBuilder(); sb.append("

"); //NOI18N - sb.append(getAnnotations(cdoc.annotations())); + sb.append(getAnnotations(cdoc.annotations(), ctx)); int mods = cdoc.modifierSpecifier() & ~Modifier.INTERFACE; if (cdoc.isEnum()) mods &= ~Modifier.FINAL; @@ -712,7 +790,7 @@ if (tvars.length > 0) { sb.append("<"); //NOI18N for (int i = 0; i < tvars.length; i++) { - appendType(sb, tvars[i], false, true, false); + appendType(sb, tvars[i], false, true, false, ctx); if (i < tvars.length - 1) sb.append(","); //NOI18N } @@ -724,14 +802,14 @@ Type supercls = cdoc.superclassType(); if (supercls != null) { sb.append(" extends "); //NOI18N - appendType(sb, supercls, false, false, false); + appendType(sb, supercls, false, false, false, ctx); } } Type[] ifaces = cdoc.interfaceTypes(); if (ifaces.length > 0) { sb.append(cdoc.isInterface() ? " extends " : " implements "); //NOI18N for (int i = 0; i < ifaces.length; i++) { - appendType(sb, ifaces[i], false, false, false); + appendType(sb, ifaces[i], false, false, false, ctx); if (i < ifaces.length - 1) sb.append(", "); //NOI18N } @@ -741,29 +819,29 @@ return sb; } - private CharSequence getPackageHeader(PackageDoc pdoc) { + private CharSequence getPackageHeader(PackageDoc pdoc, Pair ctx) { StringBuilder sb = new StringBuilder(); sb.append("

"); //NOI18N - sb.append(getAnnotations(pdoc.annotations())); + sb.append(getAnnotations(pdoc.annotations(), ctx)); sb.append("package ").append(pdoc.name()).append(""); //NOI18N sb.append("

"); //NOI18N return sb; } - private CharSequence getAnnotations(AnnotationDesc[] annotations) { + private CharSequence getAnnotations(AnnotationDesc[] annotations, Pair ctx) { StringBuilder sb = new StringBuilder(); for (AnnotationDesc annotationDesc : annotations) { AnnotationTypeDoc annotationType = annotationDesc.annotationType(); if (annotationType != null && isDocumented(annotationType)) { - appendType(sb, annotationType, false, false, true); + appendType(sb, annotationType, false, false, true, ctx); ElementValuePair[] pairs = annotationDesc.elementValues(); if (pairs.length > 0) { sb.append('('); //NOI18N for (int i = 0; i < pairs.length; i++) { AnnotationTypeElementDoc ated = pairs[i].element(); - createLink(sb, eu.elementFor(ated), ated.name()); + createLink(sb, ctx.second.elementFor(ated), ated.name()); sb.append('='); //NOI18N - appendAnnotationValue(sb, pairs[i].value()); + appendAnnotationValue(sb, pairs[i].value(), ctx); if (i < pairs.length - 1) sb.append(","); //NOI18N } @@ -783,31 +861,31 @@ return false; } - private void appendAnnotationValue(StringBuilder sb, AnnotationValue av) { + private void appendAnnotationValue(StringBuilder sb, AnnotationValue av, Pair ctx) { Object value = av.value(); if (value instanceof AnnotationValue[]) { int length = ((AnnotationValue[])value).length; if (length > 1) sb.append('{'); //NOI18N for(int i = 0; i < ((AnnotationValue[])value).length; i++) { - appendAnnotationValue(sb, ((AnnotationValue[])value)[i]); + appendAnnotationValue(sb, ((AnnotationValue[])value)[i], ctx); if (i < ((AnnotationValue[])value).length - 1) sb.append(","); //NOI18N } if (length > 1) sb.append('}'); //NOI18N } else if (value instanceof Doc) { - createLink(sb, eu.elementFor((Doc)value), ((Doc)value).name()); + createLink(sb, ctx.second.elementFor((Doc)value), ((Doc)value).name()); } else { sb.append(value.toString()); } } private CharSequence getMethodTags(MethodDoc doc, Tag[] returnTags, Map> paramInlineTags, - List throwsTags, Map> throwsInlineTags) { + List throwsTags, Map> throwsInlineTags, Pair ctx) { StringBuilder ret = new StringBuilder(); if (returnTags.length > 0) { - ret.append(inlineTags(doc, returnTags)); + ret.append(inlineTags(doc, returnTags, ctx)); ret.append("
"); //NOI18N } StringBuilder par = new StringBuilder(); @@ -818,7 +896,7 @@ List tags = paramInlineTags.get(pos); Tag[] its = tags.toArray(new Tag[tags.size()]); if (its.length > 0) { - CharSequence cs = inlineTags(doc, its); + CharSequence cs = inlineTags(doc, its, ctx); if (cs.length() > 0) { par.append(" - "); //NOI18N par.append(cs); @@ -834,7 +912,7 @@ tpar.append("").append(pTag.parameterName()).append(""); //NOI18N Tag[] its = pTag.inlineTags(); if (its.length > 0) { - CharSequence cs = inlineTags(doc, its); + CharSequence cs = inlineTags(doc, its, ctx); if (cs.length() > 0) { tpar.append(" - "); //NOI18N tpar.append(cs); @@ -849,7 +927,7 @@ thr.append(""); //NOI18N Type exType = throwsTag.exceptionType(); if (exType != null) { - createLink(thr, eu.elementFor(exType.asClassDoc()), exType.simpleTypeName()); + createLink(thr, ctx.second.elementFor(exType.asClassDoc()), exType.simpleTypeName()); } else { thr.append(throwsTag.exceptionName()); } @@ -857,7 +935,7 @@ List tags = throwsInlineTags.get(exType != null ? exType.qualifiedTypeName() : throwsTag.exceptionName()); Tag[] its = tags == null ? throwsTag.inlineTags() : tags.toArray(new Tag[tags.size()]); if (its.length > 0) { - CharSequence cs = inlineTags(doc, its); + CharSequence cs = inlineTags(doc, its, ctx); if (cs.length() > 0) { thr.append(" - "); //NOI18N thr.append(cs); @@ -877,7 +955,7 @@ String label = stag.label(); if (memberName != null) { if (refClass != null) { - createLink(see, eu.elementFor(stag.referencedMember()), "" + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + ""); //NOI18N + createLink(see, ctx.second.elementFor(stag.referencedMember()), "" + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + ""); //NOI18N } else { see.append(className); see.append('.'); //NOI18N @@ -886,7 +964,7 @@ see.append(", "); //NOI18N } else if (className != null) { if (refClass != null) { - createLink(see, eu.elementFor(refClass), "" + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + ""); //NOI18N + createLink(see, ctx.second.elementFor(refClass), "" + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + ""); //NOI18N } else { see.append(className); } @@ -921,7 +999,7 @@ return sb; } - private CharSequence getTags(Doc doc) { + private CharSequence getTags(Doc doc, Pair ctx) { StringBuilder see = new StringBuilder(); StringBuilder par = new StringBuilder(); StringBuilder thr = new StringBuilder(); @@ -933,25 +1011,25 @@ Tag[] its = tag.inlineTags(); if (its.length > 0) { par.append(" - "); //NOI18N - par.append(inlineTags(doc, its)); + par.append(inlineTags(doc, its, ctx)); } par.append("
"); //NOI18N } else if (THROWS_TAG.equals(tag.kind()) && !doc.isMethod()) { thr.append(""); //NOI18N Type exType = ((ThrowsTag)tag).exceptionType(); if (exType != null) - createLink(thr, eu.elementFor(exType.asClassDoc()), exType.simpleTypeName()); + createLink(thr, ctx.second.elementFor(exType.asClassDoc()), exType.simpleTypeName()); else thr.append(((ThrowsTag)tag).exceptionName()); thr.append(""); //NOI18N Tag[] its = tag.inlineTags(); if (its.length > 0) { thr.append(" - "); //NOI18N - thr.append(inlineTags(doc, its)); + thr.append(inlineTags(doc, its, ctx)); } thr.append("
"); //NOI18N } else if (RETURN_TAG.equals(tag.kind()) && !doc.isMethod()) { - ret.append(inlineTags(doc, tag.inlineTags())); + ret.append(inlineTags(doc, tag.inlineTags(), ctx)); ret.append("
"); //NOI18N } else if (SEE_TAG.equals(tag.kind())) { SeeTag stag = (SeeTag)tag; @@ -961,7 +1039,7 @@ String label = stag.label(); if (memberName != null) { if (refClass != null) { - createLink(see, eu.elementFor(stag.referencedMember()), "" + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + ""); //NOI18N + createLink(see, ctx.second.elementFor(stag.referencedMember()), "" + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + ""); //NOI18N } else { see.append(className); see.append('.'); //NOI18N @@ -970,7 +1048,7 @@ see.append(", "); //NOI18N } else if (className != null) { if (refClass != null) { - createLink(see, eu.elementFor(refClass), "" + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + ""); //NOI18N + createLink(see, ctx.second.elementFor(refClass), "" + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + ""); //NOI18N } else { see.append(className); } @@ -1002,18 +1080,18 @@ return sb; } - private CharSequence getDeprecatedTag(Doc doc) { + private CharSequence getDeprecatedTag(Doc doc, Pair ctx) { StringBuilder sb = new StringBuilder(); for (Tag tag : doc.tags()) { if (DEPRECATED_TAG.equals(tag.kind())) { - sb.append("").append(NbBundle.getMessage(ElementJavadoc.class, "JCD-deprecated")).append(" ").append(inlineTags(doc, tag.inlineTags())).append("

"); //NOI18N + sb.append("").append(NbBundle.getMessage(ElementJavadoc.class, "JCD-deprecated")).append(" ").append(inlineTags(doc, tag.inlineTags(),ctx)).append("

"); //NOI18N break; } } return sb; } - private CharSequence inlineTags(Doc doc, Tag[] tags) { + private CharSequence inlineTags(Doc doc, Tag[] tags, Pair ctx) { StringBuilder sb = new StringBuilder(); for (Tag tag : tags) { if (SEE_TAG.equals(tag.kind())) { @@ -1035,7 +1113,7 @@ boolean plain = LINKPLAIN_TAG.equals(stag.name()); if (memberName != null) { if (refClass != null) { - createLink(sb, eu.elementFor(stag.referencedMember()), (plain ? "" : "") + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + (plain ? "" : "")); //NOI18N + createLink(sb, ctx.second.elementFor(stag.referencedMember()), (plain ? "" : "") + (label != null && label.length() > 0 ? label : (refClass.simpleTypeName() + "." + memberName)) + (plain ? "" : "")); //NOI18N } else { sb.append(stag.referencedClassName()); sb.append('.'); //NOI18N @@ -1043,7 +1121,7 @@ } } else { if (refClass != null) { - createLink(sb, eu.elementFor(refClass), (plain ? "" : "") + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + (plain ? "" : "")); //NOI18N + createLink(sb, ctx.second.elementFor(refClass), (plain ? "" : "") + (label != null && label.length() > 0 ? label : refClass.simpleTypeName()) + (plain ? "" : "")); //NOI18N } else { String className = stag.referencedClassName(); sb.append(className != null ? className : stag.text()); @@ -1054,7 +1132,7 @@ if (doc.isMethod()) { MethodDoc mdoc = ((MethodDoc)doc).overriddenMethod(); if (mdoc != null) - sb.append(inlineTags(mdoc, mdoc.inlineTags())); + sb.append(inlineTags(mdoc, mdoc.inlineTags(),ctx)); } } else if (LITERAL_TAG.equals(tag.kind())) { try { @@ -1115,7 +1193,7 @@ sb.append(' '); //NOI18N } - private int appendType(StringBuilder sb, Type type, boolean varArg, boolean typeVar, boolean annotation) { + private int appendType(StringBuilder sb, Type type, boolean varArg, boolean typeVar, boolean annotation, Pair ctx) { int len = 0; WildcardType wt = type.asWildcardType(); if (wt != null) { @@ -1125,13 +1203,13 @@ if (bounds != null && bounds.length > 0) { sb.append(" extends "); //NOI18N len += 9; - len += appendType(sb, bounds[0], false, false, false); + len += appendType(sb, bounds[0], false, false, false, ctx); } bounds = wt.superBounds(); if (bounds != null && bounds.length > 0) { sb.append(" super "); //NOI18N len += 7; - len += appendType(sb, bounds[0], false, false, false); + len += appendType(sb, bounds[0], false, false, false, ctx); } } else { TypeVariable tv = type.asTypeVariable(); @@ -1142,7 +1220,7 @@ sb.append(" extends "); //NOI18N len += 9; for (int i = 0; i < bounds.length; i++) { - len += appendType(sb, bounds[i], false, false, false); + len += appendType(sb, bounds[i], false, false, false, ctx); if (i < bounds.length - 1) { sb.append(" & "); //NOI18N len += 3; @@ -1154,14 +1232,14 @@ String tName = cd != null ? cd.name() : type.simpleTypeName(); if (cd != null && cd.isAnnotationType() && annotation) tName = "@" + tName; //NOI18N - len += createLink(sb, eu.elementFor(type.asClassDoc()), tName); + len += createLink(sb, ctx.second.elementFor(type.asClassDoc()), tName); ParameterizedType pt = type.asParameterizedType(); if (pt != null) { Type[] targs = pt.typeArguments(); if (targs.length > 0) { sb.append("<"); //NOI18N for (int j = 0; j < targs.length; j++) { - len += appendType(sb, targs[j], false, false, false); + len += appendType(sb, targs[j], false, false, false, ctx); if (j < targs.length - 1) { sb.append(","); //NOI18N len++; @@ -1198,12 +1276,12 @@ private String inheritedDocFor(MethodDoc mdoc, ClassDoc cdoc, List inlineTags, List returnTags, Set paramPos, Map paramTags, Map> paramInlineTags, Set throwsTypes, Map throwsTags, Map> throwsInlineTags, - Callable cancel) { + Callable cancel, boolean stopByRemoteJdoc, Pair ctx) throws RemoteJavadocException { JavadocHelper.TextStream inheritedPage = null; for (ClassDoc ifaceDoc : cdoc.interfaces()) { for (MethodDoc methodDoc : ifaceDoc.methods(false)) { if (mdoc.overrides(methodDoc)) { - Element e = eu.elementFor(methodDoc); + Element e = ctx.second.elementFor(methodDoc); boolean isLocalized = false; if (e != null) { inheritedPage = JavadocHelper.getJavadoc(e, cancel); @@ -1211,7 +1289,7 @@ docURL = inheritedPage.getLocation(); } if (!(isLocalized = isLocalized(docURL, e))) - trees.getTree(e); + ctx.first.getTree(e); } if (!isLocalized) { List inheritedInlineTags = null; @@ -1295,7 +1373,7 @@ inheritedParamPos != null && inheritedParamTags != null) inheritedDocFor(mdoc, ifaceDoc, inheritedInlineTags, inheritedReturnTags, inheritedParamPos, inheritedParamTags, inheritedParamInlineTags, - inheritedThrowsTypes, inheritedThrowsTags, inheritedThrowsInlineTags, cancel); + inheritedThrowsTypes, inheritedThrowsTags, inheritedThrowsInlineTags, cancel, stopByRemoteJdoc, ctx); if (inheritedInlineTags != null && !inheritedInlineTags.isEmpty()) { inlineTags.clear(); for (Tag tag : methodDoc.inlineTags()) { @@ -1350,13 +1428,16 @@ (throwsTypes == null || throwsTypes.isEmpty())) return null; } + if (stopByRemoteJdoc && isRemote(inheritedPage, docURL)) { + throw new RemoteJavadocException(); + } String jdText = inheritedPage != null ? HTMLJavadocParser.getJavadocText(inheritedPage, false) : docURL != null ? HTMLJavadocParser.getJavadocText(docURL, false) : null; if (jdText != null) return jdText; for (ClassDoc ifaceDoc : cdoc.interfaces()) { jdText = inheritedDocFor(mdoc, ifaceDoc, inlineTags, returnTags, paramPos, paramTags, paramInlineTags, - throwsTypes, throwsTags, throwsInlineTags, cancel); + throwsTypes, throwsTags, throwsInlineTags, cancel, stopByRemoteJdoc, ctx); if (jdText != null) return jdText; if ((inlineTags == null || !inlineTags.isEmpty()) && @@ -1370,7 +1451,7 @@ if (superclass != null) { //NOI18N for (MethodDoc methodDoc : superclass.methods(false)) { if (mdoc.overrides(methodDoc)) { - Element e = eu.elementFor(methodDoc); + Element e = ctx.second.elementFor(methodDoc); boolean isLocalized = false; if (e != null) { inheritedPage = JavadocHelper.getJavadoc(e, cancel); @@ -1378,7 +1459,7 @@ docURL = inheritedPage.getLocation(); } if (!(isLocalized = isLocalized(docURL, e))) - trees.getTree(e); + ctx.first.getTree(e); } if (!isLocalized) { List inheritedInlineTags = null; @@ -1463,7 +1544,7 @@ inheritedDocFor(mdoc, superclass, inheritedInlineTags, inheritedReturnTags, inheritedParamNames, inheritedParamTags, inheritedParamInlineTags, inheritedThrowsTypes, - inheritedThrowsTags, inheritedThrowsInlineTags, cancel); + inheritedThrowsTags, inheritedThrowsInlineTags, cancel, stopByRemoteJdoc, ctx); if (inheritedInlineTags != null && !inheritedInlineTags.isEmpty()) { inlineTags.clear(); for (Tag tag : methodDoc.inlineTags()) { @@ -1516,11 +1597,14 @@ returnTags != null && returnTags.isEmpty() || paramPos != null && !paramPos.isEmpty() || throwsTypes != null && !throwsTypes.isEmpty()) { + if (stopByRemoteJdoc && isRemote(inheritedPage,docURL)) { + throw new RemoteJavadocException(); + } jdText = inheritedPage != null ? HTMLJavadocParser.getJavadocText(inheritedPage, false) : docURL != null ? HTMLJavadocParser.getJavadocText(docURL, false) : null; return jdText != null ? jdText : inheritedDocFor(mdoc, superclass, inlineTags, returnTags, paramPos, paramTags, paramInlineTags, throwsTypes, - throwsTags, throwsInlineTags, cancel); + throwsTags, throwsInlineTags, cancel, stopByRemoteJdoc, ctx); } } return null; @@ -1536,4 +1620,45 @@ return -1; } + + private static boolean isRemote(final JavadocHelper.TextStream page, final URL url) { + return page != null ? page.getLocation().toString().startsWith("http") : url != null ? url.toString().startsWith("http") : false; + } + + private static final class Now implements Future { + + private final String value; + + Now(final String value) { + this.value = value; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public String get() throws InterruptedException, ExecutionException { + return value; + } + + @Override + public String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return value; + } + } + + private static class RemoteJavadocException extends Exception { + } }