我有一个复合组件来动态调用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和动作?
谢谢!
答案 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));
}
}
...