1

This question is an offshoot of another that I posted a couple of weeks ago: log4j2 logging of code in EJB jar on JBoss EAP 7. In that post I posed a problem and eventually a solution for logging initialization on EJBs deployed as EJB jars (not EARs) onto a JBoss EAP 7 Server and invoked from another servlet. These EJBs are invoked through local interface.

The solution I presented in that link worked beautifully for the first EJB I tried it with, a Stateful EJB. the @PostConstruct-annotated method is called and initializes the logging context and everything works great.

The solution failed on the second EJB I tried it with. This EJB was stateless. @PostConstruct method is never called and the first attempt at logging blows the thing up because logger is null. The only difference I could see between the two beans was that the second one was stateless whereas the first was stateful. As an experiment, I made the second one stateful. Once I did that, @PostConstruct was called, logging got initialized and everything was basically fine.

According to the Oracle JavaEE6 tutorial, @PostConstruct method is supposed to be called on stateless bean instantiation. So, why does stateful session bean instantiation call @PostConstruct while stateless session bean instantiation does not, and what might I do about it?

Thanks.

Update: Adding Source Code.

ejb-jar.xml

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         version="3.2"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd">
    <module-name>DealerLocatorBean</module-name>
    <enterprise-beans>
        <session>
            <ejb-name>DealerLocatorBean</ejb-name>
            <home>com.whatever.ServiceLogicHome</home>
            <remote>com.whatever.ServiceLogic</remote>
            <local-home>com.whatever.ServiceLogicLocalHome</local-home>
            <local>com.whatever.ServiceLogicLocal</local>
            <ejb-class>com.whatever.ejbs.DealerLocatorBean</ejb-class>
            <session-type>Stateless</session-type>
            <!-- <session-type>Stateful</session-type> No problem if this is made stateful-->
            <transaction-type>Bean</transaction-type>
        </session>
    </enterprise-beans>
</ejb-jar>

DealerLocatorBean.java:

public class DealerLocatorBean implements SessionBean
{

    private static final String LOGGER_CONFIG = "/path/to/log4j2.xml";
    private static final String LOGGER_CONTEXT_NAME = "VTDLLOC-EJB";
    private static LoggerContext logctx;
    private static Logger logger = null;

    public DealerLocatorBean() {
        System.out.println("calling DealerLocatorBean() constructor");
    }
    @PostConstruct
    @TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
    private void postConstruct() {
        System.out.println("DealerLocatorBean.postConstruct()");
        logctx = Configurator.initialize(LOGGER_CONTEXT_NAME, LOGGER_CONFIG);
        logger = logctx.getLogger(getClass().getName());
        logger.log(Level.INFO, ("postConstruct() in DealerLocatorBean called"));
        logger.log(Level.INFO, ("******END OF THE postConstruct() CALL******"));
    }

    @PreDestroy
    @TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
    private void preDestroy() {
        logger.log(Level.INFO, ("preDestroy() in DealerLocatorBean called.  Shutting down logging."));
        Configurator.shutdown(logctx);
    }

If the bean is deployed as stateful (in ejb-jar.xml), @postConstruct is called the first time the bean is used after deployment and everything works. DealerLocatorBean.postConstruct() is seen in the output and all subsqeuent logging works.

If the bean is deployed as stateless (in ejb-jar.xml), @postConstruct is never called. DealerLocatorBean.postConstruct() is NOT seen in the output. Logging is not initialized, and NullPointerExceptions result as soon as the code tries to log something through logger.

Community
  • 1
  • 1
Steve Cohen
  • 4,679
  • 9
  • 51
  • 89
  • I don’t use EAP, but with all JBOSS community EE6 and EE7 editions that I have worked “@PostConstruct” works flawlessly and that this must be a case with EAP versions which are supposed to be more stable. Search the logs for a Runtime exception that eventually has occurred during the “@PostConstruct” of the particular SLSB. – garfield Dec 02 '16 at 02:58
  • Thanks, but I don't think this can be the cause. I added a System.out.println statement as the first line of the @PostConstruct method and it does not appear in the server.log when the bean is stateless (indicating no call of the method) and does appear when the bean is made stateful. No runtime exceeption occurs in either case. – Steve Cohen Dec 02 '16 at 20:53
  • Maybe you should post the code for the specific SLSB. – garfield Dec 05 '16 at 04:05
  • I cannot post the code for this SLSB. It contains too much proprietary business logic, all of which is irrelevant to the problem at hand. I will try to post, the ejb-jar.xml and the PostConstruct and PreDestroy methods which should be all that is necessary. – Steve Cohen Dec 05 '16 at 20:26
  • There are certain things here, with which I'm not familiar. Have you seen this bean reported to the logs as deployed? Also not final statics are not allowed in SLSBs. I would suggest to change private static LoggerContext logctx; to private static final LoggerContext logctx= Configurator.initialize(LOGGER_CONTEXT_NAME, LOGGER_CONFIG); if possible and the same for logger and remove the corresponding statements out of @PostConstruct or just remove the static keyword in the declarations of logctx and logger. – garfield Dec 06 '16 at 02:40
  • @garfield - You are correct. I was able to get it to "work" by replacing the non-final static members with static final. However, on further reading, I learned the reasons for these restrictions - that they don't transfer to code running on other jvms/machines, which EJBs are supposed to do. Pondering the meaning of LoggerContext objects shared across machines made me realize I was opening a Pandora's box when I went from standalone to clustered JBoss. However I found a viable alternative - deploying EJB in War File. This freed me of need to define LoggerContexts in my code. – Steve Cohen Dec 07 '16 at 17:17
  • 1
    @garfield - make your remarks an "answer" and I'll be happy to upvote you. – Steve Cohen Dec 07 '16 at 17:17

1 Answers1

0

Have you seen this bean reported to the logs as deployed? Also not final statics are not allowed in SLSBs. I would suggest to change private static LoggerContext logctx; to private static final LoggerContext logctx= Configurator.initialize(LOGGER_CONTEXT_NAME, LOGGER_CONFIG); if possible and the same for logger and remove the corresponding statements out of @PostConstruct or just remove the static keyword in the declarations of logctx and logger.

garfield
  • 571
  • 9
  • 21