简体   繁体   中英

Can I access FacesContext inside Hibernate event listener?

Here is my scenario:

I have my-jsf-app.war (JSF 1.2 application) and daos-and-entities.har (Hibernate 3.3.1) deployed to a JBOSSAS 5 server. What I want is to have some sort of change log in my application, that contains the information "who made the change". So my idea was to have hibernate event listeners that access the FacesContext (or actually the HttpSession inside the context) to retrieve the currently logged in user.

So basically I configured event listeners and added the following method to retrieve the currently logged in user.

protected static String tryToFindUserLogin() {

    try {
        Class classFacesContext = Class.forName("javax.faces.context.FacesContext");
        Class classExternalContext = Class.forName("javax.faces.context.ExternalContext");
        Method methodGetCurrentInstance =  classFacesContext.getMethod("getCurrentInstance", (Class[])null);
        Method methodGetExternalContext =  classFacesContext.getMethod("getExternalContext", (Class[])null);
        Method methodGetRemoteUser =  classExternalContext.getMethod("getRemoteUser", (Class[])null);

        // This call always returns null
        Object currentFacesContext = methodGetCurrentInstance.invoke(null, (Object[])null);

        Object currentExternalContext = methodGetExternalContext.invoke(currentFacesContext, (Object[])null);
        String login = (String)  methodGetRemoteUser.invoke(currentExternalContext, (Object[])null);
        logger.debug("Found Weblogin: " + login);
        return login;

    } catch (Exception e) {
        logger.debug(e, e);
    }

    return "anonymous";
    }

I use java reflection to do this, because the HAR file is also used in other non-jsf-projects.

The problem is that I never get a currentFacesContext. I understand that FacesContext.getCurrentInstance() is ThreadLocal. But if the hibernate action (eg saveOrUpdate()) is directly triggered from within a JSF ManagedBean actionmethod, shouldn't the event listener be executed by the same thread as the actionmethod?

Any help is appriciated, maybe there ist also a totally different approach to my scenario, that I'm not aware of. I obviously don't want to add a userContext paramter to all my dao calls though, as this would be a huge amount of work.

Thx in advance

After getting a valueable hint, I found a solution. The WAR has the JSF Implementation JARs inside its WEB-INF\\lib. As WAR and HAR are separate deployments, they use separate class loaders, which results in the WAR loading JSF Implementation from its WEB-INF\\lib, while the HAR loads it from the JBOSS installation.

I was able to force the use of the correct classloader by changing the above code in the following way:

protected static String tryToFindUserLogin() {

    try {
        /*** Obtain the classLoader from the calling Thread, instead of using the default ***/
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class classFacesContext = classLoader.loadClass("javax.faces.context.FacesContext");
        Class classExternalContext = classLoader.loadClass("javax.faces.context.ExternalContext");
        /**************/

        Method methodGetCurrentInstance =  classFacesContext.getMethod("getCurrentInstance", (Class[])null);
        Method methodGetExternalContext =  classFacesContext.getMethod("getExternalContext", (Class[])null);
        Method methodGetRemoteUser =  classExternalContext.getMethod("getRemoteUser", (Class[])null);

        Object currentFacesContext = methodGetCurrentInstance.invoke(null, (Object[])null);

        Object currentExternalContext = methodGetExternalContext.invoke(currentFacesContext, (Object[])null);
        String login = (String)  methodGetRemoteUser.invoke(currentExternalContext, (Object[])null);
        logger.debug("Found Weblogin: " + login);
        return login;

    } catch (Throwable e) {
        logger.debug(e, e);
    }

    return "anonymous";
    }

Additionally I changed the catch block to catch(Throwable), because if run in non JSF environment getMethod() might throw a RuntimeException, which ist not caught by catch(Exception)

This works perfectly!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM