package frostillicus.xsp.bean; import java.io.Serializable; import java.util.*; import javax.faces.context.FacesContext; import javax.faces.el.EvaluationException; import javax.faces.el.VariableResolver; import lotus.domino.NotesException; import org.openntf.domino.*; import org.openntf.domino.design.*; import org.openntf.domino.utils.Factory; import com.ibm.commons.util.StringUtil; import frostillicus.xsp.bean.ApplicationScoped; import frostillicus.xsp.bean.ManagedBean; import frostillicus.xsp.bean.RequestScoped; import frostillicus.xsp.bean.SessionScoped; import frostillicus.xsp.bean.ViewScoped; /** * @since 1.0 */ public class AnnotatedBeanResolver extends VariableResolver { private final VariableResolver delegate_; public AnnotatedBeanResolver(final VariableResolver resolver) { delegate_ = resolver; } @SuppressWarnings("unchecked") @Override public Object resolveVariable(final FacesContext facesContext, final String name) throws EvaluationException { if(name == null) { return null; } // Check the delegate first, since this adds the beans to the appropriate scope as needed if(delegate_ != null) { Object existing = delegate_.resolveVariable(facesContext, name); if(existing != null) { return existing; } } if(delegate_ != null) { try { // If the main resolver couldn't find it, check our annotated managed beans Map<String, Object> applicationScope = (Map<String, Object>)delegate_.resolveVariable(facesContext, "applicationScope"); if(!applicationScope.containsKey("$$annotatedManagedBeanMap")) { Map<String, BeanInfo> beanMap = new HashMap<String, BeanInfo>(); Database database = getDatabase(facesContext); DatabaseDesign design = database.getDesign(); for(String className : design.getJavaResourceClassNames()) { Class<?> loadedClass = Class.forName(className, true, facesContext.getContextClassLoader()); ManagedBean beanAnnotation = loadedClass.getAnnotation(ManagedBean.class); if(beanAnnotation != null) { BeanInfo info = new BeanInfo(); info.className = loadedClass.getName(); if(loadedClass.isAnnotationPresent(ApplicationScoped.class)) { info.scope = "application"; } else if(loadedClass.isAnnotationPresent(SessionScoped.class)) { info.scope = "session"; } else if(loadedClass.isAnnotationPresent(ViewScoped.class)) { info.scope = "view"; } else if(loadedClass.isAnnotationPresent(RequestScoped.class)) { info.scope = "request"; } else { info.scope = "none"; } if(!StringUtil.isEmpty(beanAnnotation.name())) { beanMap.put(beanAnnotation.name(), info); } else { beanMap.put(loadedClass.getSimpleName(), info); } } } applicationScope.put("$$annotatedManagedBeanMap", beanMap); } // Now that we know we have a built map, look for the requested name Map<String, BeanInfo> beanMap = (Map<String, BeanInfo>)applicationScope.get("$$annotatedManagedBeanMap"); if(beanMap.containsKey(name)) { BeanInfo info = beanMap.get(name); Class<?> loadedClass = Class.forName(info.className, true, facesContext.getContextClassLoader()); // Check its scope if("none".equals(info.scope)) { return loadedClass.newInstance(); } else { Map<String, Object> scope = (Map<String, Object>)delegate_.resolveVariable(facesContext, info.scope + "Scope"); if(!scope.containsKey(name)) { scope.put(name, loadedClass.newInstance()); } return scope.get(name); } } } catch(Throwable e) { e.printStackTrace(); throw new RuntimeException("Throwable encountered when looking for variable " + name, e); } } return null; } private Database getDatabase(final FacesContext facesContext) throws NotesException { lotus.domino.Database lotusDatabase = (lotus.domino.Database)delegate_.resolveVariable(facesContext, "database"); Database database; if(lotusDatabase instanceof Database) { database = (Database)lotusDatabase; } else { Session session; lotus.domino.Session lotusSession = lotusDatabase.getParent(); if(lotusSession instanceof Session) { session = (Session)lotusSession; } else { session = Factory.getWrapperFactory().fromLotus(lotusSession, Session.SCHEMA, null); } database = Factory.getWrapperFactory().fromLotus(lotusDatabase, Database.SCHEMA, session); } return database; } private static class BeanInfo implements Serializable { private static final long serialVersionUID = 1L; String className; String scope; } }