我可以在Hibernate事件侦听器中访问FacesContext吗? [英] Can I access FacesContext inside Hibernate event listener?

查看:131
本文介绍了我可以在Hibernate事件侦听器中访问FacesContext吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的场景:

我有my-jsf-app.war(JSF 1.2应用程序)和daos-and-entities.har(Hibernate 3.3.1 )部署到JBOSSAS 5服务器。我想要的是在我的应用程序中有某种更改日志,其中包含谁进行了更改的信息。所以我的想法是让hibernate事件监听器访问FacesContext(或者实际上在上下文中的HttpSession)来检索当前登录的用户。



因此,基本上我配置了事件监听器并添加了以下方法来检索当前登录的用户。

  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);
方法methodGetExternalContext = classFacesContext.getMethod(getExternalContext,(Class [])null);
方法methodGetRemoteUser = classExternalContext.getMethod(getRemoteUser,(Class [])null);

//这个调用总是返回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);
返回登录;

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

返回匿名;
}

我使用java反射来做到这一点,因为HAR文件也用在其他非jsf项目。

问题是我从来没有得到一个currentFacesContext。我明白FacesContext.getCurrentInstance()是ThreadLocal。但是,如果在JSF ManagedBean action方法中直接触发hibernate操作(例如saveOrUpdate()),那么事件监听器不应该与action方法执行相同的线程吗?

任何帮助都很有价值,也许对于我的情况来说也是一种完全不同的方法,我不知道。我显然不希望为我的所有dao调用添加一个userContext参数,因为这将是一项巨大的工作。



提前Thx

解决方案

获得有价值的提示后,我找到了解决方案。 WAR在其WEB-INF \ lib中包含JSF实现JAR。由于WAR和HAR是独立的部署,因此它们使用单​​独的类加载器,导致WAR从Web-INF \ lib中加载JSF实现,而HAR则从JBOSS安装加载它。



我可以通过以下方式更改上面的代码来强制使用正确的类加载器:

  protected static String tryToFindUserLogin(){

try {
/ ***从调用线程获取classLoader,而不是使用默认的** * /
ClassLoader classLoader = Thread.currentThread()。getContextClassLoader();
Class classFacesContext = classLoader.loadClass(javax.faces.context.FacesContext);
Class classExternalContext = classLoader.loadClass(javax.faces.context.ExternalContext);
/ ************** /

方法methodGetCurrentInstance = classFacesContext.getMethod(getCurrentInstance,(Class [])null);
方法methodGetExternalContext = classFacesContext.getMethod(getExternalContext,(Class [])null);
方法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);
返回登录;

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

返回匿名;
}

另外我更改catch catch(Throwable),因为如果运行非JSF环境getMethod()可能会抛出一个RuntimeException,它不会被catch(Exception)捕获(Exception)



这非常完美!


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 (e.g. 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!

这篇关于我可以在Hibernate事件侦听器中访问FacesContext吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆