Clover coverage report - Code Coverage for tapestry release 4.0-beta-6
Coverage timestamp: Wed Sep 7 2005 18:41:34 EDT
file stats: LOC: 292   Methods: 10
NCLOC: 156   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
BeanProvider.java 70% 80.8% 80% 77.2%
coverage coverage
 1    // Copyright 2004, 2005 The Apache Software Foundation
 2    //
 3    // Licensed under the Apache License, Version 2.0 (the "License");
 4    // you may not use this file except in compliance with the License.
 5    // You may obtain a copy of the License at
 6    //
 7    // http://www.apache.org/licenses/LICENSE-2.0
 8    //
 9    // Unless required by applicable law or agreed to in writing, software
 10    // distributed under the License is distributed on an "AS IS" BASIS,
 11    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12    // See the License for the specific language governing permissions and
 13    // limitations under the License.
 14   
 15    package org.apache.tapestry.bean;
 16   
 17    import java.util.Collection;
 18    import java.util.Collections;
 19    import java.util.HashMap;
 20    import java.util.HashSet;
 21    import java.util.Iterator;
 22    import java.util.List;
 23    import java.util.Map;
 24    import java.util.Set;
 25   
 26    import org.apache.commons.logging.Log;
 27    import org.apache.commons.logging.LogFactory;
 28    import org.apache.hivemind.ApplicationRuntimeException;
 29    import org.apache.hivemind.ClassResolver;
 30    import org.apache.tapestry.IBeanProvider;
 31    import org.apache.tapestry.IComponent;
 32    import org.apache.tapestry.IEngine;
 33    import org.apache.tapestry.event.PageDetachListener;
 34    import org.apache.tapestry.event.PageEndRenderListener;
 35    import org.apache.tapestry.event.PageEvent;
 36    import org.apache.tapestry.spec.BeanLifecycle;
 37    import org.apache.tapestry.spec.IBeanSpecification;
 38    import org.apache.tapestry.spec.IComponentSpecification;
 39   
 40    /**
 41    * Basic implementation of the {@link IBeanProvider} interface.
 42    *
 43    * @author Howard Lewis Ship
 44    * @since 1.0.4
 45    */
 46   
 47    public class BeanProvider implements IBeanProvider, PageDetachListener, PageEndRenderListener
 48    {
 49    private static final Log LOG = LogFactory.getLog(BeanProvider.class);
 50   
 51    /**
 52    * Indicates whether this instance has been registered with its page as a PageDetachListener.
 53    * Registration only occurs the first time a bean with lifecycle REQUEST is instantiated.
 54    */
 55   
 56    private boolean _registeredForDetach = false;
 57   
 58    /**
 59    * Indicates whether this instance has been registered as a render listener with the page.
 60    */
 61   
 62    private boolean _registeredForRender = false;
 63   
 64    /**
 65    * The component for which beans are being created and tracked.
 66    */
 67   
 68    private IComponent _component;
 69   
 70    /**
 71    * Used for instantiating classes.
 72    */
 73   
 74    private ClassResolver _resolver;
 75   
 76    /**
 77    * Map of beans, keyed on name.
 78    */
 79   
 80    private Map _beans;
 81   
 82    /**
 83    * Set of bean names provided by this provider.
 84    *
 85    * @since 2.2
 86    */
 87   
 88    private Set _beanNames;
 89   
 90  47 public BeanProvider(IComponent component)
 91    {
 92  47 _component = component;
 93  47 IEngine engine = component.getPage().getEngine();
 94  47 _resolver = engine.getClassResolver();
 95   
 96  47 if (LOG.isDebugEnabled())
 97  0 LOG.debug("Created BeanProvider for " + component);
 98   
 99    }
 100   
 101    /** @since 1.0.6 * */
 102   
 103  42 public Collection getBeanNames()
 104    {
 105  42 if (_beanNames == null)
 106    {
 107  19 Collection c = _component.getSpecification().getBeanNames();
 108   
 109  19 if (c == null || c.isEmpty())
 110  0 _beanNames = Collections.EMPTY_SET;
 111    else
 112  19 _beanNames = Collections.unmodifiableSet(new HashSet(c));
 113    }
 114   
 115  42 return _beanNames;
 116    }
 117   
 118    /**
 119    * @since 1.0.5
 120    */
 121   
 122  3 public IComponent getComponent()
 123    {
 124  3 return _component;
 125    }
 126   
 127  170 public Object getBean(String name)
 128    {
 129  170 if (LOG.isDebugEnabled())
 130  0 LOG.debug("getBean(" + name + ")");
 131   
 132  170 Object bean = null;
 133   
 134  170 if (_beans != null)
 135  123 bean = _beans.get(name);
 136   
 137  170 if (bean != null)
 138  85 return bean;
 139   
 140  85 IBeanSpecification spec = _component.getSpecification().getBeanSpecification(name);
 141   
 142  85 if (spec == null)
 143  0 throw new ApplicationRuntimeException(BeanMessages.beanNotDefined(_component, name));
 144   
 145  85 bean = instantiateBean(name, spec);
 146   
 147  85 BeanLifecycle lifecycle = spec.getLifecycle();
 148   
 149  85 if (lifecycle == BeanLifecycle.NONE)
 150  0 return bean;
 151   
 152  85 if (_beans == null)
 153  47 _beans = new HashMap();
 154   
 155  85 _beans.put(name, bean);
 156   
 157    // The first time in a request that a REQUEST lifecycle bean is created,
 158    // register with the page to be notified at the end of the
 159    // request cycle.
 160   
 161  85 if (lifecycle == BeanLifecycle.REQUEST && !_registeredForDetach)
 162    {
 163  46 _component.getPage().addPageDetachListener(this);
 164  46 _registeredForDetach = true;
 165    }
 166   
 167  85 if (lifecycle == BeanLifecycle.RENDER && !_registeredForRender)
 168    {
 169  0 _component.getPage().addPageEndRenderListener(this);
 170  0 _registeredForRender = true;
 171    }
 172   
 173    // No need to register if a PAGE lifecycle bean; those can stick around
 174    // forever.
 175   
 176  85 return bean;
 177    }
 178   
 179  85 private Object instantiateBean(String beanName, IBeanSpecification spec)
 180    {
 181  85 String className = spec.getClassName();
 182  85 Object bean = null;
 183   
 184  85 if (LOG.isDebugEnabled())
 185  0 LOG.debug("Instantiating instance of " + className);
 186   
 187    // Do it the hard way!
 188   
 189  85 try
 190    {
 191  85 Class beanClass = _resolver.findClass(className);
 192   
 193  85 bean = beanClass.newInstance();
 194    }
 195    catch (Exception ex)
 196    {
 197  0 throw new ApplicationRuntimeException(BeanMessages.instantiationError(
 198    beanName,
 199    _component,
 200    className,
 201    ex), spec.getLocation(), ex);
 202    }
 203   
 204    // OK, have the bean, have to initialize it.
 205   
 206  85 List initializers = spec.getInitializers();
 207   
 208  85 if (initializers == null)
 209  84 return bean;
 210   
 211  1 Iterator i = initializers.iterator();
 212  1 while (i.hasNext())
 213    {
 214  3 IBeanInitializer iz = (IBeanInitializer) i.next();
 215   
 216  3 if (LOG.isDebugEnabled())
 217  0 LOG.debug("Initializing property " + iz.getPropertyName());
 218   
 219  3 iz.setBeanProperty(this, bean);
 220    }
 221   
 222  1 return bean;
 223    }
 224   
 225    /**
 226    * Removes all beans with the REQUEST lifecycle. Beans with the PAGE lifecycle stick around, and
 227    * beans with no lifecycle were never stored in the first place.
 228    */
 229   
 230  87 public void pageDetached(PageEvent event)
 231    {
 232  87 removeBeans(BeanLifecycle.REQUEST);
 233    }
 234   
 235    /**
 236    * Removes any beans with the specified lifecycle.
 237    *
 238    * @since 2.2
 239    */
 240   
 241  87 private void removeBeans(BeanLifecycle lifecycle)
 242    {
 243  87 if (_beans == null)
 244  0 return;
 245   
 246  87 IComponentSpecification spec = null;
 247   
 248  87 Iterator i = _beans.entrySet().iterator();
 249  87 while (i.hasNext())
 250    {
 251  83 Map.Entry e = (Map.Entry) i.next();
 252  83 String name = (String) e.getKey();
 253   
 254  83 if (spec == null)
 255  83 spec = _component.getSpecification();
 256   
 257  83 IBeanSpecification s = spec.getBeanSpecification(name);
 258   
 259  83 if (s.getLifecycle() == lifecycle)
 260    {
 261  83 Object bean = e.getValue();
 262   
 263  83 if (LOG.isDebugEnabled())
 264  0 LOG.debug("Removing " + lifecycle.getName() + " bean " + name + ": " + bean);
 265   
 266  83 i.remove();
 267    }
 268    }
 269    }
 270   
 271    /** @since 1.0.8 * */
 272   
 273  0 public ClassResolver getClassResolver()
 274    {
 275  0 return _resolver;
 276    }
 277   
 278    /** @since 2.2 * */
 279   
 280  0 public void pageEndRender(PageEvent event)
 281    {
 282  0 removeBeans(BeanLifecycle.RENDER);
 283    }
 284   
 285    /** @since 2.2 * */
 286   
 287  42 public boolean canProvideBean(String name)
 288    {
 289  42 return getBeanNames().contains(name);
 290    }
 291   
 292    }