/* DelegatingVariableResolver.java
{{IS_NOTE
Purpose:
Description:
History:
Dec 31, 2009 10:56:14 AM, Created by henrichen
}}IS_NOTE
Copyright (C) 2009 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under GPL Version 3.0 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zkplus.cdi;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import org.zkoss.lang.Objects;
import org.zkoss.xel.VariableResolverX;
import org.zkoss.xel.XelContext;
import org.zkoss.xel.XelException;
/**
* Generic CDI EL named managed bean resolver.
* <p>Applicable to CDI version 1.0 or later</p>
* @author henrichen
*
*/
public class DelegatingVariableResolver implements VariableResolverX {
private BeanManager _beanMgr;
public DelegatingVariableResolver() {
_beanMgr = CDIUtil.getBeanManager();
}
public Object resolveVariable(String name) throws XelException {
return resolveVariable(null, null, name);
}
@SuppressWarnings("rawtypes")
public Object resolveVariable(XelContext ctx, Object base, Object name) throws XelException {
if (base != null || !(name instanceof String))
return null;
final Set<Bean<?>> beans = _beanMgr.getBeans((String) name);
if (beans == null || beans.size() == 0)
return null;
//I(Dennis) think we don't need to check(if there are more than one bean has same name), CDI should check this when startup
//However, Since it returns a Set, so I just check it.
//Note, I do some test, the alternative bean will not be returned by the getBeans api with the name.
Bean bean = null;
for (Bean b : beans) {
if (b.isAlternative())
continue; //(Ian Tsai) alternative is the bean with explicit declaration in bean.xml. they are reserved for Bean
if (bean != null) {
throw new XelException(
"more than one non-alternative bean have same name " + bean + " and " + b + ", name " + name);
}
bean = b;
}
if (bean == null)
return null;
CreationalContext context = _beanMgr.createCreationalContext(null);
/*
* Ian Tsai & Dennis
*
* We are not sure what is the best way to handle the life cycle of CreationalContext.
* CreationalContext is the context designed to serve a specific contextual bean type,
* we are using null here, so we got no contextual concept.
*/
// CreationalContext context = ctx==null?
// null:(CreationalContext)ctx.getAttribute(CREATIONAL_CONTEXT);
// if(context==null){
// System.out.println(">>>>>create a new CreationalContext");
// context = _beanMgr.createCreationalContext(null);
// if(ctx!=null){
// ctx.setAttribute(CREATIONAL_CONTEXT,context);
// }else{
//
// }
// }
Object value = _beanMgr.getReference(bean, bean.getBeanClass(), context);
// follow the old implementation, we won't handle preDestroy of creationalContext in dependent scope.
// we cannot call release() before user get the returned value and use it.
// context.release();
return value;
}
public int hashCode() {
return Objects.hashCode(_beanMgr);
}
public boolean equals(Object o) {
return this == o || (o instanceof DelegatingVariableResolver
&& Objects.equals(_beanMgr, ((DelegatingVariableResolver) o)._beanMgr));
}
}