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 252644 - Support jimage file in FileUtil.getArchiveFile, FileUtil.getArchiveRoot
Summary: Support jimage file in FileUtil.getArchiveFile, FileUtil.getArchiveRoot
Status: NEW
Alias: None
Product: platform
Classification: Unclassified
Component: Filesystems (show other bugs)
Version: 8.1
Hardware: All All
: P2 normal (vote)
Assignee: Tomas Zezula
URL:
Keywords: API, API_REVIEW
Depends on:
Blocks:
 
Reported: 2015-05-28 11:36 UTC by Tomas Zezula
Modified: 2015-11-30 19:09 UTC (History)
7 users (show)

See Also:
Issue Type: TASK
Exception Reporter:


Attachments
Diff file (44.37 KB, patch)
2015-05-28 11:42 UTC, Tomas Zezula
Details | Diff
Diff with renamed isArchiveRoot method (35.44 KB, patch)
2015-11-06 15:59 UTC, Tomas Zezula
Details | Diff
Diff with renamed isArchiveRoot method (35.44 KB, patch)
2015-11-06 17:42 UTC, Tomas Zezula
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tomas Zezula 2015-05-28 11:36:43 UTC
The JDK 9 introduces a new java archive file format (jimage). The bootstrap libraries are no more bundled in rt.jar but in JDK's image(s). The content of these images is accessible using a NIO FS provider for given JDK. Each JDK instance may have different jimage NIO FS provider and different jimage format. So the JDK's NIO FS provider needs to be used to access given JDK's classes. The jrt scheme introduced by the NIO FS provider creates URLs with no information about the JDK installation folder, for example: jrt:/java.base/java/lang/Object.class.

To support several platforms NB defines a nbjrt scheme having both path to JDK install folder and a path in the jimage, for example: nbjrt:file///opt/jdk9!/java.base/java/lang/Object.class

The nbjrt protocol is similar to jar protocol. Both these protocols address files in an archive and both are opaque. It makes a sense to extend the FileUtil.getArchiveFile() and FileUtil.getArchiveRoot() to support them. Such a support has to be pluggable as jimage support (NetBeans FileSystem, URLStreamHandler, URLMapper) come from non filesystem module (java.j2seplatform).

Another problem is a following pattern (taken from FileOwnerQuery):
        if ("jar".equals(uri.getScheme())) {
            try {
                URL jar = FileUtil.getArchiveFile(uri.toURL());
                if (jar != null) {
                    uri = jar.toURI();
                }
            } catch (Exception x) {
                LOG.log(Level.INFO, null, x);
            }
        }
        if (!uri.isAbsolute() || uri.isOpaque()) {
            throw new IllegalArgumentException("Bad URI: " + uri); // NOI18N
        }

where just a jar protocol is unwrapped causing IAE on nbjrt URIs.
To address this problem a FileUtil.isArchiveRoot(URL) was added.
The same pattern rewritten to the FU.iAR which works with nbjrt potocol:

       try {
            URL url = uri.toURL();
            if (FileUtil.isArchiveRoot(url)) {
                url = FileUtil.getArchiveFile(url);
                if (url != null) {
                    uri = url.toURI();
                }
            }
        } catch (MalformedURLException | URISyntaxException e) {
            LOG.log(Level.INFO, null, e);
        }
        if (!uri.isAbsolute() || uri.isOpaque()) {
            throw new IllegalArgumentException("Bad URI: " + uri); // NOI18N
        }



The upgrade hints are a part of a patch but they are disabled as such an upgrade should not happen automatically. There is a plenty of code which should not be upgraded (more than code which should be upgraded), as an example: PlatformNode.java

FileObject file;
Icon icon;
Icon openedIcon;
if ("jar".equals(roots[i].toURL().getProtocol())) { //NOI18N
  file = FileUtil.getArchiveFile (roots[i]);
  icon = openedIcon = ImageUtilities.loadImageIcon(ARCHIVE_ICON, false);
} else {
  file = roots[i];
  icon = null;
  openedIcon = null;
}
String displayName = file.getNameExt();

where just the "jar" should be handled. In case of "nbjrt" the getArchiveFile() call will remove the path in jar which is the module name.


The SPI uses JDK 8 language features as it will be integrated into NB 9.0 which will require JDK 8.


Open questions:
Should the FileUtil be extended by methods preserving the path in archive like:

getArchiveArtefact(archiveFile, relativePathInArchive) replacement for getArchiveRoot.

getArchiveFileAndPath(archiveArtefact) returning Pair<URL,String> an URL of an archive file and relative path in the archive file.
Comment 1 Tomas Zezula 2015-05-28 11:42:59 UTC
Created attachment 153920 [details]
Diff file
Comment 2 Tomas Zezula 2015-06-02 09:01:27 UTC
Usage of isArchiveRoot in the debugger.jpda: http://hg.netbeans.org/jet-main/rev/3393535cf2a2
The code converts classpath URLs to the paths preserving the relocation in the archive and back.

This may be a requirement for methods returning the path in archive as I described above.
Comment 3 Tomas Zezula 2015-06-02 11:54:12 UTC
FileUtil.archiveOrDirForURL(URL) uses FU.isArchiveRoot() and FU.getArchiveFile() but keeping the semantic compatibility. For URLs with path inside an archive return null.
Even if such a behaviour is strange it probably cannot be changed as it's documented in Javadoc and covered by unit tests.

http://hg.netbeans.org/jet-main/rev/4c53ebc6155f
Comment 4 Jaroslav Havlin 2015-11-02 15:22:26 UTC
Thank you very much, Tomas, for describing the problem and writing the patch.

The only thing that seems a little confusing to me is name of methods "isArchiveRoot(FileObject)". I would expect that such method returns true only if the passed FileObject is the root directory (/) contained in the archive, but the method returns true if the FileObject is just "inside an archive".
So, name like "isInsideArchive" would sound more correct to me :-)

> Open questions:
> Should the FileUtil be extended by methods preserving the path in archive like:
> getArchiveArtefact(archiveFile, relativePathInArchive) ...
> getArchiveFileAndPath(archiveArtefact) ...
As this is would make code in debugger (and possibly in other modules) simpler, we can add these methods to FileUtil, I think.

What about having getArchiveFileAndPath for both URL and FileObject?
(Maybe URL version will be sufficient, I don't know much about the use-cases.)
Signatures could be be like this:

FileObject               getArchiveArtefact(FileObject archiveFile, String relativePathInArchive)
Pair<FileObject, String> getArchiveFileAndPath(FileObject archiveArtefact) // FileObject version
Pair<URL, String>        getArchiveFileAndPath(URL archiveArtefact)        // URL version

Is is what you meant?
Comment 5 Tomas Zezula 2015-11-02 21:50:46 UTC
Thanks Jardo for review.
The isArchiveRoot comes from getArchiveFile <-> getArchiveRoot naming which we already have in the FileUtil. There is already isArchiveFile, so I've added the isArchiveRoot.
The isInsideArchive is fine for me.

Regarding the getArchiveArtifact and getArchiveArtifactAndPath I agree that thare should be versions for both URL and FileObject. I believe they do not need changes in SPI just adding the methods into FileUtil. I have already such methods in java.j2seplatform and probably debugger.jpda. I will check and attach a link.
Comment 6 Jaroslav Havlin 2015-11-03 14:39:58 UTC
(In reply to Tomas Zezula from comment #5)
> Thanks Jardo for review.
> The isArchiveRoot comes from getArchiveFile <-> getArchiveRoot naming which
> we already have in the FileUtil. There is already isArchiveFile, so I've
> added the isArchiveRoot.
> The isInsideArchive is fine for me.
I see.
What about boolean isArchiveArtefact(FileObject) or boolean canGetArchiveFile(FileObject)?
(Although it would be more consistent with rest of archive-related API, isInsideArchive sounds more natural to me.)


> Regarding the getArchiveArtifact and getArchiveArtifactAndPath I agree that
> thare should be versions for both URL and FileObject. I believe they do not
> need changes in SPI just adding the methods into FileUtil. I have already
> such methods in java.j2seplatform and probably debugger.jpda. I will check
> and attach a link.
Thank you very much.
Comment 7 Tomas Zezula 2015-11-06 15:44:37 UTC
Thanks Jardo!
The isArchiveArtefact sounds best to me, so I've used it.

Regarding the getArchiveArtifact and getArchiveArtifactAndPath I will create a new API review for these utility methods as they are independent to this SPI and base API.
Comment 8 Tomas Zezula 2015-11-06 15:59:50 UTC
Created attachment 157191 [details]
Diff with renamed isArchiveRoot method
Comment 9 Tomas Zezula 2015-11-06 17:42:19 UTC
Created attachment 157193 [details]
Diff with renamed isArchiveRoot method

I've changed the "isArchiveArtefact" to "isArchiveArtifact" as the "Artifact" is more common in NetBeans APIs (eg. AntArtifact).
Comment 10 Quality Engineering 2015-11-30 19:09:30 UTC
Integrated into 'main-silver', will be available in build *201511301649* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)

Changeset: http://hg.netbeans.org/main-silver/rev/9bab0452ef4d
User: Tomas Zezula <tzezula@netbeans.org>
Log: #252644:Support jimage file in FileUtil.getArchiveFile, FileUtil.getArchiveRoot