1

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" />

すべてがOKで、ActionEventによってリスナー内のBeanとアクションを検出できますが、複合コンポーネントとこのコードでは、実際のアクションパラメーターに関する情報がありません。

ブレース表記を使用した場合も同じ問題が発生します:#{beanName['action']}。この場合、デバッグモードでは、メソッドExpressionImplおよびVariableMapperImplとバインドされているオブジェクトTagMethodExpressionを確認できます。ここで、マッピングbeanName-> "real_bean_name"

複合コンポーネントまたはブレース表記によって生成された場合、ActionEventによってBeanとアクションを取得する方法はありますか?

ありがとう!

4

1 に答える 1

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));
    }
}
...
于 2013-03-20T13:08:57.657 に答える