Archetypes for "thin" JSF portlet WAR artifacts (with optional OSGi+CDI Integration) now available

The Future is Finally Here

Announcement

On March 2, 2021 Liferay released a new set of Maven archetypes that enable developers to build and deploy "thin" JSF portlet WAR artifacts. In addition, these archetypes enable developers to optionally enable OSGi+CDI Integration.

Background

This post is a follow-up to How to try JSF thin WAR demo portlets

The Future is Finally Here

Back on Nov 23, 2016 I presented a session at Liferay DEVCON titled Developing WABs With a View to the Future. Although it took 4 1/2 years, these archetypes represent the fulfillment of a promise made during that session. Specifically, developers can now deploy "thin" JSF portlet WAR artifacts that optionally enable Contexts and Dependency Injection (CDI). The main reasons for the delay was that CDI integration was undergoing the standardization process, and the first implementation of it didn't appear in Liferay as a feature until January of 2019 with the release of Liferay Portal 7.1.2 CE GA3. Not coincidentally, that was the first release that fully supported JSR 362 (Portlet 3.0) which has CDI requirements. After this release, the Liferay Faces team was able to press forward with JSR 378 (Portlet 3.0 Bridge for JSF 2.2) along with support for "thin" JSF portlet WARs and OSGi+CDI Integration.

What is a "thick" JSF portlet WAR artifact?

Until recently, JSF portlet applications have always been built as a "thick" WAR artifact, meaning the JSF dependencies were embedded inside of WEB-INF/lib. In some cases, this caused WAR artifacts to start out at 12MB in size, even before any custom code was added. For example, with PrimeFaces:

  • WEB-INF/lib/javax.faces-2.2.20.jar (3.1 MB)
  • WEB-INF/lib/primefaces-8.0.jar (5.4 MB)
  • WEB-INF/lib/com.liferay.faces.alloy-4.1.0.jar (600 KB)
  • WEB-INF/lib/com.liferay.faces.bridge.api-4.2.0.jar (83 KB)
  • WEB-INF/lib/com.liferay.faces.bridge.ext-6.1.0.jar (146 KB)
  • WEB-INF/lib/com.liferay.faces.bridge.impl-4.2.0.jar (540 KB)
  • WEB-INF/lib/com.liferay.faces.portal-4.1.0.jar (173 KB)
  • WEB-INF/lib/com.liferay.faces.util-3.4.0.jar (385 KB)

In order to cut down on some of the size, developers would use Java EE application servers like Glassfish and WildFly which shipped with the JSF implementation (Mojarra) already in the classpath. This worked fine back in the days of Liferay Portal CE/EE 6.2. But when Liferay Portal CE/DXP 7.0 migrated to OSGi, developers lost the ability to use the JSF implementation provided by the application server. This is because with Liferay Portal CE/DXP 7.x, a WAR artifact is transformed upon deployment into Web Application Bundle (WAB). Since WABs are OSGi modules, they participate in the OSGi classpath, and not the classpath provided by application server.

What is a "thin" JSF portlet WAR artifact?

With the release of Liferay Faces Bridge 4.2.0 back on October 24, 2020 it became possible to deploy ALL of the aforementioned JAR artifacts as OSGi modules in $LIFERAY_HOME/osgi/modules. Soon after, I published a blog post titled How to try JSF thin WAR demo portlets. But again, there was no convenient way for developers to learn how to convert their "thick" WAR artifacts into "thin" ones. But now that the archetypes are available, we hope that developers find it convenient and easy.

Again, since of the aforementioned JAR modules can be deployed to $LIFERAY_HOME/osgi/modules, it means that they no longer need to be present in WEB-INF/lib. That's what makes a JSF portlet WAR artifact "thin".

How can I try the archetypes?

We just updated the home page of liferayfaces.org with a new archetype selector. Specifically, there are two new dropdown lists:


 

The first dropdown list is Format which has two options: Thick/Thin.

The second dropdown list is OSGi+CDI Integration which has two options: Enabled/Disabled.

When you make selections from these dropdown lists, the Maven Build command will update with corresponding Maven profile usage.

What does a project generated from an archetype look like?

The generated project has a very simple "Hello World" type of UI:


And if CDI is enabled, the UI will contain "Greetings from CDI" as well.

Enjoy!

 

Blogs

hi Neil,

question regarding the OSGI/CDI and the latest version liferay 7.3.6-ga7 I tried as described in the How to try JSF thin WAR demo portlets. without success / because of the comment from Michael I checked out the the Liferay-faces packages and built them problem here missing javax.annoation dependencies (is there a special parent pom needed ?)

when I deploy them on the tomcat / liferay bundle 

1363|Active | 10|primefaces-8.0.7 (8.0.7)|8.0.7

1371|Installed | 15|Liferay Faces Util (4.0.0.202104221322)|4.0.0.202104221322

1372|Installed | 10|Liferay Faces Bridge Ext (8.0.0.202104221335)|8.0.0.202104221335

1373|Installed | 10|Liferay Faces Bridge Implementation (6.0.0.202104221335)|6.0.0.202104221335

1374|Installed | 10|Liferay Faces Bridge API (6.0.0.202104221333)|6.0.0.202104221333

1380|Active | 15|Mojarra JSF Implementation 2.3.9 (20190401-1936) 77894020e94a338c9701619b7ef6e9871c5a9079 (2.3.9)|2.3.9

1389|Installed | 15|Liferay Faces Alloy (4.1.1.202104221325)|4.1.1.202104221325

1390|Installed | 15|Liferay Faces Portal (6.0.0.202104221339)|6.0.0.202104221339

1391|Installed | 1|my.primefaces.portlet (1.0.0)|1.0.0

on restart with init errors of missing dependencies of OSGI but starting / BUT the deployed Portlet ist not accessible at all

also a question on building: mvn clean package on the packages should be enough or ?

only for the Portlet the cdi/thin is needed ? 

br horst

Hi Horst,

What version of Java are you using? Java 8 or Java 11?

Also, according to the Archetype Selector found at the liferayfaces.org home page, for Liferay 7.3.5-ga6 you should have the following in $LIFERAY_HOME/osgi/modules:

com.liferay.faces.alloy-4.1.0.jar

com.liferay.faces.bridge.api-5.0.0.jar

com.liferay.faces.bridge.ext-7.0.0.jar

com.liferay.faces.bridge.impl-5.0.0.jar

com.liferay.faces.portal-4.1.0.jar

com.liferay.faces.util-3.4.0.jar

javax.faces-2.2.20.jar

You can find all of those at Maven Central.

For Liferay 7.3.6-ga7, there is only one small fix that you need, which is only for the com.liferay.faces.portal module. This is the problem that Michael Seyfried reported. It was fixed in https://issues.liferay.com/browse/FACES-3606 but we haven't released com.liferay.faces.portal-4.1.1.jar to Maven Central yet. Are you sure that you need that module?

-- Neil

hi Neil, thank's for your fast reply

java openjdk 11.0.10

liferay 7.3.!6- ga7! / tomcat bundle not 5-ga6 as described from Michael there is a problem with wiki => I tried to build myself

(I also tried with war file installation in wildfly 23, similar problems)

When I build the portlet for archetype

7.3 / Maven / 2.2 / THIN / Primefaces / CDI enabled

First problem here the archetype generates a dependency in maven pom.xml for

[ERROR] [ERROR] Some problems were encountered while processing the POMs:

[FATAL] Non-resolvable parent POM for at.it4health:my.primefaces.portlet:1.0-SNAPSHOT: Could not find artifact com.liferay.faces.archetype:com.liferay.faces.archetype.parent:pom:6.1.0-SNAPSHOT in liferay-public (https://repository.liferay.com/nexus/content/groups/public) and 'parent.relativePath' points at wrong local POM @ line 7, column 10

<parent>

    <groupId>com.liferay.faces.archetype</groupId>

        <artifactId>com.liferay.faces.archetype.parent</artifactId>

        <version>6.1.0-SNAPSHOT</version>. <<<== this does not exists in repo only 6.1.0

</parent>

Correcting this, I can compile; additional I changed / to be on the same as primefaces 8.x is:

<faces.spec.version>2.3</faces.spec.version>

<liferay.version>7.3.6</liferay.version>

 

And dependencies on other libs, all scopes are provided

javax.enterprise:cdi-api:1.2

javax.faces:javax.faces-api:2.3

org.glassfish:javax.faces:2.3.9

com.liferay.faces:com.liferay.faces.bridge.ext:8.0.0-SNAPSHOT

com.liferay.faces:com.liferay.faces.bridge.impl:6.0.0-SNAPSHOT

org.primefaces:primefaces:8.0

 

I get this structure (as expected):

|____my.primefaces.portlet-1.0-SNAPSHOT

| |____resources

| | |____images

| | | |____icon.png

| |____META-INF

| | |____module-log4j-ext.xml

| |____WEB-INF

| | |____classes

| | | |____META-INF

| | | | |____services

| | | | | |____javax.servlet.ServletContainerInitializer

| | | | | |____javax.enterprise.inject.spi.Extension

| | | | | |____com.sun.faces.spi.annotationprovider

| | | | | |____com.sun.faces.spi.FaceletConfigResourceProvider

| | | | | |____com.sun.faces.spi.FacesConfigResourceProvider

| | | | | |____com.sun.faces.util.cdi11.CDIUtil

| | | |____i18n.properties

| | | |____com

| | | | |____mycompany

| | | | | |____dto

| | | | | | |____Greeting.class

| | | | | |____backing

| | | | | | |____MyBacking.class

| | | |____log4j.properties

| | |____beans.xml

| | |____resources

| | | |____css

| | | | |____main.css

| | |____liferay-plugin-package.properties

| | |____faces-config.xml

| | |____portlet.xml

| | |____web.xml

| | |____liferay-portlet.xml

| | |____liferay-display.xml

| | |____views

| | | |____view.xhtml

 

The prepared javaserver faces packages I have deployed (a lot of problems with missing dep on javax.annotation in multiple demo packages I'm not sure what here the problem is if I'm something missing // general I build everything on cli not inside any tool to prevent caching problems in all directions)

 

In LIFERAY_HOME/osgi/modules

com.liferay.faces.alloy-4.1.1-SNAPSHOT.jar

com.liferay.faces.bridge.api-6.0.0-SNAPSHOT.jar

com.liferay.faces.bridge.ext-8.0.0-SNAPSHOT.jar

com.liferay.faces.bridge.impl-6.0.0-SNAPSHOT.jar

com.liferay.faces.portal-6.0.0-SNAPSHOT.jar

com.liferay.faces.util-4.0.0-SNAPSHOT.jar

javax.faces-2.3.9.jar

primefaces-8.0.7.jar

 

On startup errors are popping up (without portlet deployed)

2021-04-23 09:29:18.819 ERROR [Framework Event Dispatcher: Equinox Container: eedb21ce-7c77-457d-8bc5-92bd1b7eeb47][Framework:93] FrameworkEvent ERROR

org.osgi.framework.BundleException: Could not resolve module: com.liferay.faces.bridge.ext [1372]_

Unresolved requirement:

  Import-Package: com.liferay.faces.util.cache; version="[4.0.0,5.0.0)"_    

-> Export-Package: com.liferay.faces.util.cache; bundle-symbolic-name="com.liferay.faces.util"; bundle-version="4.0.0.202104221322"; version="4.0.0";

uses:="javax.faces,javax.faces.context"_       com.liferay.faces.util [1371]_         

Unresolved requirement: Import-Package: com.sun.faces.util; version="[2.2.0,2.3.0)"_  **** SEE

Unresolved requirement: Import-Package: com.liferay.faces.util.application; version="[4.0.0,5.0.0)"_    

-> Export-Package: com.liferay.faces.util.application; bundle-symbolic-name="com.liferay.faces.util"; bundle-version="4.0.0.202104221322"; version="4.0.0";

uses:="javax.faces,javax.faces.application,javax.faces.component,javax.faces.context"_ [Sanitized]

 

For me now not clear; if the version/bundle-version numbering could be a problem ?

 

When liferay is started I checked via Gogo Shell : lb

If packages are installed / but not active

 

1363|Active     |   10|primefaces-8.0.7 (8.0.7)|8.0.7

1371|Installed  |   15|Liferay Faces Util (4.0.0.202104230658)|4.0.0.202104230658

1372|Installed  |   10|Liferay Faces Bridge Ext (8.0.0.202104230708)|8.0.0.202104230708

1373|Installed  |   10|Liferay Faces Bridge Implementation (6.0.0.202104230728)|6.0.0.202104230728

1374|Installed  |   10|Liferay Faces Bridge API (6.0.0.202104230700)|6.0.0.202104230700

1380|Active     |   15|Mojarra JSF Implementation 2.3.9 (20190401-1936) 77894020e94a338c9701619b7ef6e9871c5a9079 (2.3.9)|2.3.9

1389|Installed  |   15|Liferay Faces Alloy (4.1.1.202104221325)|4.1.1.202104221325

1390|Installed  |   15|Liferay Faces Portal (6.0.0.202104230749)|6.0.0.202104230749

 

It seems to be ok or ? For me not clear why not in state active ? Because or dep error before ?

 

Now only testing purpose deployment of the portlet into LIFERAY_HOME/deploy directory

 

2021-04-23 09:34:54.242 ERROR [fileinstall-directory-watcher][DirectoryWatcher:1136] Unable to start bundle: webbundle:/liferay-ce-portal-7.3.6-ga7/osgi/war/my.primefaces.portlet.war?Bundle-SymbolicName=my.primefaces.portlet&Web-ContextPath=/my.primefaces.portlet&protocol=file

org.osgi.framework.BundleException:

Could not resolve module: my.primefaces.portlet [1392]_

Unresolved requirement: Import-Package: net.fortuna.ical4j.model; resolution:="optional"_

Unresolved requirement: Import-Package: net.fortuna.ical4j.model.property; resolution:="optional"_

Unresolved requirement: Import-Package: org.apache.axis.tools.ant.wsdl; resolution:="optional"_

Unresolved requirement: Import-Package: org.apache.poi.hssf.usermodel; resolution:="optional"_

Unresolved requirement: Import-Package: org.apache.poi.ss.usermodel; resolution:="optional"_

Unresolved requirement: Import-Package: com.liferay.faces.bridge.ext_    

-> Export-Package: com.liferay.faces.bridge.ext; bundle-symbolic-name="com.liferay.faces.bridge.ext"; bundle-version="8.0.0.202104230708"; version="8.0.0";

uses:="javax.portlet,javax.portlet.faces"_       com.liferay.faces.bridge.ext [1372]_         

Unresolved requirement: Import-Package: com.liferay.faces.util.application; version="[4.0.0,5.0.0)"_           

-> Export-Package: com.liferay.faces.util.application; bundle-symbolic-name="com.liferay.faces.util"; bundle-version="4.0.0.202104230658"; version="4.0.0";

uses:="javax.faces,javax.faces.application,javax.faces.component,javax.faces.context"_              com.liferay.faces.util [1371]_                

Unresolved requirement: Import-Package: com.sun.faces.util; version="[2.2.0,2.3.0)"_

Unresolved requirement: Import-Package: com.liferay.faces.bridge.impl_    

-> Export-Package: com.liferay.faces.bridge.impl; bundle-symbolic-name="com.liferay.faces.bridge.impl"; bundle-version="6.0.0.202104230728"; version="6.0.0"_       com.liferay.faces.bridge.impl [1373]_         

Unresolved requirement: Import-Package: com.liferay.faces.util.application; version="[4.0.0,5.0.0)"_           -> Export-Package: com.liferay.faces.util.application; bundle-symbolic-name="com.liferay.faces.util"; bundle-version="4.0.0.202104230658"; version="4.0.0";

uses:="javax.faces,javax.faces.application,javax.faces.component,javax.faces.context"_         

Unresolved requirement: Import-Package: com.liferay.faces.util.cache; version="[4.0.0,5.0.0)"_           

-> Export-Package: com.liferay.faces.util.cache; bundle-symbolic-name="com.liferay.faces.util"; bundle-version="4.0.0.202104230658"; version="4.0.0";

uses:="javax.faces,javax.faces.context"_

Unresolved requirement: Import-Package: javax.portlet.faces_    

-> Export-Package: javax.portlet.faces; bundle-symbolic-name="com.liferay.faces.bridge.api"; bundle-version="6.0.0.202104230700"; version="6.0.0";

uses:="javax.enterprise.context,javax.faces,javax.faces.context,javax.portlet,javax.portlet.faces.event"_       com.liferay.faces.bridge.api [1374]_         

Unresolved requirement: Require-Capability: osgi.serviceloader; filter:="(osgi.serviceloader=javax.portlet.faces.BridgeFactoryFinder)"; cardinality:="multiple"_           -> Provide-Capability: osgi.serviceloader; osgi.serviceloader="javax.portlet.faces.BridgeFactoryFinder"_         

Unresolved requirement: Require-Capability: osgi.serviceloader; filter:="(osgi.serviceloader=javax.portlet.faces.Bridge)"; cardinality:="multiple"_           -> Provide-Capability: osgi.serviceloader; osgi.serviceloader="javax.portlet.faces.Bridge"_ [Sanitized]

 

 

Example: net.fortuna.ical4j.model; resolution:="optional". Should this be ignored ? Because of optional

 

The error for the com.liferay.faces.bridge.ext_ I don't understand I checked all dependencies and classes they are all there only thing is the version number of the bundle

 

After deployment the portlet is installed

 

1392|Installed  |   15|my.primefaces.portlet (1.0.0)|1.0.0

 

But can't be accessed from the paged edit / widget Sample Category (according to the Liferay-display.xml it should be in the sample category)

 

**** fixed problem from util Unresolved requirement: Import-Package: com.sun.faces.util; version="[2.2.0,2.3.0)"_

 

Inside liferay-faces-util/pom.xml in the bnd configuration of Import-Package:

Changed com.sun.faces.util;version="[2.2.0,2.3.0)",\ -> com.sun.faces.util;version="[2.2.0,3)",\

 

As I understood 2.3.0) is excluded 2.3.0 or ? (Recompile util mvn clean install / remove from OSGi/modules !  / restart / deployment otherwise  not correct version..)

Now because of glassfish 2.3.9 or higher it should work

 

1363|Active     |   10|primefaces-8.0.7 (8.0.7)|8.0.7

1372|Active     |   10|Liferay Faces Bridge Ext (8.0.0.202104230708)|8.0.0.202104230708

1373|Active     |   10|Liferay Faces Bridge Implementation (6.0.0.202104230728)|6.0.0.202104230728

1374|Active     |   10|Liferay Faces Bridge API (6.0.0.202104230700)|6.0.0.202104230700

1380|Active     |   15|Mojarra JSF Implementation 2.3.9 (20190401-1936) 77894020e94a338c9701619b7ef6e9871c5a9079 (2.3.9)|2.3.9

1389|Active     |   15|Liferay Faces Alloy (4.1.1.202104221325)|4.1.1.202104221325

1390|Active     |   15|Liferay Faces Portal (6.0.0.202104230749)|6.0.0.202104230749

1393|Active     |   15|Liferay Faces Util (4.0.0.202104260755)|4.0.0.202104260755

 

:-)

 

Again redeployment of portlet to LIFERAY_HOME/deploy/

 

2021-04-26 08:27:42.295 ERROR [Framework Event Dispatcher: Equinox Container: 41f083b0-e0d3-454e-be1e-c67b789d83fc][Framework:93] FrameworkEvent ERROR

java.lang.RuntimeException: No Common Superclass:groovy/util/ResourceException groovy/util/ScriptException

at org.apache.aries.spifly.dynamic.OSGiFriendlyClassWriter.getCommonSuperClass(OSGiFriendlyClassWriter.java:115)

 

2021-04-26 08:27:42.326 ERROR [fileinstall-directory-watcher][WabBundleProcessor:244] Catastrophic initialization failure! Shutting down at.it4health.my.primefaces.portlet WAB due to: java.lang.ClassFormatError: Unexpected error from weaving hook.

java.lang.RuntimeException: java.lang.ClassFormatError: Unexpected error from weaving hook.

at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:315)

Caused by: java.lang.ClassFormatError: Unexpected error from weaving hook.

at org.eclipse.osgi.internal.weaving.WeavingHookConfigurator.processClass(WeavingHookConfigurator.java:76)

at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.processClass(ClasspathManager.java:658)

 

Caused by: java.lang.RuntimeException: No Common Superclass:groovy/util/ResourceException groovy/util/ScriptException

at org.apache.aries.spifly.dynamic.OSGiFriendlyClassWriter.getCommonSuperClass(OSGiFriendlyClassWriter.java:115)

at org.objectweb.asm.SymbolTable.addMergedType(SymbolTable.java:1198)

 

 

2021-04-26 08:27:42.714 WARN  [fileinstall-directory-watcher][Interceptor:46] WELD-001700: Interceptor annotation class javax.ejb.PostActivate not found, interception based on it is not enabled

2021-04-26 08:27:42.714 WARN  [fileinstall-directory-watcher][Interceptor:46] WELD-001700: Interceptor annotation class javax.ejb.PrePassivate not found, interception based on it is not enabled

 

Which let me additionally added the following jars to the LIFERAY_HOME/osgi/modules

 

javax.annotation:javax.annotation-api:1.3.2 for the WARN before  WELD-001700: Interceptor annotation class javax.ejb.PostActivate not found

org.codehaus.groovy:groovy:3.0.8   for the ERROR before No Common Superclass:groovy/util/ResourceException groovy/util/ScriptException

 

1396|Active     |   15|Groovy Runtime (3.0.8)|3.0.8

1397|Active     |   15|javax.annotation API (1.3.2)|1.3.2

 

Now deployment of example portlet ends with

2021-04-26 08:54:45.220 ERROR [fileinstall-directory-watcher][WabBundleProcessor:244] Catastrophic initialization failure! Shutting down my.primefaces.portlet WAB due to: java.lang.NullPointerException

java.lang.RuntimeException: java.lang.NullPointerException

at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:315)

 

Caused by: java.lang.NullPointerException

at com.sun.faces.util.ReflectionUtils.newInstance(ReflectionUtils.java:369)

at com.sun.faces.el.ELUtils.addEL3_0_Resolvers(ELUtils.java:340)

at com.sun.faces.el.ELUtils.buildFacesResolver(ELUtils.java:258)

at com.sun.faces.application.ApplicationAssociate.initializeELResolverChains(ApplicationAssociate.java:503)

 

So now I'm not sure what next :-)

 

And I know it's not released and I'm on the cutting edge of development, but I want to know how are the things working together => I'm willing to invest time to it

 

Br horst

Hi Horst,

Apologies for the lateness of my reply -- you are right to change "6.1.0-SNAPSHOT" to "6.1.0" for the archetype. That was caused by an oversight in the release process.

Regarding JSF 2.3, it's not supported yet. You need to stick with JSF 2.2 for now.

Have you been able to get "thin" mode working with JSF 2.2 (the 5.x version of Liferay Faces Bridge API/Impl)?

Kind Regards,

Neil