Clover coverage report - Code Coverage for tapestry release 4.0-rc-2
Coverage timestamp: Sat Dec 17 2005 09:39:46 PST
file stats: LOC: 324   Methods: 10
NCLOC: 178   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
BeanProvider.java 70% 82.1% 70% 77.3%
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.INamespace;
 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.services.ClassFinder;
 37    import org.apache.tapestry.services.Infrastructure;
 38    import org.apache.tapestry.spec.BeanLifecycle;
 39    import org.apache.tapestry.spec.IBeanSpecification;
 40    import org.apache.tapestry.spec.IComponentSpecification;
 41   
 42    /**
 43    * Basic implementation of the {@link IBeanProvider} interface.
 44    *
 45    * @author Howard Lewis Ship
 46    * @since 1.0.4
 47    */
 48   
 49    public class BeanProvider implements IBeanProvider, PageDetachListener, PageEndRenderListener
 50    {
 51    private static final Log LOG = LogFactory.getLog(BeanProvider.class);
 52   
 53    /**
 54    * Indicates whether this instance has been registered with its page as a PageDetachListener.
 55    * Registration only occurs the first time a bean with lifecycle REQUEST is instantiated.
 56    */
 57   
 58    private boolean _registeredForDetach = false;
 59   
 60    /**
 61    * Indicates whether this instance has been registered as a render listener with the page.
 62    */
 63   
 64    private boolean _registeredForRender = false;
 65   
 66    /**
 67    * The component for which beans are being created and tracked.
 68    */
 69   
 70    private final IComponent _component;
 71   
 72    /**
 73    * Used for instantiating classes.
 74    */
 75   
 76    private final ClassResolver _resolver;
 77   
 78    /**
 79    * Used for resolving partial class names.
 80    */
 81   
 82    private final ClassFinder _classFinder;
 83   
 84    private final String _packageList;
 85   
 86    /**
 87    * Map of beans, keyed on name.
 88    */
 89   
 90    private Map _beans;
 91   
 92    /**
 93    * Set of bean names provided by this provider.
 94    *
 95    * @since 2.2
 96    */
 97   
 98    private Set _beanNames;
 99   
 100  45 public BeanProvider(IComponent component)
 101    {
 102  45 _component = component;
 103   
 104  45 Infrastructure infrastructure = component.getPage().getRequestCycle().getInfrastructure();
 105   
 106  45 _resolver = infrastructure.getClassResolver();
 107   
 108  45 INamespace namespace = component.getNamespace();
 109  45 _packageList = namespace.getPropertyValue("org.apache.tapestry.bean-class-packages");
 110   
 111  45 _classFinder = infrastructure.getClassFinder();
 112    }
 113   
 114    /** @since 1.0.6 * */
 115   
 116  30 public Collection getBeanNames()
 117    {
 118  30 if (_beanNames == null)
 119    {
 120  14 Collection c = _component.getSpecification().getBeanNames();
 121   
 122  14 if (c == null || c.isEmpty())
 123  0 _beanNames = Collections.EMPTY_SET;
 124    else
 125  14 _beanNames = Collections.unmodifiableSet(new HashSet(c));
 126    }
 127   
 128  30 return _beanNames;
 129    }
 130   
 131    /**
 132    * @since 1.0.5
 133    */
 134   
 135  0 public IComponent getComponent()
 136    {
 137  0 return _component;
 138    }
 139   
 140  152 public Object getBean(String name)
 141    {
 142  152 if (LOG.isDebugEnabled())
 143  0 LOG.debug("getBean(" + name + ")");
 144   
 145  152 Object bean = null;
 146   
 147  152 if (_beans != null)
 148  110 bean = _beans.get(name);
 149   
 150  152 if (bean != null)
 151  73 return bean;
 152   
 153  79 IBeanSpecification spec = _component.getSpecification().getBeanSpecification(name);
 154   
 155  79 if (spec == null)
 156  0 throw new ApplicationRuntimeException(BeanMessages.beanNotDefined(_component, name));
 157   
 158  79 bean = instantiateBean(name, spec);
 159   
 160  79 BeanLifecycle lifecycle = spec.getLifecycle();
 161   
 162  79 if (lifecycle == BeanLifecycle.NONE)
 163  0 return bean;
 164   
 165  79 if (_beans == null)
 166  42 _beans = new HashMap();
 167   
 168  79 _beans.put(name, bean);
 169   
 170    // The first time in a request that a REQUEST lifecycle bean is created,
 171    // register with the page to be notified at the end of the
 172    // request cycle.
 173   
 174  79 if (lifecycle == BeanLifecycle.REQUEST && !_registeredForDetach)
 175    {
 176  42 _component.getPage().addPageDetachListener(this);
 177  42 _registeredForDetach = true;
 178    }
 179   
 180  79 if (lifecycle == BeanLifecycle.RENDER && !_registeredForRender)
 181    {
 182  0 _component.getPage().addPageEndRenderListener(this);
 183  0 _registeredForRender = true;
 184    }
 185   
 186    // No need to register if a PAGE lifecycle bean; those can stick around
 187    // forever.
 188   
 189  79 return bean;
 190    }
 191   
 192  82 Object instantiateBean(String beanName, IBeanSpecification spec)
 193    {
 194  82 String className = spec.getClassName();
 195  82 Object bean = null;
 196   
 197  82 if (LOG.isDebugEnabled())
 198  0 LOG.debug("Instantiating instance of " + className);
 199   
 200  82 Class beanClass = _classFinder.findClass(_packageList, className);
 201   
 202  82 if (beanClass == null)
 203  1 throw new ApplicationRuntimeException(BeanMessages.missingBeanClass(
 204    _component,
 205    beanName,
 206    className,
 207    _packageList), _component, spec.getLocation(), null);
 208   
 209    // Do it the hard way!
 210   
 211  81 try
 212    {
 213  81 bean = beanClass.newInstance();
 214    }
 215    catch (Exception ex)
 216    {
 217  1 throw new ApplicationRuntimeException(BeanMessages.instantiationError(
 218    beanName,
 219    _component,
 220    beanClass,
 221    ex), _component, spec.getLocation(), ex);
 222    }
 223   
 224    // OK, have the bean, have to initialize it.
 225   
 226  80 List initializers = spec.getInitializers();
 227   
 228  80 if (initializers == null)
 229  79 return bean;
 230   
 231  1 Iterator i = initializers.iterator();
 232  1 while (i.hasNext())
 233    {
 234  1 IBeanInitializer iz = (IBeanInitializer) i.next();
 235   
 236  1 if (LOG.isDebugEnabled())
 237  0 LOG.debug("Initializing property " + iz.getPropertyName());
 238   
 239  1 try
 240    {
 241  1 iz.setBeanProperty(this, bean);
 242    }
 243    catch (Exception ex)
 244    {
 245  1 throw new ApplicationRuntimeException(BeanMessages.initializationError(
 246    _component,
 247    beanName,
 248    iz.getPropertyName(),
 249    ex), bean, iz.getLocation(), ex);
 250   
 251    }
 252    }
 253   
 254  0 return bean;
 255    }
 256   
 257    /**
 258    * Removes all beans with the REQUEST lifecycle. Beans with the PAGE lifecycle stick around, and
 259    * beans with no lifecycle were never stored in the first place.
 260    */
 261   
 262  83 public void pageDetached(PageEvent event)
 263    {
 264  83 removeBeans(BeanLifecycle.REQUEST);
 265    }
 266   
 267    /**
 268    * Removes any beans with the specified lifecycle.
 269    *
 270    * @since 2.2
 271    */
 272   
 273  83 private void removeBeans(BeanLifecycle lifecycle)
 274    {
 275  83 if (_beans == null)
 276  0 return;
 277   
 278  83 IComponentSpecification spec = null;
 279   
 280  83 Iterator i = _beans.entrySet().iterator();
 281  83 while (i.hasNext())
 282    {
 283  79 Map.Entry e = (Map.Entry) i.next();
 284  79 String name = (String) e.getKey();
 285   
 286  79 if (spec == null)
 287  79 spec = _component.getSpecification();
 288   
 289  79 IBeanSpecification s = spec.getBeanSpecification(name);
 290   
 291  79 if (s.getLifecycle() == lifecycle)
 292    {
 293  79 Object bean = e.getValue();
 294   
 295  79 if (LOG.isDebugEnabled())
 296  0 LOG.debug("Removing " + lifecycle.getName() + " bean " + name + ": " + bean);
 297   
 298  79 i.remove();
 299    }
 300    }
 301    }
 302   
 303    /** @since 1.0.8 * */
 304   
 305  0 public ClassResolver getClassResolver()
 306    {
 307  0 return _resolver;
 308    }
 309   
 310    /** @since 2.2 * */
 311   
 312  0 public void pageEndRender(PageEvent event)
 313    {
 314  0 removeBeans(BeanLifecycle.RENDER);
 315    }
 316   
 317    /** @since 2.2 * */
 318   
 319  30 public boolean canProvideBean(String name)
 320    {
 321  30 return getBeanNames().contains(name);
 322    }
 323   
 324    }