Coverage Report - org.apache.myfaces.el.unified.resolver.ManagedBeanResolver
 
Classes in this File Line Coverage Branch Coverage Complexity
ManagedBeanResolver
0%
0/137
0%
0/82
4.222
ManagedBeanResolver$1
0%
0/3
N/A
4.222
ManagedBeanResolver$2
0%
0/3
N/A
4.222
ManagedBeanResolver$3
0%
0/3
N/A
4.222
ManagedBeanResolver$4
0%
0/2
N/A
4.222
ManagedBeanResolver$5
0%
0/3
N/A
4.222
ManagedBeanResolver$Scope
N/A
N/A
4.222
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.el.unified.resolver;
 20  
 
 21  
 import org.apache.myfaces.config.ManagedBeanBuilder;
 22  
 import org.apache.myfaces.config.RuntimeConfig;
 23  
 import org.apache.myfaces.config.element.ManagedBean;
 24  
 import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
 25  
 
 26  
 import javax.el.ELContext;
 27  
 import javax.el.ELException;
 28  
 import javax.el.ELResolver;
 29  
 import javax.el.PropertyNotFoundException;
 30  
 import javax.el.PropertyNotWritableException;
 31  
 import javax.faces.FacesException;
 32  
 import javax.faces.application.ProjectStage;
 33  
 import javax.faces.component.UIViewRoot;
 34  
 import javax.faces.context.ExternalContext;
 35  
 import javax.faces.context.FacesContext;
 36  
 import java.beans.FeatureDescriptor;
 37  
 import java.util.ArrayList;
 38  
 import java.util.HashMap;
 39  
 import java.util.Iterator;
 40  
 import java.util.List;
 41  
 import java.util.Map;
 42  
 import java.util.logging.Level;
 43  
 import java.util.logging.Logger;
 44  
 
 45  
 /**
 46  
  * See JSF 1.2 spec section 5.6.1.2
 47  
  * 
 48  
  * @author Stan Silvert
 49  
  */
 50  
 public class ManagedBeanResolver extends ELResolver
 51  
 {
 52  0
     private static final Logger log = Logger.getLogger(ManagedBeanResolver.class.getName());
 53  
     private static final String BEANS_UNDER_CONSTRUCTION =
 54  
             "org.apache.myfaces.el.unified.resolver.managedbean.beansUnderConstruction";
 55  
 
 56  
     private static final String CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION =
 57  
             "org.apache.myfaces.el.unified.resolver.managedbean.customScopeCyclicReferenceDetection";
 58  
 
 59  
     // adapted from Manfred's JSF 1.1 VariableResolverImpl
 60  0
     protected static final Map<String, Scope> STANDARD_SCOPES = new HashMap<String, Scope>(16);
 61  
 
 62  
     static
 63  
     {
 64  0
         STANDARD_SCOPES.put("request", new Scope()
 65  0
         {
 66  
             public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
 67  
             {
 68  0
                 extContext.getRequestMap().put(name, obj);
 69  0
             }
 70  
         });
 71  
 
 72  0
         STANDARD_SCOPES.put("session", new Scope()
 73  0
         {
 74  
             public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
 75  
             {
 76  0
                 extContext.getSessionMap().put(name, obj);
 77  0
             }
 78  
         });
 79  
 
 80  0
         STANDARD_SCOPES.put("application", new Scope()
 81  0
         {
 82  
             public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
 83  
             {
 84  0
                 extContext.getApplicationMap().put(name, obj);
 85  0
             }
 86  
         });
 87  
 
 88  0
         STANDARD_SCOPES.put("none", new Scope()
 89  0
         {
 90  
             public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
 91  
             {
 92  
                 // do nothing
 93  0
             }
 94  
         });
 95  
         
 96  
         // jsf 2.0 view scope
 97  0
         STANDARD_SCOPES.put("view", new Scope()
 98  0
         {
 99  
             public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj)
 100  
             {
 101  0
                 facesContext.getViewRoot().getViewMap().put(name, obj);
 102  0
             }
 103  
         });
 104  0
     }
 105  
 
 106  
     /**
 107  
      * Stores all scopes defined for this instance of <code>VariableResolver</code>
 108  
      * <p>
 109  
      * Can store instances of <code>Scope</code> which have the ability to dynamically resolve against ExternalContext
 110  
      * for put operations.
 111  
      * </p>
 112  
      * <p>
 113  
      * WARNING: this implementation is not serialized as it is thread safe because it does not update/add to _scopes
 114  
      * after object initialization. If you need to add your own scopes, either extend and add more in an initialization
 115  
      * block, or add proper sychronization
 116  
      * </p>
 117  
      */
 118  0
     protected final Map<String, Scope> _scopes = new HashMap<String, Scope>(16);
 119  
     {
 120  0
         _scopes.putAll(STANDARD_SCOPES);
 121  
     }
 122  
 
 123  
     /**
 124  
      * RuntimeConfig is instantiated once per servlet and never changes--we can safely cache it
 125  
      */
 126  
     private RuntimeConfig runtimeConfig;
 127  
 
 128  0
     private ManagedBeanBuilder beanBuilder = new ManagedBeanBuilder();
 129  
 
 130  
     /** Creates a new instance of ManagedBeanResolver */
 131  
     public ManagedBeanResolver()
 132  0
     {
 133  0
     }
 134  
 
 135  
     @Override
 136  
     public void setValue(final ELContext context, final Object base, final Object property, final Object value)
 137  
         throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException
 138  
     {
 139  
 
 140  0
         if ((base == null) && (property == null))
 141  
         {
 142  0
             throw new PropertyNotFoundException();
 143  
         }
 144  
 
 145  0
     }
 146  
 
 147  
     @Override
 148  
     public boolean isReadOnly(final ELContext context, final Object base, final Object property)
 149  
         throws NullPointerException, PropertyNotFoundException, ELException
 150  
     {
 151  
 
 152  0
         if ((base == null) && (property == null))
 153  
         {
 154  0
             throw new PropertyNotFoundException();
 155  
         }
 156  
 
 157  0
         return false;
 158  
     }
 159  
 
 160  
     @Override
 161  
     @SuppressWarnings("unchecked")
 162  
     public Object getValue(final ELContext context, final Object base, final Object property)
 163  
         throws NullPointerException, PropertyNotFoundException, ELException
 164  
     {
 165  
         // we only resolve ManagedBean instances, not properties of those  
 166  0
         if (base != null)
 167  
         {
 168  0
             return null;
 169  
         }
 170  
 
 171  0
         if (property == null)
 172  
         {
 173  0
             throw new PropertyNotFoundException();
 174  
         }
 175  
 
 176  0
         final FacesContext facesContext = facesContext(context);
 177  0
         if (facesContext == null)
 178  
         {
 179  0
             return null;
 180  
         }
 181  0
         final ExternalContext extContext = facesContext.getExternalContext();
 182  0
         if (extContext == null)
 183  
         {
 184  0
             return null;
 185  
         }
 186  
 
 187  0
         final boolean startup = (extContext instanceof StartupServletExternalContextImpl);
 188  
         
 189  
         // request scope (not available at startup)
 190  0
         if (!startup)
 191  
         {
 192  0
             if (extContext.getRequestMap().containsKey(property))
 193  
             {
 194  0
                 return null;
 195  
             }
 196  
         }
 197  
 
 198  
         // view scope
 199  0
         UIViewRoot root = facesContext.getViewRoot();
 200  0
         if (root != null)
 201  
         {
 202  0
             Map<String, Object> viewMap = root.getViewMap(false);
 203  0
             if (viewMap != null && viewMap.containsKey(property))
 204  
             {
 205  0
                 return null;
 206  
             }
 207  
         }
 208  
 
 209  
         // session scope (not available at startup)
 210  0
         if (!startup)
 211  
         {
 212  0
             if (extContext.getSessionMap().containsKey(property))
 213  
             {
 214  0
                 return null;
 215  
             }
 216  
         }
 217  
 
 218  
         // application scope
 219  0
         if (extContext.getApplicationMap().containsKey(property))
 220  
         {
 221  0
             return null;
 222  
         }
 223  
 
 224  
         // not found in standard scopes - get ManagedBean metadata object
 225  
         // In order to get the metadata object, we need property to be the managed bean name (--> String)
 226  0
         if (!(property instanceof String))
 227  
         {
 228  0
             return null;
 229  
         }
 230  0
         final String strProperty = (String) property;
 231  
 
 232  0
         final ManagedBean managedBean = runtimeConfig(context).getManagedBean(strProperty);
 233  0
         Object beanInstance = null;
 234  0
         if (managedBean != null)
 235  
         {
 236  0
             context.setPropertyResolved(true);
 237  
             
 238  
             // managed-bean-scope could be a ValueExpression pointing to a Map (since 2.0) --> custom scope
 239  0
             if (managedBean.isManagedBeanScopeValueExpression())
 240  
             {
 241  
                 // check for cyclic references in custom scopes, if we are not in Production stage
 242  0
                 boolean checkCyclicReferences = !facesContext.isProjectStage(ProjectStage.Production);
 243  0
                 List<String> cyclicReferences = null;
 244  
                 
 245  0
                 if (checkCyclicReferences)
 246  
                 {
 247  0
                     final Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
 248  0
                     final String managedBeanName = managedBean.getManagedBeanName();
 249  
                     
 250  0
                     cyclicReferences = (List<String>) requestMap.get(CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION);
 251  0
                     if (cyclicReferences == null)
 252  
                     {
 253  0
                         cyclicReferences = new ArrayList<String>();
 254  0
                         requestMap.put(CUSTOM_SCOPE_CYCLIC_REFERENCE_DETECTION, cyclicReferences);
 255  
                     }
 256  0
                     else if (cyclicReferences.contains(managedBeanName))
 257  
                     {
 258  0
                         throw new ELException("Detected cyclic reference to managedBean " + managedBeanName);
 259  
                     }
 260  
 
 261  0
                     cyclicReferences.add(managedBeanName);
 262  
                 }
 263  
                 try
 264  
                 {
 265  0
                     Object customScope = managedBean.getManagedBeanScopeValueExpression(facesContext)
 266  
                                                 .getValue(facesContext.getELContext());
 267  0
                     if (customScope instanceof Map)
 268  
                     {
 269  0
                         beanInstance = ((Map) customScope).get(managedBean.getManagedBeanName());
 270  
                     }
 271  0
                     else if (customScope != null)
 272  
                     {
 273  0
                         throw new FacesException("The expression '" + managedBean.getManagedBeanScope() + 
 274  
                                 "' does not evaluate to java.util.Map. It evaluates to '" + customScope + 
 275  
                                 "' of type " + customScope.getClass().getName());
 276  
                     }
 277  
                     else
 278  
                     {
 279  0
                         log.warning("Custom scope '" + managedBean.getManagedBeanScope() +
 280  
                                 "' evaluated to null. Unable to determine if managed bean '" +
 281  
                                 managedBean.getManagedBeanName() + "' exists.");
 282  
                     }
 283  
                 }
 284  
                 finally
 285  
                 {
 286  0
                     if (checkCyclicReferences)
 287  
                     {
 288  0
                         cyclicReferences.remove(managedBean.getManagedBeanName());
 289  
                     }
 290  
                 }
 291  
             }
 292  
 
 293  
             // not found in any scope - create instance!
 294  0
             if (beanInstance == null)
 295  
             {
 296  0
                 beanInstance = createManagedBean(managedBean, facesContext);
 297  
             }
 298  
         }
 299  
 
 300  0
         return beanInstance;
 301  
     }
 302  
 
 303  
     // Create a managed bean. If the scope of the bean is "none" then
 304  
     // return it right away. Otherwise store the bean in the appropriate
 305  
     // scope and return null.
 306  
     //
 307  
     // adapted from Manfred's JSF 1.1 VariableResolverImpl
 308  
     @SuppressWarnings("unchecked")
 309  
     private Object createManagedBean(final ManagedBean managedBean, final FacesContext facesContext) throws ELException
 310  
     {
 311  
 
 312  0
         final ExternalContext extContext = facesContext.getExternalContext();
 313  0
         final Map<Object, Object> facesContextMap = facesContext.getAttributes();
 314  0
         final String managedBeanName = managedBean.getManagedBeanName();
 315  
 
 316  
         // check for cyclic references
 317  0
         List<String> beansUnderConstruction = (List<String>) facesContextMap.get(BEANS_UNDER_CONSTRUCTION);
 318  0
         if (beansUnderConstruction == null)
 319  
         {
 320  0
             beansUnderConstruction = new ArrayList<String>();
 321  0
             facesContextMap.put(BEANS_UNDER_CONSTRUCTION, beansUnderConstruction);
 322  
         }
 323  0
         else if (beansUnderConstruction.contains(managedBeanName))
 324  
         {
 325  0
             throw new ELException("Detected cyclic reference to managedBean " + managedBeanName);
 326  
         }
 327  
 
 328  0
         beansUnderConstruction.add(managedBeanName);
 329  
 
 330  0
         Object obj = null;
 331  
         try
 332  
         {
 333  0
             obj = beanBuilder.buildManagedBean(facesContext, managedBean);
 334  
         }
 335  
         finally
 336  
         {
 337  0
             beansUnderConstruction.remove(managedBeanName);
 338  0
         }
 339  
 
 340  0
         putInScope(managedBean, facesContext, extContext, obj);
 341  
 
 342  0
         return obj;
 343  
     }
 344  
 
 345  
     @SuppressWarnings("unchecked")
 346  
     private void putInScope(final ManagedBean managedBean, final FacesContext facesContext,
 347  
             final ExternalContext extContext, final Object obj)
 348  
     {
 349  
 
 350  0
         final String managedBeanName = managedBean.getManagedBeanName();
 351  
 
 352  0
         if (obj == null)
 353  
         {
 354  0
             if (log.isLoggable(Level.FINE))
 355  
             {
 356  0
                 log.fine("Variable '" + managedBeanName + "' could not be resolved.");
 357  
             }
 358  
         }
 359  
         else
 360  
         {
 361  0
             final String scopeKey = managedBean.getManagedBeanScope();
 362  
 
 363  
             // find the scope handler object
 364  0
             final Scope scope = _scopes.get(scopeKey);
 365  0
             if (scope != null)
 366  
             {
 367  0
                 scope.put(facesContext, extContext, managedBeanName, obj);
 368  
             }
 369  0
             else if (managedBean.isManagedBeanScopeValueExpression())
 370  
             {
 371  
                 // managed-bean-scope could be a ValueExpression pointing to a Map (since 2.0)
 372  
                 // Optimisation: We do NOT check for cyclic references here, because when we reach this code,
 373  
                 // we have already checked for cyclic references in the custom scope
 374  0
                 Object customScope = managedBean.getManagedBeanScopeValueExpression(facesContext)
 375  
                         .getValue(facesContext.getELContext());
 376  
                 
 377  0
                 if (customScope instanceof Map)
 378  
                 {
 379  0
                     ((Map) customScope).put(managedBeanName, obj);
 380  
                 }
 381  0
                 else if (customScope != null)
 382  
                 {
 383  0
                     throw new FacesException("The expression '" + scopeKey + "' does not evaluate to " +
 384  
                             "java.util.Map. It evaluates to '" + customScope + "' of type " + 
 385  
                             customScope.getClass().getName());
 386  
                 }
 387  
                 else
 388  
                 {
 389  0
                     log.warning("Custom scope '" + scopeKey + "' evaluated to null. " +
 390  
                             "Cannot store managed bean '" + managedBeanName + "' in custom scope.");
 391  
                 }
 392  0
             }
 393  
             else
 394  
             {
 395  0
                 log.severe("Managed bean '" + managedBeanName + "' has illegal scope: " + scopeKey);
 396  
             }
 397  
         }
 398  
 
 399  0
     }
 400  
 
 401  
     // get the FacesContext from the ELContext
 402  
     private static FacesContext facesContext(final ELContext context)
 403  
     {
 404  0
         return (FacesContext)context.getContext(FacesContext.class);
 405  
     }
 406  
 
 407  
     @Override
 408  
     public Class<?> getType(final ELContext context, final Object base, final Object property)
 409  
         throws NullPointerException, PropertyNotFoundException, ELException
 410  
     {
 411  
 
 412  0
         if ((base == null) && (property == null))
 413  
         {
 414  0
             throw new PropertyNotFoundException();
 415  
         }
 416  
 
 417  0
         return null;
 418  
     }
 419  
 
 420  
     @Override
 421  
     public Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext context, final Object base)
 422  
     {
 423  
 
 424  0
         if (base != null)
 425  
         {
 426  0
             return null;
 427  
         }
 428  
 
 429  0
         final ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>();
 430  
 
 431  0
         final Map<String, ManagedBean> managedBeans = runtimeConfig(context).getManagedBeans();
 432  0
         for (Map.Entry<String, ManagedBean> managedBean : managedBeans.entrySet())
 433  
         {
 434  0
             descriptors.add(makeDescriptor(managedBean.getKey(), managedBean.getValue()));
 435  0
         }
 436  
 
 437  0
         return descriptors.iterator();
 438  
     }
 439  
 
 440  
     private static FeatureDescriptor makeDescriptor(final String beanName, final ManagedBean managedBean)
 441  
     {
 442  0
         final FeatureDescriptor fd = new FeatureDescriptor();
 443  0
         fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
 444  0
         fd.setValue(ELResolver.TYPE, managedBean.getManagedBeanClass());
 445  0
         fd.setName(beanName);
 446  0
         fd.setDisplayName(beanName);
 447  0
         fd.setShortDescription(managedBean.getDescription());
 448  0
         fd.setExpert(false);
 449  0
         fd.setHidden(false);
 450  0
         fd.setPreferred(true);
 451  0
         return fd;
 452  
     }
 453  
 
 454  
     protected RuntimeConfig runtimeConfig(final ELContext context)
 455  
     {
 456  0
         final FacesContext facesContext = facesContext(context);
 457  
 
 458  
         // application-level singleton - we can safely cache this
 459  0
         if (this.runtimeConfig == null)
 460  
         {
 461  0
             this.runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
 462  
         }
 463  
 
 464  0
         return runtimeConfig;
 465  
     }
 466  
 
 467  
     @Override
 468  
     public Class<?> getCommonPropertyType(final ELContext context, final Object base)
 469  
     {
 470  0
         if (base == null)
 471  
         {
 472  0
             return Object.class;
 473  
         }
 474  
 
 475  0
         return null;
 476  
     }
 477  
 
 478  
     interface Scope
 479  
     {
 480  
         public void put(FacesContext facesContext, ExternalContext extContext, String name, Object obj);
 481  
     }
 482  
 }