joinfaces / joinfaces-maven-jar-example

JoinFaces Maven Jar Example
83 stars 79 forks source link

AdminFaces support #103

Closed rmpestano closed 6 years ago

rmpestano commented 7 years ago

Hi guys,

I'm trying to create an example based on your great project but looks like my CDI beans are not being recognized. The beans are inside another project (jar dependency) and are application and session scoped from javax.enterprise package.

The sample project can be found here: https://github.com/adminfaces/admin-boot

And there was some discussion on this issue which may help: https://github.com/adminfaces/admin-template/issues/13

As you can see on the sample project, the index.xhtml references a bean called AdminConfig (app scoped) and SkinMB (session scoped) but looks like both are being ignored. When I look into html page source, body class should have class 'skin-blue' resolved by a property in SkinMB (session scoped bean from admin-template) but it doesnt.

Same for:

<p:ajaxStatus rendered="#{adminConfig.renderAjaxStatus}"....

The rendered evaluates to false.

Any ideas? thanks in advance.

persapiens commented 6 years ago

hi @rmpestano ,

First of all, congrats for your amazing AdminFaces!

I've started Adminfaces Starter branch. I followed discussion in https://github.com/adminfaces/admin-template/issues/13.

AdminfacesAutoConfiguration does some tasks:

I've forked Admin Boot. If you build the joinfaces brach above, you will see it Admin Boot working with java -jar targer/admin-boot.jar

I've forked Admin Starter too. If you build the joinfaces brach above, you will see it Admin Boot working with java -jar target/admin-starter.war

However, there is one issue with both examples: just released mojarra 2.3.4 fails. In Admin Boot, just press 'Submit' button and you will see the error. If I downgrade to 2.3.3 or use myfaces instead of mojarra, it works. Could you verify it?

I look forward your answer.

rmpestano commented 6 years ago

Hi @persapiens,

that's great news!

I've tried admin-starter and its working great, the only thing missing is to autoconfigure AdminFilter. The filter is responsible for redirecting user to login page if user is not logged in and to redirect user back to the page it was after session expiration.

The filter uses AdminSession to know if user is loggedIn or not, it is just a method which returns boolean.

I've tried to configure the filter in AdminfacesAutoConfiguration like below:

       @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> adminfacesWebServerFactoryCustomizer() {
        return factory -> {
            factory.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN, "/403.jsf"),
                    new ErrorPage(AccessDeniedException.class, "/403.jsf"),
                    new ErrorPage(HttpStatus.NOT_FOUND, "/404.jsf"),
                    new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/500.jsf"),
                    new ErrorPage(Throwable.class, "/500.jsf"),
                    new ErrorPage(ViewExpiredException.class, "/expired.jsf"),
                    new ErrorPage(OptimisticLockException.class, "/optimistic.jsf")
            );
            factory.addInitializers(servletContext -> {
                servletContext.addListener(new AdminServletContextListener());
                                FilterRegistration adminFilterRegistration = servletContext.addFilter("AdminFaces", AdminFilter.class);
                    adminFilterRegistration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
            });

        };
    }

But I am getting a NPE here, looks like AdminConfig was not inject, here is the stacktrace:

2018-04-09 14:16:33.432 ERROR 24058 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Exception starting filter [AdminFaces]

java.lang.NullPointerException: null
    at com.github.adminfaces.template.session.AdminFilter.init(AdminFilter.java:53) ~[admin-template-1.0.0-RC13.jar!/:na]
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:285) ~[tomcat-embed-core-8.5.29.jar!/:8.5.29]
    at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:266) ~[tomcat-embed-core-8.5.29.jar!/:8.5.29]
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108) ~[tomcat-embed-core-8.5.29.jar!/:8.5.29]
rmpestano commented 6 years ago

Also another thing I got was a classnotfound exception when the Exception handler was invoked. The handler is responsible for redirecting user to error and optmisticLock pages and also showing error facesMessage on the page when a BusinessException is raised.

This can be fixed by adding EJB API do the admin-starter:

        <dependency>
            <groupId>javax.ejb</groupId>
            <artifactId>javax.ejb-api</artifactId>
            <version>3.2</version>
        </dependency>

The EJB dependency is needed to unwrap exceptions raised in EJBs.

persapiens commented 6 years ago

I think AdminFilter is autoconfigured. It is created by

  @ServletComponentScan({"com.github.adminfaces.template.security",
    "com.github.adminfaces.template.session"})

The code above creates AdminSession instance:

  @Bean
  @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
  public AdminSession adminSession() {
    return new AdminSession();
  }

The code above creates AdminConfig instance:

  @ComponentScan({"com.github.adminfaces.template.bean",
    "com.github.adminfaces.template.config",
    "com.github.adminfaces.template.security"})

AdminFilter is singleton scope, AdminConfig is singleton scope, but AdminSession is session scope. You inject AdminSession (session scope) into AdminFilter (singleton). It is not usual to me. I had to use ScopedProxyMode.TARGET_CLASS to enable the injection.

More, I've included javax.ejb-api dependency. Just pull adminfaces branch, rebuild it and try again.

rmpestano commented 6 years ago

Ok, I think I got the "problem". If you see AdminStarter sample application here it prompts the login page. It happens because AdminSession is overidden (via CDI bean specialization) here. So isLoggedIn, which is true by default, was changed in admin-starter to return true only if current user is != null. Current user is set on login method invoked by login page here.

In the end AdminFilter will check if user is loggedIn here and if not it will redirect user to login page.

So in order to make it work we need to set isLoggedIn to false in a sessionScoped bean. If bean specialization is not working we can also call setLoggedIn to false, I just don't know how/when to initialize AdminSession.

persapiens commented 6 years ago

Adminfaces cdi beans are created by spring in adminfaces-spring-boot-starter. In this case, @ Specializes does not work.

I've just included the following at LogonMB:

@Primary
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)

Usually, only @ Primary is necessary. I had to include @ Scope to solve injection of session bean into singleton one.

rmpestano commented 6 years ago

This is working great now!

Thank you very much @persapiens! I'll add your admin-starter fork to AdminFaces organization after the release of JoinFaces containing AdminFacesAutoconfiguration.

This integration will bring the Spring community to AdminFaces and probably more contributors and feedback.

Thank you again for your great work!

I've renamed the issue because it solves the integration of AdminFaces and is not a CDI SpringBoot problem as I thought at the first moment.

I think we can close it now.

persapiens commented 6 years ago

This issue was moved to joinfaces/joinfaces#454