Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for JSF 4.0 namespaces #6160

Merged

Conversation

asbachb
Copy link
Collaborator

@asbachb asbachb commented Jul 7, 2023

Previously NetBeans bundles the JSF reference implementation Mojarra in order to provide several functionality
(like namespaces) based on the parsed taglib xml files from that jar. This is somehow problematic as:

  1. The dependency needs to be updated on every new JSF release
  2. NetBeans needs to fulfil the expectations of Mojarra

This leads to the problem that we currently cannot update and bundle the latest Mojarra version as
Java 11 is required.

This change wants to get less dependant on that bundled JSF implementation by resolving the reference implementation
using maven. Instead of reading the taglib xml files from that bundled jar NetBeans now gets in from the local maven
repository or downloads it from maven central. If this is not possible we fallback to the bundled version.

This change also improves the situation when autosuggestion is invoked in the namespace part of JSF xhtml documents
by ordering the suggested namespace with the one on top which is most likely to be used.

@morvael
Copy link

morvael commented Jul 7, 2023

Will be glad to give it a spin, once a built version is available. I hope this solved taglib 4.0 files issue as well.

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

The maven code might need some improvement. I'm not 100% sure if it respects the local maven settings (proxy, central repository override for company environments).

@morvael
Copy link

morvael commented Jul 7, 2023

NB should offer access to its configured maven or at least the settings for it, no?

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

@morvael Indeed, but I'm not 100% sure I got the correct API.

Created a preview build of this PR: https://impl.it/NetBeans-dev-dev-ddb8fbfc0816b3179736c22f91679f1ac434e491-enterprise.zip

@morvael
Copy link

morvael commented Jul 7, 2023

Help works, it nicely suggests new namespace name when completing xmlns:ui="
info2

The only thing that is missing is recognizing taglib 4.0.

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

@morvael Can you be a little bit more specific what you're missing?

@morvael
Copy link

morvael commented Jul 7, 2023

re taglib

I have my own taglib registering a converter. It works as long as the declaration is set to:

<facelet-taglib version="2.2"
                xmlns="http://xmlns.jcp.org/xml/ns/javaee"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">

It stops working when switched to

<facelet-taglib version="4.0"
                xmlns="https://jakarta.ee/xml/ns/jakartaee"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-facelettaglibrary_4_0.xsd">

Even though it's just like described in https://jakarta.ee/xml/ns/jakartaee/web-facelettaglibrary_4_0.xsd

Tag turns red and attributes are no longer recognizable, and the xhtml file using the tag is highlighted with red icon.

@morvael
Copy link

morvael commented Jul 7, 2023

There's also this logged in the IDE log, might not be because of your change, but since it mentions something Jsf related I thought I'll include it:
exception.txt

Not sure if this is related to this one following it:
Even though the source level of .../src/main/java:.../src/main/webapp:.../src/main/resources is set to: 11, java.util.zip.CRC32C cannot be found on the system module path:
I have IDE running on JDK17, project compiles with JDK17 though source/binary format is kept as 11. Might be unrelated NB bug :)

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

@morvael May I ask you to provide an example project? Would be easier for me to figure out what's going on with that.

@morvael
Copy link

morvael commented Jul 7, 2023

I'll try to make one. Give me some time.

@morvael
Copy link

morvael commented Jul 7, 2023

Trying to make vanilla Web Application with Ant, but it seems it doesn't know about any JSF libraries and doesn't allow to switch from JSP to Facelets.
Screenshot at 2023-07-07 09-36-26

@morvael
Copy link

morvael commented Jul 7, 2023

Oops, a bug, seems in your new code (or it's old code):
Screenshot at 2023-07-07 09-38-40
Cannot invoke "org.netbeans.modules.web.jsfapi.api.JsfVersion.isAtLeast(org.netbeans.modules.web.jsfapi.api.JsfVersion)" because "jsfVersion" is null

@morvael
Copy link

morvael commented Jul 7, 2023

So, going with maven project then, at least there wizard can be completed.

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

Oops, a bug, seems in your new code (or it's old code): Screenshot at 2023-07-07 09-38-40 Cannot invoke "org.netbeans.modules.web.jsfapi.api.JsfVersion.isAtLeast(org.netbeans.modules.web.jsfapi.api.JsfVersion)" because "jsfVersion" is null

That Exception is caused by the new code right. On the other hand I tried the same with NetBeans 18 which also seems not to work. So that Exception might new, but I guess the feature is already broken in NB18.

Edit: NB18 JSF 2.3 seems to work.

@morvael
Copy link

morvael commented Jul 7, 2023

Lol, default maven web project does not compile as it pulls so old war plugin that it crashes without reflective access to some tree map comparator :) Switching project to use JDK11.

@neilcsmith-net
Copy link
Member

This leads to the problem that we currently cannot update and bundle the latest Mojarra version as
Java 11 is required.

I'm not the right person to be commenting on much of the JSF stuff, but this statement stands out. There may be other reasons for preferring the approach here, but if the right thing to do is to require Java 11 then that's the thing to do.

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

This leads to the problem that we currently cannot update and bundle the latest Mojarra version as
Java 11 is required.

I'm not the right person to be commenting on much of the JSF stuff, but this statement stands out. There may be other reasons for preferring the approach here, but if the right thing to do is to require Java 11 then that's the thing to do.

I slightly agree, but from my understanding this won't be fixed soon (see #4904).

Actually I think to use the matching JSF implementation does make much more sense, as things like attribute completion suggestions or helper text relies on that.
Just proposing these attributes based on the latest or one most recent taglib description is not that ideal.

From my - limit - understanding I'd prefer to remove that bundled JSF implementation at all, but currently it's quite tightly coupled with the module.

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

Lol, default maven web project does not compile as it pulls so old war plugin that it crashes without reflective access to some tree map comparator :) Switching project to use JDK11.

That's a known issue which is - afaik - fixed master. My branch is not rebased to the latest master branch.

To get it work with JDK 17 just update maven-war-plugin to most recent version then it should compile.

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from ddb8fbf to 69d750b Compare July 7, 2023 08:21
@morvael
Copy link

morvael commented Jul 7, 2023

Crazy, after I made this project both 2.2 and 4.0 taglib declarations stopped to be recognized (both in sample project and my core project). But the project works once deployed.
mavenproject1.tar.gz
It's configured to use jdk called "JDK 11" and server "Wildfly", please change nb-configuration.xml directly if you need to change that. Should show something like this:
Screenshot 2023-07-07 at 10-20-57 Facelet Title

@neilcsmith-net
Copy link
Member

if the right thing to do is to require Java 11 then that's the thing to do.

I slightly agree, but from my understanding this won't be fixed soon (see #4904).

We have a few modules that require Java 11 - there are ways and means to work around this prior to all tests being fixed - if that is the right approach for this.

@morvael
Copy link

morvael commented Jul 7, 2023

In vanilla NB 18 with old h namespace it can see my custom taglib (provided it's in 2.2 version):
info3

@morvael
Copy link

morvael commented Jul 7, 2023

I have upgraded plugin versions and switched it to use JDK_17, so here is latest version that works in vanilla NB 18 (so without taglib declaration using version 4.0):
mavenproject1.tar.gz

Wildfly seems to be pretty forgiving, and accepts old namespaces etc - it's just NB that isn't developer friendly.

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from 69d750b to 6d1e186 Compare July 7, 2023 11:46
@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

@morvael Just pushed some fixes. Custom taglib should work now with 2.2 and 4.0.

Wildfly seems to be pretty forgiving, and accepts old namespaces etc - it's just NB that isn't developer friendly.

I don't think that's fair. If you want to improve the situation get behind the code and start hacking ;)

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 7, 2023

Build: https://impl.it/NetBeans-dev-dev-ddb8fbfc0816b3179736c22f91679f1ac434e491-enterprise.zip

@mbien mbien added Java EE/Jakarta EE [ci] enable enterprise job ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) labels Jul 7, 2023
@apache apache locked and limited conversation to collaborators Jul 7, 2023
@asbachb
Copy link
Collaborator Author

asbachb commented Jul 12, 2023

I found one location where I think composite components will not be found (see inline comment). I also noticed, that code completion for namespaces reports jakarata.faces.passthrough, jakarta.faces, jakarta.faces.composite/components/$COMPONENT even though the project is JSF 2.2.

Tbh I already recognized that as well, but haven't had the time to fix it.

One thing I tough about right know: What happens if the JSF artifacts are not present locally in the maven repository? Will they be downloaded and then what happens if there is connection to central possible?

So the idea would be:

  1. Get the artifact from local repository
  2. If not present download it from maven central
  3. If this fails fallback to the bundled jsf implementation (which won't support jakarta namespaces)

3.) I have not tested actively.

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from c787881 to 629cc68 Compare July 12, 2023 08:48
@asbachb
Copy link
Collaborator Author

asbachb commented Jul 12, 2023

Pushed some more adjustment which

  • won't add jakarta pseudo namespaces for non jakarta jsf versions
  • adding jakarta namepsace CompositeComponentModel

Just wanted to note: That this patchset might not be the silver bullet to support jakarta namespaces everywhere and is heavily influenced by the reported bugs.
I think it would be a good idea to target NB19 to get some more feedback about potentially broken things with a clear way how to reproduce.

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from 629cc68 to ae0859a Compare July 12, 2023 16:50
@matthiasblaesing
Copy link
Contributor

@asbachb sorry, but I have to further things:

I still see jakarta composite libraries offered to me by CC. I looked into this an indeed they are generated independently of the JsfVersion. I suggest this:

Align `LibraryUtils#getCompositeLibraryURL` and `LibraryUtils#getAllCompositeLibraryNamespaces`
# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- a/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/spi/LibraryUtils.java
+++ b/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/spi/LibraryUtils.java
@@ -71,10 +71,14 @@
         }
     }
 
-    public static Set<String> getAllCompositeLibraryNamespaces(String libraryName) {
+    public static Set<String> getAllCompositeLibraryNamespaces(String libraryName, JsfVersion jsfVersion) {
         Set<String> namespaces = new LinkedHashSet<>();
-        namespaces.add(COMPOSITE_LIBRARY_JAKARTA_NS + "/" + libraryName);
-        namespaces.add(COMPOSITE_LIBRARY_JCP_NS + "/" + libraryName);
+        if (jsfVersion.isAtLeast(JsfVersion.JSF_4_0)) {
+            namespaces.add(COMPOSITE_LIBRARY_JAKARTA_NS + "/" + libraryName);
+        }
+        if(jsfVersion.isAtLeast(JsfVersion.JSF_2_2)) {
+            namespaces.add(COMPOSITE_LIBRARY_JCP_NS + "/" + libraryName);
+        }
         namespaces.add(COMPOSITE_LIBRARY_SUN_NS + "/" + libraryName);
         return namespaces;
     }

--- a/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig
+++ b/enterprise/web.jsfapi/nbproject/org-netbeans-modules-web-jsfapi.sig
@@ -279,7 +279,7 @@
 meth public static java.lang.String getCompositeLibraryURL(java.lang.String,org.netbeans.modules.web.jsfapi.api.JsfVersion)
 meth public static java.util.Map<java.lang.String,org.netbeans.modules.web.jsfapi.api.Library> getDeclaredLibraries(org.netbeans.modules.html.editor.lib.api.HtmlParsingResult)
 meth public static java.util.Map<org.netbeans.modules.web.jsfapi.api.Library,java.lang.String> importLibrary(javax.swing.text.Document,java.util.Map<org.netbeans.modules.web.jsfapi.api.Library,java.lang.String>)
-meth public static java.util.Set<java.lang.String> getAllCompositeLibraryNamespaces(java.lang.String)
+meth public static java.util.Set<java.lang.String> getAllCompositeLibraryNamespaces(java.lang.String,org.netbeans.modules.web.jsfapi.api.JsfVersion)
 meth public static org.netbeans.api.project.Project[] getOpenedJSFProjects()
 supr java.lang.Object

I also noticed, that the order of the namespaces did not seem consistent. I think the problem is in JsfNamespaceComparator. That nicely bundles the namespace based on prefix, but inside each group there is no order ensured by it.

Suggested adjustment to `JsfNamespaceComparator.java`
--- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/facelets/JsfNamespaceComparator.java
+++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/facelets/JsfNamespaceComparator.java
@@ -37,7 +37,12 @@
 
     @Override
     public int compare(String namespace1, String namespace2) {
-        return rate(namespace1).compareTo(rate(namespace2));
+        int prefixResult = rate(namespace1).compareTo(rate(namespace2));
+        if(prefixResult != 0) {
+            return prefixResult;
+        } else {
+            return namespace1.compareTo(namespace2);
+        }
     }
 
     private Integer rate(String namespace) {

@asbachb
Copy link
Collaborator Author

asbachb commented Jul 12, 2023

I still see jakarta composite libraries offered to me by CC. I looked into this an indeed they are generated independently of the JsfVersion. I suggest this:

@matthiasblaesing can you give some more information on this (or a screenshot). I'm unable to reproduce that behavior.

Think I got it.

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from ae0859a to 8def2b9 Compare July 12, 2023 19:58
@asbachb
Copy link
Collaborator Author

asbachb commented Jul 12, 2023

@matthiasblaesing Applied suggested fixes.

@matthiasblaesing
Copy link
Contributor

Before:

image

After:

image

The critical parts:

  • In the before screenshot the first two entries in the namespace list should not be there. This is a JSF 2.2 application, so the jakarta namespace is not available
  • Notice the ordering of http://xmlns.jcp.org/jsf/composite, http://xmlns.jcp.org/jsf/composite/components/mytudo and http://xmlns.jcp.org/jsf/composite/components/xyz are spread over apart from each other in the before image and placed in the right order below each other in the after image.

@asbachb asbachb requested a review from matthiasblaesing July 13, 2023 15:16
@matthiasblaesing
Copy link
Contributor

@asbachb as I feared, in offline mode this was problematic. I removed the jsf-impl artifact from the local repository and cut the network connections. I got two error cases:

The first issue is, that the check if the maven artifact is present is not correct/incomplete. The maven resolver gives back a path, but the path point to a non-existing file. I got this exception:

Exception
WARNING [org.netbeans.modules.csl.editor.semantic.SemanticHighlighter]: SemanticAnalyzer = org.netbeans.modules.html.editor.gsf.HtmlSemanticAnalyzer@13bbb006; Language = org.netbeans.modules.csl.core.Language@541b0c9[text/html (mimetype = text/html; ParserResult = org.netbeans.modules.html.editor.api.gsf.HtmlParserResult$Lkp@66b7c8cd(mimepath = MimePath[text/xhtml/text/html])
java.lang.NullPointerException: Cannot invoke "org.openide.filesystems.FileObject.isValid()" because "fo" is null
	at org.openide.filesystems.JarArchiveRootProvider.isArchiveFile(JarArchiveRootProvider.java:72)
	at org.openide.filesystems.FileUtil.getArchiveRoot(FileUtil.java:1918)
	at org.netbeans.modules.web.jsf.editor.facelets.DefaultFaceletLibraries.init(DefaultFaceletLibraries.java:80)
	at org.netbeans.modules.web.jsf.editor.facelets.DefaultFaceletLibraries.<init>(DefaultFaceletLibraries.java:67)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.parseLibraries(FaceletsLibrarySupport.java:368)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport._findLibraries(FaceletsLibrarySupport.java:327)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.findLibraries(FaceletsLibrarySupport.java:272)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.getNamespaceLibraryMapping(FaceletsLibrarySupport.java:175)
	at org.netbeans.modules.web.jsf.editor.JsfSupportImpl.getLibrary(JsfSupportImpl.java:224)
	at org.netbeans.modules.web.jsf.editor.JsfPageMetadataProvider.getMetadataMap(JsfPageMetadataProvider.java:74)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getMetadata(WebPageMetadata.java:54)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getMetadata(WebPageMetadata.java:113)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getContentMimeType(WebPageMetadata.java:87)
	at org.netbeans.modules.html.editor.gsf.HtmlSemanticAnalyzer.run(HtmlSemanticAnalyzer.java:60)

I suggest to adjust the contract of the provider to require the provider to only return valid paths.

Suggested fix
--- a/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/spi/JsfReferenceImplementationProvider.java
+++ b/enterprise/web.jsfapi/src/org/netbeans/modules/web/jsfapi/spi/JsfReferenceImplementationProvider.java
@@ -27,5 +27,11 @@
  */
 public interface JsfReferenceImplementationProvider {
 
+    /**
+     * Determine the path to the JSF reference implementation JAR.
+     *
+     * @param jsfVersion
+     * @return path to the JAR or {@code null} if not found
+     */
     Path artifactPathFor(JsfVersion jsfVersion);
 }
--- a/enterprise/maven.j2ee/src/org/netbeans/modules/maven/j2ee/MavenJsfReferenceImplementationProvider.java
+++ b/enterprise/maven.j2ee/src/org/netbeans/modules/maven/j2ee/MavenJsfReferenceImplementationProvider.java
@@ -18,11 +18,12 @@
  */
 package org.netbeans.modules.maven.j2ee;
 
+import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.Map;
+import java.util.Optional;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
@@ -82,6 +83,10 @@
             return null;
         }
 
-        return Paths.get(jsfRIArtifact.getFile().toURI());
+        return Optional.ofNullable(jsfRIArtifact)
+                .map(artifact -> artifact.getFile())
+                .map(file -> file.toPath())
+                .filter(file -> Files.exists(file))
+                .orElse(null);
     }
 }

The second issue is that the schemas in the reference implementation JARs are not optimal. They contain this:

  <xsd:import namespace="http://www.w3.org/XML/1998/namespace"
	      schemaLocation="http://www.w3.org/2001/xml.xsd"/>

The schema parse will then try to load the XSD from network. This is a privacy and performance problem. NetBeans has a solution for this: We carry the schemas and can use the NetBeans UserCatalog to resolve them. In offline mode I see an exception:

Exception
INFO [null]: Error parsing facelets library descriptor
org.xml.sax.SAXParseException; systemId: jar:file:/home/matthias/src/netbeans/nbbuild/netbeans/enterprise/modules/ext/jsf-2_2/javax.faces.jar!/com/sun/faces/javaee_5.xsd; lineNumber: 182; columnNumber: 33; src-resolve: Name 'xml:lang' kann nicht als 'attribute declaration'-Komponente aufgelöst werden.
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
	at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
	at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4254)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4237)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1728)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDAttributeTraverser.traverseLocal(XSDAttributeTraverser.java:90)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDAbstractTraverser.traverseAttrsAndAttrGrps(XSDAbstractTraverser.java:760)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDComplexTypeTraverser.traverseSimpleContent(XSDComplexTypeTraverser.java:656)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDComplexTypeTraverser.traverseComplexTypeDecl(XSDComplexTypeTraverser.java:304)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDComplexTypeTraverser.traverseGlobal(XSDComplexTypeTraverser.java:191)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseSchemas(XSDHandler.java:1480)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:663)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:618)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:577)
	at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:543)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:281)
	at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:612)
	at java.xml/javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:644)
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager$ParseTask.getSchema(ConfigManager.java:1216)
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager$ParseTask.getDocument(ConfigManager.java:1140)
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager$ParseTask.call(ConfigManager.java:1045)
Caused: com.sun.faces.config.ConfigurationException: Unable to parse document 'jar:file:/home/matthias/.m2/repository/org/primefaces/primefaces/11.0.0/primefaces-11.0.0.jar!/META-INF/primefaces-p.taglib.xml': src-resolve: Name 'xml:lang' kann nicht als 'attribute declaration'-Komponente aufgelöst werden.
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager$ParseTask.call(ConfigManager.java:1054)
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager$ParseTask.call(ConfigManager.java:971)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager.getConfigDocuments(ConfigManager.java:775)
Caused: java.util.concurrent.ExecutionException
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
[catch] at org.netbeans.modules.web.jsf.editor.facelets.mojarra.ConfigManager.getConfigDocuments(ConfigManager.java:792)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.parseLibraries(FaceletsLibrarySupport.java:408)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport._findLibraries(FaceletsLibrarySupport.java:327)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.findLibraries(FaceletsLibrarySupport.java:272)
	at org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport.getNamespaceLibraryMapping(FaceletsLibrarySupport.java:175)
	at org.netbeans.modules.web.jsf.editor.JsfSupportImpl.getLibrary(JsfSupportImpl.java:224)
	at org.netbeans.modules.web.jsf.editor.JsfPageMetadataProvider.getMetadataMap(JsfPageMetadataProvider.java:74)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getMetadata(WebPageMetadata.java:54)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getMetadata(WebPageMetadata.java:113)
	at org.netbeans.modules.web.common.api.WebPageMetadata.getContentMimeType(WebPageMetadata.java:87)
	at org.netbeans.modules.html.editor.gsf.HtmlSemanticAnalyzer.run(HtmlSemanticAnalyzer.java:60)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter.process(SemanticHighlighter.java:278)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter.access$000(SemanticHighlighter.java:57)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter$1.run(SemanticHighlighter.java:108)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter$1.run(SemanticHighlighter.java:117)
	at org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask(TaskProcessor.java:586)
	at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:132)
	at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:116)
	at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:181)
	at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:178)
	at org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager.priorityIO(FileChangedManager.java:153)
	at org.netbeans.modules.masterfs.providers.ProvidedExtensions.priorityIO(ProvidedExtensions.java:335)
	at org.netbeans.modules.parsing.nb.DataObjectEnvFactory.runPriorityIO(DataObjectEnvFactory.java:118)
	at org.netbeans.modules.parsing.impl.Utilities.runPriorityIO(Utilities.java:67)
	at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:178)
	at org.netbeans.modules.parsing.api.ParserManager.parse(ParserManager.java:83)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter.run(SemanticHighlighter.java:98)
	at org.netbeans.modules.csl.editor.semantic.SemanticHighlighter.run(SemanticHighlighter.java:57)
	at org.netbeans.modules.parsing.impl.TaskProcessor.callParserResultTask(TaskProcessor.java:561)
	at org.netbeans.modules.parsing.impl.TaskProcessor$RequestPerformer.run(TaskProcessor.java:786)
	at org.openide.util.lookup.Lookups.executeWith(Lookups.java:288)
	at org.netbeans.modules.parsing.impl.TaskProcessor$RequestPerformer.execute(TaskProcessor.java:702)
	at org.netbeans.modules.parsing.impl.TaskProcessor$CompilationJob.run(TaskProcessor.java:663)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1419)
	at org.netbeans.modules.openide.util.GlobalLookup.execute(GlobalLookup.java:45)
	at org.openide.util.lookup.Lookups.executeWith(Lookups.java:287)
	at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2034)
INFO [null]: Error parsing facelets library descriptor
Suggested fix
# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- a/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/facelets/mojarra/ConfigManager.java
+++ b/enterprise/web.jsf.editor/src/org/netbeans/modules/web/jsf/editor/facelets/mojarra/ConfigManager.java
@@ -68,6 +68,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringWriter;
 import java.lang.annotation.Annotation;
 import java.lang.ref.WeakReference;
 import java.net.MalformedURLException;
@@ -120,9 +122,13 @@
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
+import org.netbeans.api.xml.services.UserCatalog;
 import org.netbeans.modules.web.jsf.editor.facelets.DefaultFaceletLibraries;
 import org.netbeans.modules.web.jsfapi.api.JsfNamespaces;
+import org.openide.util.Exceptions;
 import org.w3c.dom.*;
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
@@ -1180,6 +1186,31 @@
             WeakReference<Schema> schema = SCHEMA_CACHE.get(id);
             if (schema == null || schema.get() == null) {
                 SchemaFactory schemaFactory = SchemaFactory.newDefaultInstance();
+                schemaFactory.setResourceResolver(new LSResourceResolver() {
+                    @Override
+                    public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
+                        try {
+                            InputSource is = UserCatalog.getDefault().
+                                    getEntityResolver().
+                                    resolveEntity(publicId, systemId);
+                            if (is != null) {
+                                return new LSInputFromInputSource(is);
+                            }
+                        } catch (SAXException | IOException ex) {
+                            LOGGER.log(
+                                    Level.FINE,
+                                    "Failed to resolve namespaceURI: {}, publicId: {}, systemId: {}, baseURI: {}",
+                                    new Object[] {
+                                        namespaceURI,
+                                        publicId,
+                                        systemId,
+                                        baseURI
+                                    }
+                            );
+                        }
+                        return null;
+                    }
+                });
                 schema = new WeakReference<>(schemaFactory.newSchema(jsfRIClassLoader.getResource(schemaResourceName)));
 
                 SCHEMA_CACHE.put(id, schema);
@@ -1345,4 +1376,96 @@
     } // END URITask
 
 
+    /**
+     * Helperclass to supply the SchemaFactory with XSDs from the NB catalog
+     */
+    private static class LSInputFromInputSource implements LSInput {
+
+        private final InputSource is;
+
+        public LSInputFromInputSource(InputSource is) {
+            this.is = is;
+        }
+
+        @Override
+        public Reader getCharacterStream() {
+            return is.getCharacterStream();
+        }
+
+        @Override
+        public void setCharacterStream(Reader characterStream) {
+        }
+
+        @Override
+        public InputStream getByteStream() {
+            return is.getByteStream();
+        }
+
+        @Override
+        public void setByteStream(InputStream byteStream) {
+        }
+
+        @Override
+        public String getStringData() {
+            try (Reader r = getCharacterStream()) {
+                if (r == null) {
+                    return null;
+                }
+                StringWriter sw = new StringWriter();
+                getCharacterStream().transferTo(sw);
+                return sw.toString();
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        @Override
+        public void setStringData(String stringData) {
+        }
+
+        @Override
+        public String getSystemId() {
+            return is.getSystemId();
+        }
+
+        @Override
+        public void setSystemId(String systemId) {
+        }
+
+        @Override
+        public String getPublicId() {
+            return is.getPublicId();
+        }
+
+        @Override
+        public void setPublicId(String publicId) {
+        }
+
+        @Override
+        public String getBaseURI() {
+            return "";
+        }
+
+        @Override
+        public void setBaseURI(String baseURI) {
+        }
+
+        @Override
+        public String getEncoding() {
+            return is.getEncoding();
+        }
+
+        @Override
+        public void setEncoding(String encoding) {
+        }
+
+        @Override
+        public boolean getCertifiedText() {
+            return false;
+        }
+
+        @Override
+        public void setCertifiedText(boolean certifiedText) {
+        }
+    }
 }

@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from 8def2b9 to 67cc090 Compare July 13, 2023 19:46
@asbachb
Copy link
Collaborator Author

asbachb commented Jul 13, 2023

@matthiasblaesing applied fixes (slightly adjusted stream expressions)

Note: Based on the Stack it seems that this exception is not coming from the standard taglibs, but from primefaces: primefaces-11.0.0.jar.

@matthiasblaesing
Copy link
Contributor

Looks sane to me, thanks. I'll try to have another look at this tomorrow, but if noone objects (@pepness, @juneau001, @jGauravGupta), and I don't hit another road block, I'll merge on sunday.

@mbien
Copy link
Member

mbien commented Jul 16, 2023

@asbachb small merge conflict to resolve if you have time (without github ui please)

Previously NetBeans bundles the JSF reference implementation Mojarra in order to provide several functionality
(like namespaces) based on the parsed taglib xml files from that jar. This is somehow problematic as:
1) The dependency needs to be updated on every new JSF release
2) NetBeans needs to fulfil the expectations of Mojarra

This leads to the problem that we currently cannot update and bundle the latest Mojarra version as
Java 11 is required.

This change wants to get less dependant on that bundled JSF implementation by resolving the reference implementation
using maven. Instead of reading the taglib xml files from that bundled jar NetBeans now gets in from the local maven
repository or downloads it from maven central. If this is not possible we fallback to the bundled version.

This change also improves the situation when autosuggestion is invoked in the namespace part of JSF xhtml documents
by ordering the suggested namespace with the one on top which is most likely to be used.

This should fix apache#6069 apache#5470 apache#5470 apache#4338
@asbachb asbachb force-pushed the add-support-for-faces4-urn-v3 branch from 67cc090 to 14fee17 Compare July 16, 2023 05:49
@LouisCollet
Copy link

please let me know when and how to test this promising release
Louis

Copy link
Contributor

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be still problem be lurking, but I think, that the potential benefit trumps potential problems. Thank you for working through this and staying with it @asbachb.

Lets get this in.

@matthiasblaesing matthiasblaesing merged commit e609c44 into apache:master Jul 16, 2023
@morvael
Copy link

morvael commented Jul 17, 2023

I'm gonna buy you some coffees for that @asbachb, many thanks!

@LouisCollet
Copy link

JSF 4.0 now operational in NB 19 !
Many thanks to @asbachb
a little detail : its does not detect the xmlns which are not used in the .xhtm file
Have a nice day
Louis

@asbachb
Copy link
Collaborator Author

asbachb commented Sep 11, 2023 via email

@matthiasblaesing
Copy link
Contributor

I think this might be the cause for issues: #7449, #7436, #7354.

I can't reproduce the issues, but my gut feeling is, that maven embedder loading causes class loading with the wrong classloader. My idea would be to pull out the places that trigger potential class loading:

// initialize the resource providers for facelet-taglib documents
List<ConfigurationResourceProvider> faceletTaglibProviders =
new ArrayList<>();
//1. first add provider which looks for libraries defined in web-inf.xml
//WEB-INF/web.xml <param-name>javax.faces.FACELETS_LIBRARIES</param-name> context param provider
WebModule webModule = getJsfSupport().getWebModule();
if(webModule != null) {
faceletTaglibProviders.add(new WebFaceletTaglibResourceProvider(webModule));
}
//2. second add a provider returning URIs of library descriptors found during indexing
// the URIs points to both source roots and binary roots of dependent libraries.
final Collection<URI> uris = new ArrayList<>();
for (IndexedFile file : getJsfSupport().getIndex().getAllFaceletsLibraryDescriptors()) {
try {
uris.add(URLMapper.findURL(file.getFile(), URLMapper.EXTERNAL).toURI());
} catch (URISyntaxException ex) {
LOGGER.log(Level.INFO, null, ex);
}
}
faceletTaglibProviders.add(sc -> uris);
// try to find reference implementation based on jsf version
JsfVersion jsfVersion = getJsfSupport().getJsfVersion();
JsfReferenceImplementationProvider jsfRIProvider = Lookup.getDefault().lookup(JsfReferenceImplementationProvider.class);
Path jsfReferenceImplementation = jsfRIProvider.artifactPathFor(jsfVersion);

out into _findLibraries right before the try-block that changes the context classloader.

Would you mind having a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci:dev-build [ci] produce a dev-build zip artifact (7 days expiration, see link on workflow summary page) Java EE/Jakarta EE [ci] enable enterprise job
Projects
None yet
8 participants