Forums

angle-left Back

JSF app with CDI in Liferay 7

JL
Jonathan Locht, modified 1 Year ago.

JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hello,

I'm currently trying to migrate our existing JSF app from Liferay 6.2 to Liferay 7.
We are using JSF along with CDI on jboss 6.4. and the app also includes liferay hooks such as servlet filters and themes.

The app is packaged in an ear archive that we used to deploy directly in the jboss deployment folder - not going through the liferay/deploy directory.
My first question is: Can we still deploy that way with Liferay 7 (ear + jboss deployment folder)?

However I tried to follow the instructions from this post: https://web.liferay.com/community/forums/-/message_boards/message/89548463.
I generated a new liferay project with jsf and cdi and I'm now trying to add my code in bits by bits.

My understanding is that I cannot use jboss dependencies yet but I should include all jars inside the WEB-INF/lib folder of my war.
Is that correct ?

I noticed that all the cdi examples (like the applicant portlet) are using weld-servlet.jar instead of cdi-portlet-bridge-shared-6.2.0.2.jar.
Is that required for Liferay 7 ?

The first issue I'm facing is that the CDI injections don't work if the injected class is defined inside a jar in the WEB-INF/lib.
I get this error :
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type UserSession with qualifiers @Default_  at injection point [UnbackedAnnotatedField] @Inject private com.sopra.banking.workstation.ui.web.controller.OperationalPositionListController.userSession_  at com.sopra.banking.workstation.ui.web.controller.OperationalPositionListController.userSession(OperationalPositionListController.java:0)_ [Sanitized]

The UserSession class is defined in one of the jars and the OperationalPositionListController class is directly defined in the war.
If I move that UserSession from the jar to the war classes it works.
Is there a way around this because I can't move all the classes ?

In the app, I've also included my theme that we used to apply using this property in the portal-ext :
# <themeName>_WAR_<contextroot>
default.theme.id=workstation_WAR_soprabankingworkstationweb
Now this does not work with Liferay7 because the context root is the name of the war file instead of what's defined in the jboss-web.xml.
Does Liferay 7 ignore the jboss-web.xml ?

Any advice or guidance would be much appreciated.

Best Regards,
Jonathan
Neil Griffin, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Legend Posts: 2540 Join Date: 7/26/05 Recent Posts
Hi Jonathan,

Jonathan Locht:
The app is packaged in an ear archive that we used to deploy directly in the jboss deployment folder - not going through the liferay/deploy directory. My first question is: Can we still deploy that way with Liferay 7 (ear + jboss deployment folder)?


Liferay Portal 7 does not support EAR deployment (with embedded portlet WARs) via the app server. Instead, portlet WARs must be deployed via the $LIFERAY_HOME/deploy directory. The reason why this is necessary is that the WAR must undergo transformation to a WAB (OSGi Web Application Bundle) during deployment via the WAB Generator.

Jonathan Locht:
However I tried to follow the instructions from this post: https://web.liferay.com/community/forums/-/message_boards/message/89548463. I generated a new liferay project with jsf and cdi and I'm now trying to add my code in bits by bits.


This is the right approach -- start by generating a new project with one of the archetypes found at the www.liferayfaces.org home page. Then gradually migrate code into the project.

Jonathan Locht:
My understanding is that I cannot use jboss dependencies yet but I should include all jars inside the WEB-INF/lib folder of my war. Is that correct?


Yes, that is correct because the app server (JBoss/WildFly in this case) is not aware of any of the deployed portlet WARs, since they become WABs managed by the OSGi container.

Jonathan Locht:
I noticed that all the cdi examples (like the applicant portlet) are using weld-servlet.jar instead of cdi-portlet-bridge-shared-6.2.0.2.jar. Is that required for Liferay 7?


The cdi-portlet-bridge-shared-6.2.0.2jar dependency should not be necessary if you are using weld-servlet-2.3.3.Final.jar

Jonathan Locht:
The first issue I'm facing is that the CDI injections don't work if the injected class is defined inside a jar in the WEB-INF/lib.
I get this error ... Is there a way around this because I can't move all the classes?


Try adding bean-discovery-mode="all" to beans.xml -- here is an example.

Jonathan Locht:
Does Liferay 7 ignore the jboss-web.xml?


I will ask some of my colleagues to answer that question in a subsequent post in this thread.

Kind Regards,

Neil
JL
Jonathan Locht, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Neil,

I tried adding bean-discovery-mode="all" to the beans.xml but it made no difference.

So I took the demo/jsf-cdi-applicant-portlet sources and added an injection in the ApplicantModelBean like this :


    @Inject
    private TestInjectBean testInjectBean;


And the new class is just


package com.liferay.faces.demos.bean;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class TestInjectBean
    implements Serializable
{
    private static final long serialVersionUID = 1L;

}


The TestInjectBean is in another project jar.
That jar also has a bean.xml and is included in the WEB-INF/lib of the jsf-cdi-applicant-portlet war.

I'm still getting he error :

ERROR [Refresh Thread: Equinox Container: a0e681ea-4565-0017-13af-de170e242069][com_liferay_portal_osgi_web_wab_extender:97] WELD-001408: Unsatisfied dependencies for type TestInjectBean with qualifiers @Default_ at injection point [BackedAnnotatedField] @Inject private com.liferay.faces.demos.bean.ApplicantModelBean.testInjectBean_ at com.liferay.faces.demos.bean.ApplicantModelBean.testInjectBean(ApplicantModelBean.java:0)_ [Sanitized]


I think something is wrong with the CDI injection from lib.
Has any of you tried that configuration ?

Thanks,
Jonathan
David H Nebinger, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

Community Moderator Liferay Legend Posts: 13806 Join Date: 9/1/06 Recent Posts
I hate to contradict my good friend Neil, and typically he trumps me, but...

Jonathan Locht:
The app is packaged in an ear archive that we used to deploy directly in the jboss deployment folder - not going through the liferay/deploy directory.
My first question is: Can we still deploy that way with Liferay 7 (ear + jboss deployment folder)?


Yes, but not like you think. Liferay 7 CE / Liferay DXP does not rely on the application server anymore, so war files are not really used any longer.

That said, we do have the "deployment helper". This is a specialized war file that contains all of the module jars and wars to deploy to Liferay 7 CE / Liferay DXP and upon deployment, will extract the module jars and wars to the $LIFERAY_HOME/deploy folder. So this can, in fact, get bundled into an ear because as a war file the deployment helper doesn't really have a context.

The deployment helper war is meant to be used to support the centralized management consoles of weblogic and websphere, but it should be just as usable for your ear deployment scenario.

In the app, I've also included my theme that we used to apply using this property in the portal-ext :
# <themeName>_WAR_<contextroot>
default.theme.id=workstation_WAR_soprabankingworkstationweb
Now this does not work with Liferay7 because the context root is the name of the war file instead of what's defined in the jboss-web.xml.
Does Liferay 7 ignore the jboss-web.xml ?


Since the theme is actually hosted within the Liferay OSGi container (and not deployed as a war to the app server), the jboss-web.xml file is neither used or recognized.








Come meet me at the 2017 LSNA!
David H Nebinger, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

Community Moderator Liferay Legend Posts: 13806 Join Date: 9/1/06 Recent Posts
Note that using the deployment helper to package and deploy jars and wars, even when bundled into an ear, would not allow for using @EJB or other JEE annotations or other JEE features.

The deployment helper would only allow for packaging in an ear format for deployment only and would not enable any JEE functionality.









Come meet me at the 2017 LSNA!
JL
Jonathan Locht, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Thanks David,

I found that I could use the property
Web-ContextPath: /myContextRoot
inside the liferay-plugin-package.properties file.
The theme name is now correctly populated.

We do use EJB in our project.
If we can't deploy the ear in Liferay how can we manage the EJB ?
Would it be a right approach to split the project into one war for the web part (deployed in Liferay) and one ear for the EJB part (that we would just put in the jboss deployment folder) ? Would it be possible to call the EJB from the war then ?

Regards,
Jonathan
David H Nebinger, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

Community Moderator Liferay Legend Posts: 13806 Join Date: 9/1/06 Recent Posts
Jonathan Locht:
We do use EJB in our project.
If we can't deploy the ear in Liferay how can we manage the EJB ?
Would it be a right approach to split the project into one war for the web part (deployed in Liferay) and one ear for the EJB part (that we would just put in the jboss deployment folder) ? Would it be possible to call the EJB from the war then ?


I don't know that it is going to work... All of the module jars (and even war files are converted to wabs) run underneath Liferay's OSGi container, and as such I don't think they actually have access to other entities in the app container, but honestly I haven't tried this at all.

I see them as two separate containers, one is the app server and the other is OSGi. Liferay has built in some bridging to allow pieces of the OSGi container to get access to the Liferay code running in the app server, but I don't know if the same is true for accessing anything else in the app server.







Come meet me at Devcon 2017 or 2017 LSNA!
Neil Griffin, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Legend Posts: 2540 Join Date: 7/26/05 Recent Posts
Hi Jonathan,

Thank you for bringing the WELD-001408 error to our attention. I have been able to reproduce it. It is associated with the following warning from Weld:

WARN [Bootstrap:105] WELD-ENV-000031: The bean archive reference bundleresource://532.fwk345489975:10/META-INF/beans.xml cannot be handled by any BeanArchiveHandler

Solving the problem will require a contribution from Liferay to the Weld project, so that weld-servlet.jar will be able to discover the annotated beans properly in an OSGI environment. I will incorporate that into our development calendar.

For now, I am experimenting with a CDI Extension to see if that can be used as a workaround. I will report back here when I have results.

Kind Regards,

Neil
JL
Jonathan Locht, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Neil,
I'm looking forward to hearing from you.
Thank you so much for your time.
Jonathan
Neil Griffin, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Legend Posts: 2540 Join Date: 7/26/05 Recent Posts
Hi Jonathan,

I figured out a workaround using Dynamic CDI Producers.

Attached you will find a simple maven project that contains TestInjectBean.java and an associated Dynamic CDI Producer named TestInjectBeanProducer.java

The drawback of this approach is that you need to create a Dynamic CDI Producer for each bean that you might want to @Inject. Also you will need to register each one in TestExtension.java

But if the friendly folks at JBoss are willing to merge a future fix into the codebase for weld-servlet, then you will be able to simply remove the dynamic producers and things should continue to work.

Kind Regards,

Neil
JL
Jonathan Locht, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Neil,

Thank you very much for providing the workaround.
Unfortuntely I don't think it'll be able applicable in our app.
Because we have dozens of injections comming from many different libraries (deltaspike for example).
I would have to create and register the producer for each one of them.

Regards,
Jonathan
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Hi Jonathan,
I have a more general version of Neil's workaround that should scan and find all @Named beans in your WEB-INF/lib jars and create producers for them. I've created a github project which you can build and add to your dependencies.

Alternatively, you can use the following CDI extension code as an example of what you need to do and copy it into a WEB_INF_libBeanScanner.java class file in your .war.

WEB_INF_libBeanScanner.java:


public final class WEB_INF_libBeanScanner implements Extension {

    // Private Constants
    private static final List<String> BLACKLISTED_PACKAGES = Collections.unmodifiableList(
        Arrays.asList("com.sun", "org.jboss.weld", "javax"));

    public void afterBean(@Observes final AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {

        Bundle thickWebApplicationBundle = FrameworkUtil.getBundle(WEB_INF_libBeanScanner.class);
        BundleWiring bundleWiring = thickWebApplicationBundle.adapt(BundleWiring.class);
        Collection<String> classFilePaths = bundleWiring.listResources("/", "*.class",
            BundleWiring.LISTRESOURCES_RECURSE);

        for (String classFilePath : classFilePaths) {

            URL resource = thickWebApplicationBundle.getResource(classFilePath);
            boolean classFromWEB_INF_classes = resource.getPort() < 1;
            String className = classFilePath.replaceAll("\\.class$", "").replace("/", ".");

            if (classFromWEB_INF_classes ||
                BLACKLISTED_PACKAGES.parallelStream()
                    .anyMatch(blacklistedPackage -> className.startsWith(blacklistedPackage))) {
                continue;
            }

            ClassLoader bundleClassLoader = bundleWiring.getClassLoader();
            Class<?> clazz;

            try {
                clazz = bundleClassLoader.loadClass(className);
            }
            catch (ClassNotFoundException | NoClassDefFoundError e) {
                continue;
            }

            Named namedAnnotation = clazz.getAnnotation(Named.class);

            if (namedAnnotation == null) {
                continue;
            }

            AnnotatedType annotatedType = beanManager.createAnnotatedType(clazz);
            BeanAttributes beanAttributes = beanManager.createBeanAttributes(annotatedType);
            InjectionTargetFactory injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
            Bean producer = beanManager.createBean(beanAttributes, clazz, injectionTargetFactory);
            afterBeanDiscovery.addBean(producer);
        }
    }
}

You'll also need to add a META-INF/services/javax.enterprise.inject.spi.Extension file with something like package.of.your.WEB_INF_libBeanScanner inside of it.

You may also need to add a dependency to your project:

<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>


Edit: the above code is incorrect. If you do not want to include the latest WEB-INF_lib-bean-scanner jar, then you can simply copy the latest code (it's only 2 files) into your war. See this post for more details.

Please let us know if that works for you.

- Kyle
JL
Jonathan Locht, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Kyle,

Thank you so much for this tip on cdi spi extensions.
I'm trying to make it work with the jsf cdi demo portlet from here
https://web.liferay.com/community/liferay-projects/liferay-faces/demos#jsf-cdi-applicant-portlet

So I downloaded the sources and added the WEB_INF_libBeanScanner.java and the META-INF/services/javax.enterprise.inject.spi.Extension files.
I added the osgi and cdi-api as dependencies in the pom.xml (with <scope>provided</scope>).
I also had to change the maven-compiler-plugin java version configuration from 1.6 to 1.8

But nothing happens: I cannot see any logs from the libBeanScanner.
I've also added a bunch of logs in the static block and a beforeBeanDiscovery method but still nothing.
Am I missing a configuration or a dependency ?
Could you provide an example ?

Kind Regards,
Jonathan
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Hi Jonathan,
Please build the entire github project into a jar (by following the instructions in the README.md) and include it in your portlet's WEB-INF/lib rather than copying the files, and let me know if that works. If not, please attach a sample project that reproduces the issue so I can try to fix it for you.

- Kyle
JL
Jonathan Locht, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Kyle,

I confirm that it works with the jar included in the war.
The libBeanScanner is well called now and allows to inject the named classes.

The only problem is that some classes don't have the named annotation.
For example I need to include the deltaspike extension and I get this error :
java.lang.IllegalStateException: Could not find beans for Type=class org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder and qualifiers:[]_
.
I tried adding in the scanner all the classes with a javax.enterprise.context.* annotation.
Then I found that deltaspike has it's own context annotation so I've put them in as well.

Now I get this error :
WELD-001408: Unsatisfied dependencies for type WindowContext with qualifiers @Default_ at injection point [BackedAnnotatedField] @Inject private org.apache.deltaspike.core.impl.scope.window.WindowContextQuotaHandlerCache.windowContext_ at org.apache.deltaspike.core.impl.scope.window.WindowContextQuotaHandlerCache.windowContext(WindowContextQuotaHandlerCache.java:0)

which I'm guessing is because the WindowContextImpl has a producer (WindowContextProducer) instead of an annotation.
But the WindowContextProducer is well detected by the libBeanScanner because of it's @ApplicationScoped.

I'm not sure what I'm missing now.
Should the producers be called in the libbeanscanner ?

Thanks a lot for your help,
Jonathan
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Hi Jonathan,
Please attach the simplest sample project that reproduces the issue so I can take a look at it (a maven project would be most helpful). I don't have enough knowledge of Apache DeltaSpike to try fixing this without a reproducer.

- Kyle
JL
Jonathan Locht, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hello Kyle,
Please find my test project attached.
It's basically the jsf-cdi-applicant portlet demo with a small change in the pom.xml to add deltaspike.
Jonathan
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Thanks Jonathan, I've reproduced your issue and am working on a solution.

- Kyle
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Hi Jonathan,
I've updated the WEB-INF_lib-bean-scanner project on github and tagged version 0.2.0. Please rebuild the jar (by following the updated instructions in the README.md), include it in your portlet's WEB-INF/lib, and let me know if it that fixes your issue. If not, please let me know what errors you find and provide a simple reproducer.

Thanks,
- Kyle
JL
Jonathan Locht, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hello Kyle,
That works perfectly well, I don't have any CDI issue anymore.
I'll now add my other dependencies and see how it goes.
Thank you so much,
Jonathan
Kyle Joseph Stiemann, modified 5 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Master Posts: 662 Join Date: 1/14/13 Recent Posts
Hi Jonathan,
Glad it's working for you! emoticon Please let us know if you have any other issues. Thanks for using Liferay Faces!

- Kyle
JL
Jonathan Locht, modified 10 Months ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Hi Neil,

My colleague was given the advise (thanks to Huage Chen) to use jandex as a workaround.
But I'm not sure I understand the point.
Would it be used to programatically register and generate the producers ?

Did you get any update on the WELD issue ?

Regards,
Jonathan
Neil Griffin, modified 10 Months ago.

RE: JSF app with CDI in Liferay 7

LIFERAY STAFF Liferay Legend Posts: 2540 Join Date: 7/26/05 Recent Posts
Hi Jonathan,

It's my best understanding that Huage Chen will be getting back to you regarding Jandex as a potential workaround.

Regarding the Weld issue, we haven't decided if it is something we will handle on the Liferay side or if we should make a contribution to the Weld project.

Regarding EJB, please follow the thread titled Use features of the JEE application server in Liferay 7 -- in the coming days there should be an update from Liferay's Ray Auge.

Kind Regards,

Neil
JL
Jonathan Locht, modified 1 Year ago.

RE: JSF app with CDI in Liferay 7

New Member Posts: 11 Join Date: 7/4/17 Recent Posts
Does that mean we can't/shouldn't use EJB with Liferay 7 ?
Would you recommand another technology ?