This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 200813 - Outline jar dependent on general netbeans platform APIs
Summary: Outline jar dependent on general netbeans platform APIs
Status: RESOLVED FIXED
Alias: None
Product: platform
Classification: Unclassified
Component: Outline&TreeTable (show other bugs)
Version: 7.0.1
Hardware: PC Windows XP
: P2 normal (vote)
Assignee: Martin Entlicher
URL:
Keywords: REGRESSION
Depends on:
Blocks:
 
Reported: 2011-08-10 04:49 UTC by err
Modified: 2011-09-02 20:50 UTC (History)
1 user (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description err 2011-08-10 04:49:46 UTC
The outline and etable packages are supposed to be usable as standalone jars, the docs, http://bits.netbeans.org/dev/javadoc/org-netbeans-swing-outline/overview-summary.html, say:

    This module has no dependencies on the rest of the NetBeans modules
    and can be used as a standalone jar. 

The following change breaks this

changeset:   175261:358d3ae347f9
user:        mentlicher@netbeans.org
date:        Wed Aug 04 18:22:50 2010 +0200
summary:     #183322 Use HtmlRenderer to make HTML rendering faster than Swing.


If the flag "swingRendering" in DefaultOutlineCellRenderer is set something like:

    private static final boolean swingRendering
        = Boolean.getBoolean("nb.useSwingHtmlRendering")
            || staticMethodUsingRefectionToCheckForHtmlRenderer(); //NOI18N

then there's no regression.
Comment 1 Martin Entlicher 2011-09-01 13:43:42 UTC
The fix using reflection is not nice at all, but I've verified that it is possible to obtain the HtmlRenderer class from a different module via reflection.
Therefore in this special case I'll fix it that way.
Comment 2 Martin Entlicher 2011-09-01 14:21:08 UTC
The Outline module dependency is cleaned, reflection is used to access the HtmlRenderer. This dirty solution is justified by the possibility to use Outline outside of NetBeans.
Fixed by changeset:   200468:c1fd4b79c6a9
http://hg.netbeans.org/main/rev/c1fd4b79c6a9
Comment 3 err 2011-09-01 14:23:41 UTC
> fix using reflection ...
> obtain the HtmlRenderer class from a different module via reflection

I don't have access to my development environment right now; but my recolection is that "staticMethodUsingRefectionToCheckForHtmlRenderer" could simply do something like 'Class.forName("...")' to see if the local renderer is available. Then, since the flag "swingRendering" is true, there is no attempt to create or use the NB renderer. I believe there is no need to change module dependencies and/or how the nb-renderer is created.

In particular, in my app that uses outline.jar I simply do
    System.setProperty("nb.useSwingHtmlRendering", "true");
and use the 7.0 out of the box jar and everything works fine.
Comment 4 Martin Entlicher 2011-09-01 14:31:45 UTC
Yes, I've did it in a similar way. However, I must use reflection because of the compilation. Also, the class loader system in NetBeans would not allow to directly access classes from different modules without proper module dependency.
Comment 5 err 2011-09-01 14:38:28 UTC
(There was a mid-air collision on  my last comment #3, but I submitted it anyway since it I belive it points to a simpler fix)

I just took a quick look at the fix. I reopened this bug since checking for Lookup is unreliable since Lookup is in another one of those jars that is commonly used outside of the netbeans platform.

In comment 4:
> I must use reflection because of the compilation.

Do you mean so that it can be compiled outside of NetBeans? I didn't think that was a requirement.
Comment 6 err 2011-09-01 14:39:20 UTC
Actually reopen as mentioned in comment 5 (another mid air)
Comment 7 Martin Entlicher 2011-09-01 15:02:55 UTC
I'm sorry, but I'm not able to fix it without the Lookup class. It's explained in the comment in the code. In NetBeans, you will always have the Lookup class available.

Module org.openide.awt depends on the Lookup anyway, therefore it can not be used separately. Therefore I do not see a problem with checking for the Lookup class.
Comment 8 err 2011-09-01 16:08:34 UTC
Having the dependency
    import org.openide.awt.HtmlRenderer;
does not prevent the usage of outline in a standalone, not NB, environment. (as long as it is not referenced at run time)

There seems to be some confusion, module dependencies have no meaning when jars are taken from NB and used in a standalone app.

Consider a standlone app that has both
    org-netbeans-swing-outline.jar
    org-openide-util-lookup.jar
HtmlRenderer.canUse() will return true in this case because
    ClassLoader.getSystemClassLoader().loadClass("org.openide.util.Lookup")
will succeed, but that is an error.

NOTE: I worked around the problem by doing
    System.setProperty("nb.useSwingHtmlRendering", "true");
and made no changes to the 7.0 outline.jar. That means all you have to do is correctly set the "swingRendering" flag and make no other changes to
    org/netbeans/swing/outline/DefaultOutlineCellRenderer.java

The current change does not fix the problem, AFAICT.
Comment 9 Jesse Glick 2011-09-01 16:46:19 UTC
(In reply to comment #7)
> I'm not able to fix it without the Lookup class.

Note that it is possible to use Thread.currentThread().getContextClassLoader() to find HtmlRenderer if running within a flat classpath (e.g. unit test) or NB module system. However this does not work in OSGi mode, which is why the fix of bug #182507 permits a ClassLoader to be injected into o.n.swing.plaf (in which a direct Lookup dependency is also forbidden).

But your current approach of using Lookup.getDefault().lookup(ClassLoader.class) is fine too, even in OSGi mode, so long as err's complaint is addressed that you recover gracefully from the case that org-openide-util-lookup.jar is in the classpath but the ClassLoader from Lookup is either null (e.g. no module system) or cannot load HtmlRenderer (e.g. running a small platform app not including openide.awt).
Comment 10 err 2011-09-01 17:55:31 UTC
> ... e.g. running a small platform app not including openide.awt ...

Ah, none of my comments considered various configurations of an RCP (I only thought IDE vs standalone jars). More complexities than I thought.

Is the code that creates the renderer through reflection necessary? Is it sufficient to check if the NB HtmlRenderer is accessible at runtime and simply not reference if not available? I'm wondering what case/situation I'm not considering.
Comment 11 Jesse Glick 2011-09-01 20:10:33 UTC
(In reply to comment #10)
> Is it
> sufficient to check if the NB HtmlRenderer is accessible at runtime and simply
> not reference if not available?

Not generally. It is up to the JVM how aggressively to resolve class linkages; in fact -Xverify:none (which used to be used in NB release builds) changes this semantics even for the same JVM. Anyway the NB module build harness will refuse to let you even compile against classes without a module dependency.

Reflection can be avoided only by factoring out the interaction between openide.awt and o.n.swing.outline into an optional interface, with the implementation either manually injected by some bit of NB startup code (only useful in case you are running the whole app rather than just dropping JARs in your classpath), or placed into a third eager module and discovered using e.g. ServiceLoader, or otherwise made available when it is needed.
Comment 12 Jesse Glick 2011-09-01 20:12:06 UTC
(In reply to comment #11)
> discovered using e.g. ServiceLoader

...although this by default uses the CCL, which again is not available in OSGi mode. In the absence of a standard Java module system, probably direct injection from GuiRunLevel or the like is the only alternative to reflection.
Comment 13 Martin Entlicher 2011-09-02 07:11:23 UTC
I think that the fix is fine.
Of course the corner case that Lookup class is available but HtmlRenderer is not is handled in the code, you will not encounter any problems.

What I can do more is to try to find out the HtmlRenderer class via different ways. It should work also when you just extract the HtmlRenderer class from the org.openide.awt and add it on classpath. So this is probably what remains to do...
Comment 14 Martin Entlicher 2011-09-02 08:00:54 UTC
> Note that it is possible to use
> Thread.currentThread().getContextClassLoader() to find HtmlRenderer

Thanks for that suggestion, I've incorporated it to the refined fix.

> Reflection can be avoided only by factoring out the interaction between
> openide.awt and o.n.swing.outline into an optional interface

Since the use of HtmlRenderer is localized to just two method invocations, this is not worth the effort IMHO.

In changeset:   200720:b4faa6e6a379 the HtmlRenderer class is retrieved via several approaches. When it's found it's used, when it's not found it's not used.
http://hg.netbeans.org/main/rev/b4faa6e6a379
Comment 15 err 2011-09-02 14:14:38 UTC
> Of course the corner case that Lookup class is available but HtmlRenderer is
> not is handled in the code, you will not encounter any problems.

> HtmlRenderer class is retrieved via several approaches.
> When it's found it's used, when it's not found it's not used.


I didn't study the initial fix sufficiently (I'm on vacation (not that that's an excuse)). I was confused by the name "canUse" thinking a true implied the local renderer would be used. Sorry for the noise.
Comment 16 Quality Engineering 2011-09-02 20:50:50 UTC
Integrated into 'main-golden'
Changeset: http://hg.netbeans.org/main-golden/rev/b4faa6e6a379
User: mentlicher@netbeans.org
Log: #200813 Refining of the fix - try to find out HtmlRenderer class in various ways.