JSF - 从复合组件中获取ActionEvent中的bean和操作名称

时间:2013-02-21 08:19:37

标签: jsf actionlistener composite-component actionevent

我有一个复合组件来动态调用bean动作:

<composite:interface>
    <composite:attribute name="actionMethod" method-signature="java.lang.String action()"/>
</composite:interface>

<composite:implementation>

    <p:menubar autoDisplay="false" styleClass="subMenu">
        <p:menuitem>
             <h:commandButton action="#{cc.attrs.actionMethod}" value="#{bundle.CreateSaveLink}" styleClass="smallButton button buttonSave"/>
        </p:menuitem>
    </p:menubar>

</composite:implementation>

我还定义了一个ActionListener类来实现安全性:

public class SecurityActionListener extends ActionListenerImpl implements ActionListener {


    private static final Logger log = Logger.getLogger(SecurityActionListener.class);
    private String isCasEnabled;

    public SecurityActionListener() {
        isCasEnabled = PropertyUtility.isCasEnabled();
    }


    @SuppressWarnings("unused")
    @Override
    public void processAction(final ActionEvent event) {

        if(!isCasEnabled.equals("true")) {
            super.processAction(event);
            return;
        }


        final FacesContext context = FacesContext.getCurrentInstance();
        final Application application = context.getApplication();
        final ConfigurableNavigationHandler navHandler = (ConfigurableNavigationHandler) application.getNavigationHandler();

        // Action stuff
        final UIComponent source = event.getComponent();
        final ActionSource actionSource = (ActionSource) source;
        MethodBinding binding;

        binding = actionSource.getAction();
        final String expr = binding.getExpressionString();
        if (!expr.startsWith("#")) {
            super.processAction(event);
            return;
        }

        final int idx = expr.indexOf('.');
        if (idx <0) {
            log.error("Errore nella formattazione della chiamata al metodo: " + expr + ". No '.' found");
            return;
        } 

        final String target = expr.substring(0, idx).substring(2);
        final String t = expr.substring(idx + 1);
        String method = t.substring(0, (t.length() - 1));

        final int idxParams = method.indexOf('(');
        if (idxParams >=0) {
            method = method.substring(0,idxParams);
        }

        final MethodExpression expression = new MethodExpressionMethodBindingAdapter(binding);
        final ELContext elContext = context.getELContext();
        final ExpressionFactory factory = context.getApplication().getExpressionFactory();

        final ValueExpression ve = factory.createValueExpression(elContext, "#{" + target + '}', Object.class);
        final Object result = ve.getValue(elContext);

        // Check if the target method is a secured method
        // and check security accordingly
        final Method[] methods = result.getClass().getMethods();
        for (final Method meth : methods) {
            if (meth.getName().equals(method)) {
                if (meth.isAnnotationPresent(CustomSecurity.class)) {
                    final CustomSecurity securityAnnotation = meth.getAnnotation(CustomSecurity.class);
                    log.debug("Function to check security on: " + securityAnnotation.value()); 
                    SecurityUtility.checkSecurity(securityAnnotation.value());
                } else {
                    super.processAction(event);
                }
                break;
            }
        }

        log.warn("No method: " + method + " found in: " + methods + ", for object: " + result);

    }

}

如果对commandButton的操作是以标准方式定义的:

<h:commandButton action="#{bean.action}" value="test" />

一切正常,我能够通过其ActionEvent检测监听器中的bean和动作,但是使用复合组件和代码我没有关于实际动作参数的信息

如果我使用括号表示法,我会遇到同样的问题:#{beanName ['action']}。 在这种情况下,在调试模式下,我可以看到对象TagMethodExpression与MethodExpressionImpl和VariableMapperImpl绑定,其中有映射beanName - &gt; “real_bean_name”

如果它是由复合组件或括号表示法生成的,那么有没有办法通过ActionEvent获取bean和动作?

谢谢!

1 个答案:

答案 0 :(得分:1)

不是很干净的解决方案,但我解决了使用ActionSource2,MethodExpression和Reflection来访问TagMethodExpression私有字段......

final ActionSource2 actionSource = (ActionSource2) source;
MethodExpression expression;
expression = actionSource.getActionExpression();
String exp = expression.getExpressionString();

String trimmed = exp.trim();

// remove ending bracket
trimmed = trimmed.substring(0, trimmed.lastIndexOf("']"));

int openBracket = trimmed.lastIndexOf("['");

String beanName = trimmed.substring(0, openBracket);
StringBuilder builder = new StringBuilder(beanName);
builder.append('.');
builder.append(trimmed.substring(openBracket + 2, trimmed.length()));

String ret = builder.toString();

if (expression instanceof TagMethodExpression) {
    try {

        TagMethodExpression tme = (TagMethodExpression) expression;
        Field f = tme.getClass().getDeclaredField("orig");
        f.setAccessible(true);
        MethodExpression me = (MethodExpression) f.get(tme);
        Field ff = me.getClass().getDeclaredField("varMapper");
        ff.setAccessible(true);
        VariableMapperImpl vmi = (VariableMapperImpl) ff.get(me);
        ValueExpression beanResolveVariable = vmi.resolveVariable(beanName);
        String toString = beanResolveVariable.toString();
        Pattern pattern = Pattern.compile("value=\"#\\{(.*?)\\}");
        Matcher matcher = pattern.matcher(toString);

        if(matcher.find()){
            String realBeanName = matcher.group(1);
            ret = ret.replace(beanName, realBeanName);
        }
    } catch (NoSuchFieldException ex) {
        log.error(LogUtility.getStrExc(ex));
    } catch (SecurityException ex) {
        log.error(LogUtility.getStrExc(ex));
    } catch (IllegalAccessException ex) {
        log.error(LogUtility.getStrExc(ex));
    }
}
...