Coverage Report - org.apache.myfaces.flow.cdi.FlowScopedContextImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
FlowScopedContextImpl
0%
0/125
0%
0/70
4.643
 
 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.flow.cdi;
 20  
 
 21  
 import java.lang.annotation.Annotation;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import javax.enterprise.context.ContextNotActiveException;
 25  
 import javax.enterprise.context.spi.Context;
 26  
 import javax.enterprise.context.spi.Contextual;
 27  
 import javax.enterprise.context.spi.CreationalContext;
 28  
 import javax.enterprise.inject.Typed;
 29  
 import javax.enterprise.inject.spi.Bean;
 30  
 import javax.enterprise.inject.spi.BeanManager;
 31  
 import javax.enterprise.inject.spi.PassivationCapable;
 32  
 import javax.faces.context.FacesContext;
 33  
 import javax.faces.flow.Flow;
 34  
 import javax.faces.flow.FlowHandler;
 35  
 import javax.faces.flow.FlowScoped;
 36  
 import org.apache.myfaces.cdi.util.BeanProvider;
 37  
 import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
 38  
 import org.apache.myfaces.cdi.util.ContextualStorage;
 39  
 import org.apache.myfaces.flow.FlowReference;
 40  
 import org.apache.myfaces.flow.util.FlowUtils;
 41  
 
 42  
 /**
 43  
  * Minimal implementation of FlowScope.
 44  
  * 
 45  
  * @TODO: We need something better for this part. The problem is the beans
 46  
  * are just put under the session map using the old know SubKeyMap hack used
 47  
  * in Flash object, but CDI implementations like OWB solves the passivation
 48  
  * problem better. The ideal is provide a myfaces specific SPI interface, to
 49  
  * allow provide custom implementation of this detail.
 50  
  * 
 51  
  * @TODO: FlowHandler.transition() method should call this object when the
 52  
  * user enter or exit a flow.
 53  
  *
 54  
  * @author Leonardo Uribe
 55  
  */
 56  
 @Typed()
 57  
 public class FlowScopedContextImpl implements Context
 58  
 {
 59  
     /**
 60  
      * Whether the Context is for a passivating scope.
 61  
      */
 62  
     private final boolean passivatingScope;
 63  
 
 64  
     /**
 65  
      * needed for serialisation and passivationId
 66  
      */
 67  
     private BeanManager beanManager;
 68  
     
 69  
     private Map<Class, FlowReference> flowBeanReferences;
 70  
 
 71  
     //private FlowScopeBeanHolder flowScopeBeanHolder;
 72  
     
 73  
     public FlowScopedContextImpl(BeanManager beanManager, 
 74  
         Map<Class, FlowReference> flowBeanReferences)
 75  0
     {
 76  0
         this.beanManager = beanManager;
 77  0
         this.flowBeanReferences = flowBeanReferences;
 78  0
         passivatingScope = beanManager.isPassivatingScope(getScope());
 79  0
     }
 80  
     
 81  
     /*
 82  
     public void initFlowContext(FlowScopeBeanHolder flowScopeBeanHolder)
 83  
     {
 84  
         this.flowScopeBeanHolder = flowScopeBeanHolder;
 85  
     }*/
 86  
     
 87  
     protected FlowScopeBeanHolder getFlowScopeBeanHolder()
 88  
     {
 89  0
         return getFlowScopeBeanHolder(FacesContext.getCurrentInstance());
 90  
     }
 91  
     
 92  
     protected FlowScopeBeanHolder getFlowScopeBeanHolder(FacesContext facesContext)
 93  
     {
 94  0
         FlowScopeBeanHolder flowScopeBeanHolder = (FlowScopeBeanHolder) 
 95  
             facesContext.getExternalContext().getApplicationMap().get(
 96  
                 "oam.flow.FlowScopeBeanHolder");
 97  0
         if (flowScopeBeanHolder == null)
 98  
         {
 99  0
             flowScopeBeanHolder = BeanProvider.getContextualReference(
 100  
                 beanManager, FlowScopeBeanHolder.class, false);
 101  0
             facesContext.getExternalContext().getApplicationMap().put(
 102  
                 "oam.flow.FlowScopeBeanHolder", flowScopeBeanHolder);
 103  
         }
 104  0
         return flowScopeBeanHolder;
 105  
     }
 106  
     
 107  
     public String getCurrentClientWindowFlowId(FacesContext facesContext)
 108  
     {
 109  0
         String flowMapKey = null;
 110  0
         FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
 111  0
         Flow flow = flowHandler.getCurrentFlow(facesContext);
 112  0
         if (flow != null)
 113  
         {
 114  0
             flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
 115  
         }
 116  0
         return flowMapKey;
 117  
     }
 118  
 
 119  
     /**
 120  
      * An implementation has to return the underlying storage which
 121  
      * contains the items held in the Context.
 122  
      * @param createIfNotExist whether a ContextualStorage shall get created if it doesn't yet exist.
 123  
      * @return the underlying storage
 124  
      */
 125  
     protected ContextualStorage getContextualStorage(boolean createIfNotExist, String clientWindowFlowId)
 126  
     {
 127  
         //FacesContext facesContext = FacesContext.getCurrentInstance();
 128  
         //String clientWindowFlowId = getCurrentClientWindowFlowId(facesContext);
 129  0
         if (clientWindowFlowId == null)
 130  
         {
 131  0
             throw new ContextNotActiveException("FlowScopedContextImpl: no current active flow");
 132  
         }
 133  
 
 134  0
         if (createIfNotExist)
 135  
         {
 136  0
             return getFlowScopeBeanHolder().getContextualStorage(beanManager, clientWindowFlowId);
 137  
         }
 138  
         else
 139  
         {
 140  0
             return getFlowScopeBeanHolder().getContextualStorageNoCreate(beanManager, clientWindowFlowId);
 141  
         }
 142  
     }
 143  
 
 144  
     public Class<? extends Annotation> getScope()
 145  
     {
 146  0
         return FlowScoped.class;
 147  
     }
 148  
 
 149  
     public boolean isActive()
 150  
     {
 151  0
         return isActive(FacesContext.getCurrentInstance());
 152  
     }
 153  
 
 154  
     public boolean isActive(FacesContext facesContext)
 155  
     {
 156  0
         if (facesContext == null)
 157  
         {
 158  0
             return false;
 159  
         }
 160  0
         Flow flow = facesContext.getApplication().
 161  
             getFlowHandler().getCurrentFlow(facesContext);
 162  
         
 163  0
         return flow != null;
 164  
     }
 165  
 
 166  
     /**
 167  
      * @return whether the served scope is a passivating scope
 168  
      */
 169  
     public boolean isPassivatingScope()
 170  
     {
 171  0
         return passivatingScope;
 172  
     }
 173  
 
 174  
     @Override
 175  
     public <T> T get(Contextual<T> bean)
 176  
     {
 177  0
         FacesContext facesContext = FacesContext.getCurrentInstance();
 178  
 
 179  0
         checkActive(facesContext);
 180  
 
 181  
         
 182  0
         FlowReference reference = flowBeanReferences.get(((Bean)bean).getBeanClass());
 183  0
         if (reference != null)
 184  
         {
 185  0
             String flowMapKey = FlowUtils.getFlowMapKey(facesContext, reference);
 186  0
             if (flowMapKey != null)
 187  
             {
 188  0
                 ContextualStorage storage = getContextualStorage(false, flowMapKey);
 189  0
                 if (storage != null)
 190  
                 {
 191  0
                     Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 192  0
                     ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 193  
 
 194  0
                     if (contextualInstanceInfo != null)
 195  
                     {
 196  0
                         return (T) contextualInstanceInfo.getContextualInstance();
 197  
                     }
 198  
                 }
 199  0
             }
 200  
             else
 201  
             {
 202  0
                 throw new IllegalStateException("Flow "+ reference.getId()+
 203  
                     " cannot be found when resolving bean " +bean.toString());
 204  
             }
 205  
         }
 206  
         
 207  0
         List<String> activeFlowMapKeys = getFlowScopeBeanHolder().getActiveFlowMapKeys(facesContext);
 208  0
         for (String flowMapKey : activeFlowMapKeys)
 209  
         {
 210  0
             ContextualStorage storage = getContextualStorage(false, flowMapKey);
 211  0
             if (storage == null)
 212  
             {
 213  
                 //return null;
 214  0
                 continue;
 215  
             }
 216  
 
 217  0
             Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 218  0
             ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 219  0
             if (contextualInstanceInfo == null)
 220  
             {
 221  
                 //return null;
 222  0
                 continue;
 223  
             }
 224  
 
 225  0
             return (T) contextualInstanceInfo.getContextualInstance();
 226  
         }
 227  0
         return null;
 228  
     }
 229  
 
 230  
     @Override
 231  
     public <T> T get(Contextual<T> bean, CreationalContext<T> creationalContext)
 232  
     {
 233  0
         FacesContext facesContext = FacesContext.getCurrentInstance();
 234  
         
 235  0
         checkActive(facesContext);
 236  
 
 237  0
         if (passivatingScope && !(bean instanceof PassivationCapable))
 238  
         {
 239  0
             throw new IllegalStateException(bean.toString() +
 240  
                     " doesn't implement " + PassivationCapable.class.getName());
 241  
         }
 242  
         
 243  0
         FlowReference reference = flowBeanReferences.get(((Bean)bean).getBeanClass());
 244  0
         if (reference != null)
 245  
         {
 246  0
             String flowMapKey = FlowUtils.getFlowMapKey(facesContext, reference);
 247  0
             if (flowMapKey != null)
 248  
             {
 249  0
                 ContextualStorage storage = getContextualStorage(false, flowMapKey);
 250  0
                 if (storage != null)
 251  
                 {
 252  0
                     Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 253  0
                     ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 254  
 
 255  0
                     if (contextualInstanceInfo != null)
 256  
                     {
 257  0
                         return (T) contextualInstanceInfo.getContextualInstance();
 258  
                     }
 259  
                 }
 260  0
             }
 261  
             else
 262  
             {
 263  0
                 throw new IllegalStateException("Flow "+ reference.getId()+
 264  
                     " cannot be found when resolving bean " + bean.toString());
 265  
             }
 266  
             
 267  0
             FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
 268  
             // Since it is possible to have only the flow id without documentId, the best
 269  
             // is first get the flow using flowHandler.getFlow and then check if the flow is
 270  
             // active or not, but using the documentId and id of the retrieved flow.
 271  0
             Flow flow = flowHandler.getFlow(facesContext, 
 272  
                 reference.getDocumentId() == null ? "" : reference.getDocumentId(), reference.getId());
 273  0
             if (flow == null)
 274  
             {
 275  0
                 throw new IllegalStateException(bean.toString() + "cannot be created because flow "+ reference.getId()+
 276  
                     " is not registered");
 277  
             }
 278  0
             if (!flowHandler.isActive(facesContext, flow.getDefiningDocumentId(), flow.getId())) 
 279  
             {
 280  0
                 throw new IllegalStateException(bean.toString() + "cannot be created if flow "+ reference.getId()+
 281  
                     " is not active");
 282  
             }
 283  
             
 284  0
             ContextualStorage storage = getContextualStorage(true, flowMapKey);
 285  0
             Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 286  0
             ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 287  
 
 288  0
             if (contextualInstanceInfo != null)
 289  
             {
 290  
                 @SuppressWarnings("unchecked")
 291  0
                 final T instance =  (T) contextualInstanceInfo.getContextualInstance();
 292  
 
 293  0
                 if (instance != null)
 294  
                 {
 295  0
                     return instance;
 296  
                 }
 297  
             }
 298  
 
 299  0
             return storage.createContextualInstance(bean, creationalContext);
 300  
         }
 301  
 
 302  0
         List<String> activeFlowMapKeys = getFlowScopeBeanHolder().getActiveFlowMapKeys(facesContext);
 303  0
         for (String flowMapKey : activeFlowMapKeys)
 304  
         {
 305  0
             ContextualStorage storage = getContextualStorage(false, flowMapKey);
 306  
 
 307  0
             Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 308  0
             ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 309  
 
 310  0
             if (contextualInstanceInfo != null)
 311  
             {
 312  
                 @SuppressWarnings("unchecked")
 313  0
                 final T instance =  (T) contextualInstanceInfo.getContextualInstance();
 314  
 
 315  0
                 if (instance != null)
 316  
                 {
 317  0
                     return instance;
 318  
                 }
 319  
             }
 320  
 
 321  0
         }
 322  
         
 323  0
         ContextualStorage storage = getContextualStorage(true, getCurrentClientWindowFlowId(facesContext));
 324  0
         Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 325  0
         ContextualInstanceInfo<?> contextualInstanceInfo = contextMap.get(storage.getBeanKey(bean));
 326  
 
 327  0
         if (contextualInstanceInfo != null)
 328  
         {
 329  
             @SuppressWarnings("unchecked")
 330  0
             final T instance =  (T) contextualInstanceInfo.getContextualInstance();
 331  
 
 332  0
             if (instance != null)
 333  
             {
 334  0
                 return instance;
 335  
             }
 336  
         }
 337  
             
 338  0
         return storage.createContextualInstance(bean, creationalContext);
 339  
     }
 340  
 
 341  
     /**
 342  
      * Destroy the Contextual Instance of the given Bean.
 343  
      * @param bean dictates which bean shall get cleaned up
 344  
      * @return <code>true</code> if the bean was destroyed, <code>false</code> if there was no such bean.
 345  
      */
 346  
     public boolean destroy(Contextual bean)
 347  
     {
 348  0
         FacesContext facesContext = FacesContext.getCurrentInstance();
 349  0
         List<String> activeFlowMapKeys = getFlowScopeBeanHolder().getActiveFlowMapKeys(facesContext);
 350  0
         for (String flowMapKey : activeFlowMapKeys)
 351  
         {
 352  0
             ContextualStorage storage = getContextualStorage(false, flowMapKey);
 353  0
             if (storage == null)
 354  
             {
 355  
                 //return false;
 356  0
                 continue;
 357  
             }
 358  0
             ContextualInstanceInfo<?> contextualInstanceInfo = storage.getStorage().get(storage.getBeanKey(bean));
 359  
 
 360  0
             if (contextualInstanceInfo == null)
 361  
             {
 362  
                 //return false;
 363  0
                 continue;
 364  
             }
 365  
 
 366  0
             bean.destroy(contextualInstanceInfo.getContextualInstance(), contextualInstanceInfo.getCreationalContext());
 367  0
             return true;
 368  
         }
 369  0
         return false;
 370  
     }
 371  
 
 372  
     /**
 373  
      * destroys all the Contextual Instances in the Storage returned by
 374  
      * {@link #getContextualStorage(boolean)}.
 375  
      */
 376  
     /*
 377  
     public void destroyAllActive()
 378  
     {
 379  
         ContextualStorage storage = getContextualStorage(false);
 380  
         if (storage == null)
 381  
         {
 382  
             return;
 383  
         }
 384  
 
 385  
         destroyAllActive(storage);
 386  
     }*/
 387  
 
 388  
     /**
 389  
      * Destroys all the Contextual Instances in the specified ContextualStorage.
 390  
      * This is a static method to allow various holder objects to cleanup
 391  
      * properly in &#064;PreDestroy.
 392  
      */
 393  
     public static void destroyAllActive(ContextualStorage storage)
 394  
     {
 395  0
         Map<Object, ContextualInstanceInfo<?>> contextMap = storage.getStorage();
 396  0
         for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : contextMap.entrySet())
 397  
         {
 398  0
             if (!FlowScopeBeanHolder.CURRENT_FLOW_SCOPE_MAP.equals(entry.getKey()))
 399  
             {
 400  0
                 Contextual bean = storage.getBean(entry.getKey());
 401  
 
 402  0
                 ContextualInstanceInfo<?> contextualInstanceInfo = entry.getValue();
 403  0
                 bean.destroy(contextualInstanceInfo.getContextualInstance(), 
 404  
                     contextualInstanceInfo.getCreationalContext());
 405  
             }
 406  0
         }
 407  0
     }
 408  
 
 409  
     /**
 410  
      * Make sure that the Context is really active.
 411  
      * @throws ContextNotActiveException if there is no active
 412  
      *         Context for the current Thread.
 413  
      */
 414  
     protected void checkActive(FacesContext facesContext)
 415  
     {
 416  0
         if (!isActive(facesContext))
 417  
         {
 418  0
             throw new ContextNotActiveException("CDI context with scope annotation @"
 419  
                 + getScope().getName() + " is not active with respect to the current thread");
 420  
         }
 421  0
     }
 422  
 
 423  
 }