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.
In the proposed solution the current NetBeans JNLP installer will not be present and the nbm files will not be used. Download of the class files (and others) would be handled by JNLP. Then only information required for the module system to work is from what module the class comes from. I propose to solve this by packing the jars in following way: if we have class xyz.Foo i propose to use following path inside the jar: mymodule1.1/xyz/Foo.class. With this layout and with some additional information available as some XML file the module system could work as it works now but load the classes by the classloader of the JNLP client. The additional information would have to be provided by some servlet similarly as it is now. The output of this servlet should tell the module system what modules and in what directories are available. From the user perspective the proposed solution would seem as if only the JNLP client is used. But I propose to still use the regular splash for the NetBeans framework startup (as it is now without the installer and nbm unpacker). JNLP classloader shouldn't be directly used IMHO since it "flattens" the classpath and does not allow for the module system functionality - managing dependencies, code isolation etc. I hope that the delegating approach (special classloaders delegating to the JNLP classloader) can work. Deployment solution: the build scripts would build jar files for the JNLP server solution. The contents of the jar files would contain one additional directory besides the normal content. The jnlp file (currently nb-launch.jnlp) + maybe one additional descriptor xml file could be generated dynamically by some servlet (index servlet). The configuration of the client would be determined by those two servlets (or by one if I am able to squeeze it into .jnlp file). The classes that would have to be modified in core: totally rewrite: http://www.netbeans.org/source/browse/core/src/org/netbeans/core/modules/ModuleList.java http://www.netbeans.org/source/browse/core/src/org/netbeans/core/modules/InstalledFileLocatorImpl.java http://www.netbeans.org/source/browse/core/bootstrap/src/org/netbeans/JarClassLoader.java partially rewrite: couple of other classes from org/netbeans/core/modules/ like http://www.netbeans.org/source/browse/core/src/org/netbeans/core/modules/Module.java and http://www.netbeans.org/source/browse/core/bootstrap/src/org/netbeans/Main.java Current status ------------------- I have quite messy changes in the NetBeans module system. They include a class called DelegatingClassLoader - it is a replacement for the JarClassLoader. In the current state I am able to load classes using the DelegatingClassLoader - not completely working but at least a rough idea works (getting the JNLP classloader and delegating the finding of the resource). I did not implement the list of modules functionality. Further work ------------------ 1. implement loading the list of modules from some xml file or from the jnlp file 2. change build scripts to package the modules according to the proposal 3. debug and polish hacks from the current state of the prototype
Re. "only information required for the module system to work is from what module the class comes from" - this information is probably worthless in a JNLP scenario; it is only used by InstanceDataObject to tell when to not load a setting when a module is disabled. But you would not have this situation under JNLP, I suppose. Also this kind of class-based settings persistence is planned for complete replacement in the next NB version (cf. nbdev discussions on the new Convertor API, which will not need such information ever). Even with a flat classpath, the association from class to module is easily available, should you ever need it, by using Class.protectionDomain.codeSource.location and comparing to that of known JAR manifests - maybe in other ways too, e.g. java.lang.Package. Re. "module system functionality - managing dependencies, code isolation etc." - IMHO all this is useless under JNLP since you control the module set that is provided. All of these features ultimately serve *only* the purpose of permitting binary-compatible upgrades of sections of the NB installation without any changes to existing sections. Under JNLP-style server distribution this is not an issue. If you don't have such requirements (or others, like componentized security, that are not met by NB anyway), you might as well use the plain Java classpath - simpler and probably more efficient. Re. classes to rewrite - if you just load everything directly from the JNLP class loader, things are much simpler, I think. org.netbeans.core.modules.Module already works correctly with classpath modules, AFAIK. ModuleList would just be a no-op - no JARs to list. InstalledFileLocatorImpl of course needs to be replaced (you can do this with a fresh class registering itself in META-INF/services, rather than patching the original impl). JarClassLoader doesn't need to be touched - it simply won't be used, since there won't be any non-classpath modules. Main & similar org.netbeans.core.* classes just need to be patched a little bit to not halt when it discovers that there is no $userdir/modules dir nor $nbhome/modules dir; generally, to rely less on the existence of these directories. I feel that all the required changes could be kept small and harmless enough to be left permanently in the NB core code, with a small JNLP-specific piece of code activated in JNLP mode (e.g. by adding a special JAR to the classpath with a few overriding service impls, where this JAR is not normally part of the distribution). Also if you use a flat CP, there is no need for any list of modules. The existing module system code already autodiscovers this by looking for META-INF/MANIFEST.MF resources. Really the only things that shouldn't work "out of the box" with a flat CP are (1) overlapping packages and so on, which you can just solve by cleaning up library usage among modules you include, (2) the standard InstalledFileLocator impl, since you need one that knows where to look for things, (3) module management UI - of course all modules will be listed, but you will not be able to disable them.
Suppose you have xyz10 and xyz12 (when 10 being version 1.0 and 12 being version 1.2 of xyz). And a bunch of code depending on xyz. Moreover you have managed to update only part of those depending modules. So you need to have both xyz10 and xyz12 for all things to work. This scenario could not be supported by the flat classloader. If we drop this usecase than I am not aware of any other. But we have to decide whether we need this or not.
"Suppose you have xyz10 and xyz12 (when 10 being version 1.0 and 12 being version 1.2 of xyz). And a bunch of code depending on xyz. Moreover you have managed to update only part of those depending modules." - i.e., some incompatible change made to an API module without changing the package name(s). In that case of course you need to update everything depending on the old version in order to use the new version. Typically though the actual updating of code is not so hard - that is what refactoring tools are for, to help speed it up. Most incompatible changes that are kept in the same package tend to be pretty small things anyway, like adding a method to an interface, where it is generally clear what you need to do in order to upgrade. In cases where you are completely redesigning a whole subsystem, of course the matching code changes elsewhere are more complex. But either (1) the subsystem is a "pure" library, in which case you should just be changing package names anyway, which works fine in a flat classpath; or (2) binary compatibility with the old API requires some sort of runtime bridge or compatibility wrapper, which is usually also a lot of work to develop, and is going to require lots of QA time to verify - you are unlikely to save engineering effort relative to just updating your other code. The harder part (at least in my experience) is usually dealing with deployment-time binary incompatibilities and infrastructure to support incremental updates in the field, including warning users of possible problems, etc. This issue vanishes under a JNLP-type system since you completely control what goes into the module configuration, and don't publish anything until you are sure it all works together smoothly. (I am assuming we are talking about situations where you are basically in control of the modules you are publishing to the JNLP server. If you are including third-party modules that you did not write, and whose source code you either have no access to or do not understand, then you are in trouble if you cannot use runtime compatibility bridges. However if there are bugs in the third-party code, good luck fixing them!) Of course if you are doing the implementation work, it is up to you to decide what you need. I am just saying that I doubt a release of the standard NB distribution would want to have coexisting binary-incompatible modules to begin with, and I doubt any Sun product would find this acceptable either. On the other hand, if support for per-module class loaders in JNLP turns out to have a relatively simple or well-isolated implementation that is not a maintenance problem for the rest of the module & startup system, then there is no harm in supporting it, if someone finds it useful. (BTW I am assuming that your proposed class loading system still uses JNLP's native JAR diff/download, so the way in which classes are loaded is mainly an internal detail.)
See issue #29128: probably if NB/JNLP uses the classpath, it will not want to include boot.jar. (It *could* but it should not need it.) So registration of the security manager, currently somewhere in core.jar, should be moved to boot.jar (org.nb.Main) so that NB/JNLP does not call it. Whatever permissions are configured by JNLP itself should be enough. (Though you will need to check up on registration of URLStreamHandlerFactory - does JNLP permit this? NB needs it. I have long wanted to clean up all registration of VM-global things in NB, since they cause major problems for (1) unit tests, (2) NB-based tools like the <makeparserdb> Ant task.) Re. use of ProxyClassLoader - (1) Module uses it if and only if you create a module from JAR (which NB/JNLP never would if using classpath), but still it statically refers to the class. (2) ModuleManager currently uses it *always*, for systemClassLoader, even though with all modules in the classpath it could simply return ClassLoader.systemClassLoader (i.e. the app startup loader), and disable all the code to set the Thread.contextClassLoader. Probably all the code in org.netbeans.core.modules.* which deals with Proxy/JarClassLoader or creates class loaders at all, should be factored out into a simple interface with an impl in Lookup, so that NB/JNLP (if using classpath) could provide a trivial alternate impl and not use boot.jar classes in any way. This (cleaning up org.netbeans.core.modules.* as above) will be a bit of work, hopefully not much. I may have time to help with that. Also core-execution.jar currently registers SecurityManager extensions to TopSecurityManager. This also needs to be worked on. (1) If there is no TopSecurityManager, of course it can't do that. Maybe the registration could be declarative - e.g. add SM instances to META-INF/services Lookup? NB/JNLP would then just ignore the registration. (2) What happens if these SM hooks are not run, during execution? System.exit() calls from executed processes will probably really halt the VM, rather than stop the task. This is probably only a problem for users of JavaThreadExecutor, which is somewhat deprecated anyway. External execution, Ant, etc. should not have this problem. (All other code in TopSecurityManager seems to be miscellaneous stuff we could do without, including some startup optimizations.)
Jesse, thanks for the offer to help with this. I just need to do the changes as patches to release35. So if you do something in trunk I will backport your changes to release35 on my private branch. Also during next 2-3 weeks I will not yet work on this. I plan to finish the zeroadmin module (that is sort of connected to this work) and implement one more feature before I really star to to work on this one. So there is at least for me still some time for discussion what should be done here. I am also waiting for a management decision whether we will need to support two versions of the same class simultaneously loaded by the platform (the incompatible API change issue you mentioned previously). I should know this some time next week. Also my goal is for all the changes that would allow JNLP start to be done such they can stay in trunk (4.0 or whatever). As I said it is ok for me to support release35 on a private branch. But even there the goal is to have the changes as little as possible. Currently my changes are on branch platform_32247. Please note that I was using special string "memory" as a value of "netbeans.user" to indicate that we in fact run without the user dir. I thought about using the same for "netbeans.home" and having null only in "netbeans.dirs". What do you think? Also is the state of the module system you are talking about from release35 or were you talking about trunk? I would like to backport as little as possible.
The new version of my patches to core on branch platform_32247 is in the cvs. I have added also a new documentation for the prefixed solution. I have changed the installer/jnlp/build.xml to build the prefix solution. I know that my changes to the core's module system classes might be more chaotic than acceptable for the trunk. But I would really like to have the solution in the trunk. I am ready to work on the trunk version. Why had I implemented the prefix solution: the requirement to support two versions of the same class is mandatory for me. The rationale behind the decision are following: our product will contain quite a huge number of modules. The modules will depend on 3rd party libs. Different modules can depend on different versions of the libs - so we have to support loading the different versions of the libs at the same time. The flat classloader cannot do this - and we don't have full control of the all the jar files making our product. The new doc is here: http://installer.netbeans.org/docs/jnlpInstaller2.html.
I think this issue is obsoleted by Jarda's new implementation.
*** Bug 232119 has been marked as a duplicate of this bug. ***