Skip to content

Commit

Permalink
Feature: Added support for Faces 4 changed xmlns namespaces
Browse files Browse the repository at this point in the history
Since Jakarte EE Faces 4 the xmls namespaces were changed from `http://xmlns.jcp.org/jsf` to `jakarta.*`.
(see jakartaee/faces#1553)

This change adds new namespace support for:
* Generation of new JSF pages
* Tag suggestion in faces xhtml editor view
* Automatic addition of missing namespace decleration when new taglib is used

In order to support the JSF 4.0 namespaces the `enum` `JsfVersion` in `web.jsfapi` module
was introduced. It's used to map the taglib namespaces based on the projects detected
JSF version.

Note: There's already an enum `JSFVersion` which is not part of the api. Both enums might
be merged in the future.

Reference: apache#6069
  • Loading branch information
asbachb committed Jun 19, 2023
1 parent 5af5f30 commit 404a217
Show file tree
Hide file tree
Showing 22 changed files with 321 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ private static boolean isJSF30(WebModule wm) {
return classpath != null && classpath.findResource("jakarta/faces/flow/Flow.class") != null; //NOI18N
}

private static boolean isJSF40(WebModule wm) {
ClassPath classpath = ClassPath.getClassPath(wm.getDocumentBase(), ClassPath.COMPILE);
return classpath != null && classpath.findResource("jakarta/faces/lifecycle/ClientWindowScoped.class") != null; //NOI18N
}

public Set<DataObject> instantiate(TemplateWizard wiz) throws IOException {
// Here is the default plain behavior. Simply takes the selected
// template (you need to have included the standard second panel
Expand Down Expand Up @@ -231,7 +236,9 @@ public Set<DataObject> instantiate(TemplateWizard wiz) throws IOException {
template = templateParent.getFileObject("JSP", "xhtml"); //NOI18N
WebModule wm = WebModule.getWebModule(df.getPrimaryFile());
if (wm != null) {
if (isJSF30(wm)) {
if (isJSF40(wm)) {
wizardProps.put("isJSF40", Boolean.TRUE);
} else if (isJSF30(wm)) {
wizardProps.put("isJSF30", Boolean.TRUE);
} else if (isJSF22(wm)) {
wizardProps.put("isJSF22", Boolean.TRUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public void run() {
public void run(ResultIterator resultIterator) throws Exception {
Library lib = jsfs.getLibrary(compositeLibURL);
if (lib != null) {
if (!LibraryUtils.importLibrary(document, lib, prefix, jsfs.isJsf22Plus())) { //XXX: fix the damned static prefix !!!
if (!LibraryUtils.importLibrary(document, lib, prefix, jsfs.getJsfVersion())) { //XXX: fix the damned static prefix !!!
logger.log(Level.WARNING, "Cannot import composite components library {0}", compositeLibURL); //NOI18N
}
} else {
Expand Down Expand Up @@ -248,7 +248,7 @@ public void run() {
((BaseDocument) templateInstanceDoc).runAtomic(new Runnable() {
@Override
public void run() {
LibraryUtils.importLibrary(templateInstanceDoc, importsMap, jsfs.isJsf22Plus());
LibraryUtils.importLibrary(templateInstanceDoc, importsMap, jsfs.getJsfVersion());
}
});
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.netbeans.modules.web.jsf.editor.facelets.CompositeComponentLibrary;
import org.netbeans.modules.web.jsf.editor.hints.HintsRegistry;
import org.netbeans.modules.web.jsfapi.api.DefaultLibraryInfo;
import org.netbeans.modules.web.jsfapi.api.JsfVersion;
import org.netbeans.modules.web.jsfapi.api.Library;
import org.netbeans.modules.web.jsfapi.api.LibraryComponent;
import org.netbeans.modules.web.jsfapi.api.NamespaceUtils;
Expand Down Expand Up @@ -199,10 +200,10 @@ public List<CompletionItem> completeOpenTags(CompletionContext context) {
if (declaredPrefix == null) {
//undeclared prefix, try to match with default library prefix
if (lib.getDefaultPrefix() != null && lib.getDefaultPrefix().startsWith(context.getPrefix())) {
items.addAll(queryLibrary(context, lib, lib.getDefaultPrefix(), true, jsfs.isJsf22Plus()));
items.addAll(queryLibrary(context, lib, lib.getDefaultPrefix(), true, jsfs.getJsfVersion()));
}
} else {
items.addAll(queryLibrary(context, lib, declaredPrefix, false, jsfs.isJsf22Plus()));
items.addAll(queryLibrary(context, lib, declaredPrefix, false, jsfs.getJsfVersion()));
}
}
} else {
Expand All @@ -215,7 +216,7 @@ public List<CompletionItem> completeOpenTags(CompletionContext context) {
for (Library lib : librariesSet) {
if (lib.getDefaultPrefix() != null && lib.getDefaultPrefix().equals(tagNamePrefix)) {
//match
items.addAll(queryLibrary(context, lib, tagNamePrefix, true, jsfs.isJsf22Plus()));
items.addAll(queryLibrary(context, lib, tagNamePrefix, true, jsfs.getJsfVersion()));
}
}

Expand All @@ -227,7 +228,7 @@ public List<CompletionItem> completeOpenTags(CompletionContext context) {
return Collections.emptyList();
} else {
//query the library
items.addAll(queryLibrary(context, lib, tagNamePrefix, false, jsfs.isJsf22Plus()));
items.addAll(queryLibrary(context, lib, tagNamePrefix, false, jsfs.getJsfVersion()));
}
}
}
Expand All @@ -253,11 +254,11 @@ private String getUriForPrefix(String prefix, Map<String, String> namespaces) {
return null;
}

private Collection<CompletionItem> queryLibrary(CompletionContext context, Library lib, String nsPrefix, boolean undeclared, boolean isJsf22Plus) {
private Collection<CompletionItem> queryLibrary(CompletionContext context, Library lib, String nsPrefix, boolean undeclared, JsfVersion jsfVersion) {
Collection<CompletionItem> items = new ArrayList<>();
for (LibraryComponent component : lib.getComponents()) {
if (!(component instanceof AbstractFaceletsLibrary.Function)) {
items.add(JsfCompletionItem.createTag(context.getCCItemStartOffset(), component, nsPrefix, undeclared, isJsf22Plus));
items.add(JsfCompletionItem.createTag(context.getCCItemStartOffset(), component, nsPrefix, undeclared, jsfVersion));
}
}

Expand Down Expand Up @@ -353,7 +354,7 @@ public List<CompletionItem> completeAttributeValue(CompletionContext context) {
JsfAttributesCompletionHelper.completeFaceletsFromProject(context, items, ns, openTag);

// completion for sections in cases of ui:define name attribute
JsfAttributesCompletionHelper.completeSectionsOfTemplate(context, items, ns, openTag);
JsfAttributesCompletionHelper.completeSectionsOfTemplate(context, items, ns, openTag, jsfs.getJsfVersion());

// completion for java classes in <cc:attribute type="com.example.|
JsfAttributesCompletionHelper.completeJavaClasses(context, items, ns, openTag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
Expand All @@ -40,6 +42,7 @@
import org.netbeans.modules.web.jsf.editor.facelets.FaceletsLibrarySupport;
import org.netbeans.modules.web.jsf.editor.index.JsfIndex;
import org.netbeans.modules.web.jsfapi.api.JsfSupport;
import org.netbeans.modules.web.jsfapi.api.JsfVersion;
import org.netbeans.modules.web.jsfapi.api.Library;
import org.netbeans.modules.web.jsfapi.api.NamespaceUtils;
import org.netbeans.modules.web.jsfapi.spi.JsfSupportProvider;
Expand All @@ -58,6 +61,21 @@ public class JsfSupportImpl implements JsfSupport {

private static final Logger LOG = Logger.getLogger(JsfSupportImpl.class.getSimpleName());

private static final Map<JSFVersion, JsfVersion> JSF_VERSION_MAPPING;
static {
Map<JSFVersion, JsfVersion> map = new HashMap<>();
map.put(JSFVersion.JSF_1_0, JsfVersion.JSF_1_0);
map.put(JSFVersion.JSF_1_1, JsfVersion.JSF_1_1);
map.put(JSFVersion.JSF_1_2, JsfVersion.JSF_1_2);
map.put(JSFVersion.JSF_2_0, JsfVersion.JSF_2_0);
map.put(JSFVersion.JSF_2_1, JsfVersion.JSF_2_1);
map.put(JSFVersion.JSF_2_2, JsfVersion.JSF_2_2);
map.put(JSFVersion.JSF_2_3, JsfVersion.JSF_2_3);
map.put(JSFVersion.JSF_3_0, JsfVersion.JSF_3_0);
map.put(JSFVersion.JSF_4_0, JsfVersion.JSF_4_0);
JSF_VERSION_MAPPING = Collections.unmodifiableMap(map);
}

public static JsfSupportImpl findFor(Source source) {
return getOwnImplementation(JsfSupportProvider.get(source));
}
Expand Down Expand Up @@ -267,6 +285,17 @@ public synchronized MetadataModel<org.netbeans.modules.jakarta.web.beans.api.mod
return webBeansModelJakarta;
}

@Override
public JsfVersion getJsfVersion() {
if (wm == null) {
return JsfVersion.latest();
}

JSFVersion jsfVersion = JSFVersion.forWebModule(wm);

return JSF_VERSION_MAPPING.getOrDefault(jsfVersion, JsfVersion.latest());
}

@Override
public boolean isJsf22Plus() {
if (wm != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.parsing.spi.Parser.Result;
import org.netbeans.modules.web.jsfapi.api.JsfVersion;
import org.netbeans.modules.web.jsfapi.api.LibraryInfo;

/**
Expand Down Expand Up @@ -99,12 +100,9 @@ public static Result getEmbeddedParserResult(ResultIterator resultIterator, Stri
return null;
}

public static Node getRoot(HtmlParserResult parserResult, LibraryInfo library) {
Node rootNode = parserResult.root(library.getNamespace());
if ((rootNode == null || rootNode.children().isEmpty()) && library.getLegacyNamespace() != null) {
rootNode = parserResult.root(library.getLegacyNamespace());
}
return rootNode;
public static Node getRoot(HtmlParserResult parserResult, LibraryInfo library, JsfVersion jsfVersion) {
String namespace = jsfVersion.getNamespaceUri(library.getDefaultPrefix());
return parserResult.root(namespace);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import org.netbeans.api.editor.EditorActionRegistration;
import org.netbeans.api.progress.ProgressUtils;
import org.netbeans.api.progress.BaseProgressUtils;
import org.netbeans.editor.BaseAction;
import static org.netbeans.editor.BaseAction.MAGIC_POSITION_RESET;
import static org.netbeans.editor.BaseAction.UNDO_MERGE_RESET;
Expand Down Expand Up @@ -83,53 +83,55 @@ public FixNamespacesAction() {

@Override
public void actionPerformed(ActionEvent evt, final JTextComponent target) {
if (target != null) {
final AtomicBoolean cancel = new AtomicBoolean();
final AtomicReference<ImportData> importData = new AtomicReference<>();
final UserTask task = new UserTask() {
@Override
public void run(ResultIterator ri) throws Exception {
Parser.Result parserResult = getHtmlParserResult(ri);
if (parserResult instanceof HtmlParserResult) {
HtmlParserResult htmlParserResult = (HtmlParserResult) parserResult;
if (cancel.get()) {
return;
}
if (target == null) {
return;
}

final ImportData data = computeNamespaces(htmlParserResult);
if (cancel.get()) {
return;
}
if (data.shouldShowNamespacesPanel) {
if (!cancel.get()) {
importData.set(data);
}
} else {
performFixNamespaces(htmlParserResult, data, data.getDefaultVariants(), isRemoveUnusedNs());
final AtomicBoolean cancel = new AtomicBoolean();
final AtomicReference<ImportData> importData = new AtomicReference<>();
final UserTask task = new UserTask() {
@Override
public void run(ResultIterator ri) throws Exception {
Parser.Result parserResult = getHtmlParserResult(ri);
if (parserResult instanceof HtmlParserResult) {
HtmlParserResult htmlParserResult = (HtmlParserResult) parserResult;
if (cancel.get()) {
return;
}

final ImportData data = computeNamespaces(htmlParserResult);
if (cancel.get()) {
return;
}
if (data.shouldShowNamespacesPanel) {
if (!cancel.get()) {
importData.set(data);
}
} else {
performFixNamespaces(htmlParserResult, data, data.getDefaultVariants(), isRemoveUnusedNs());
}
}
};
}
};

ProgressUtils.runOffEventDispatchThread(new Runnable() {
BaseProgressUtils.runOffEventDispatchThread(new Runnable() {
@Override
public void run() {
try {
ParserManager.parse(Collections.singleton(Source.create(target.getDocument())), task);
} catch (ParseException ex) {
Exceptions.printStackTrace(ex);
}
}
}, Bundle.FixNamespacesLabelLongName(), cancel, false);

if (importData.get() != null && !cancel.get()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
ParserManager.parse(Collections.singleton(Source.create(target.getDocument())), task);
} catch (ParseException ex) {
Exceptions.printStackTrace(ex);
}
showFixNamespacesDialog(target, importData.get());
}
}, Bundle.FixNamespacesLabelLongName(), cancel, false);

if (importData.get() != null && !cancel.get()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
showFixNamespacesDialog(target, importData.get());
}
});
}
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private void removeUnusedNamespaces() {

private void includeMissingNamespaces() {
for (VariantItem variant : selections) {
LibraryUtils.importLibrary(baseDocument, variant.getLibrary(), variant.getPrefix(), importData.isJsf22);
LibraryUtils.importLibrary(baseDocument, variant.getLibrary(), variant.getPrefix(), importData.jsfVersion);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.List;
import java.util.Objects;
import org.netbeans.modules.html.editor.lib.api.elements.Attribute;
import org.netbeans.modules.web.jsfapi.api.JsfVersion;
import org.netbeans.modules.web.jsfapi.api.Library;

/**
Expand All @@ -31,7 +32,7 @@
public class ImportData {

public volatile boolean shouldShowNamespacesPanel;
public volatile boolean isJsf22;
public volatile JsfVersion jsfVersion;

private final List<DataItem> dataItems = new ArrayList<>();
private final List<DataItem> dataItemsToReplace = new ArrayList<>();
Expand Down
Loading

0 comments on commit 404a217

Please sign in to comment.