Coverage Report - org.apache.tapestry5.corelib.base.AbstractPropertyOutput
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractPropertyOutput
100%
28/28
100%
12/12
0
AbstractPropertyOutput$1
60%
3/5
N/A
0
 
 1  
 // Copyright 2007, 2008, 2009 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.tapestry5.corelib.base;
 16  
 
 17  
 import org.apache.tapestry5.Block;
 18  
 import org.apache.tapestry5.MarkupWriter;
 19  
 import org.apache.tapestry5.PropertyConduit;
 20  
 import org.apache.tapestry5.PropertyOverrides;
 21  
 import org.apache.tapestry5.annotations.Parameter;
 22  
 import org.apache.tapestry5.beaneditor.PropertyModel;
 23  
 import org.apache.tapestry5.ioc.Messages;
 24  
 import org.apache.tapestry5.ioc.annotations.Inject;
 25  
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 26  
 import org.apache.tapestry5.services.BeanBlockSource;
 27  
 import org.apache.tapestry5.services.Core;
 28  
 import org.apache.tapestry5.services.Environment;
 29  
 import org.apache.tapestry5.services.PropertyOutputContext;
 30  
 
 31  
 /**
 32  
  * Base class for components that output a property value using a {@link PropertyModel}. There's a relationship between
 33  
  * such a component and its container, as the container may provide messages in its message catalog needed by the {@link
 34  
  * Block}s that render the values. In addition, the component may be passed Block parameters that are output overrides
 35  
  * for specified properties.
 36  
  * <p/>
 37  
  * Subclasses will implement a <code>beginRender()</code> method that invokes {@link #renderPropertyValue(MarkupWriter,
 38  
  * String)}.
 39  
  *
 40  
  * @see BeanBlockSource
 41  
  */
 42  355
 public abstract class AbstractPropertyOutput
 43  
 {
 44  
     /**
 45  
      * Model for property displayed by the cell.
 46  
      */
 47  
     @Parameter(required = true, allowNull = false)
 48  
     private PropertyModel model;
 49  
 
 50  
     /**
 51  
      * Used to search for block parameter overrides (this is normally the enclosing Grid component's resources).
 52  
      */
 53  
     @Parameter(required = true, allowNull = false)
 54  
     private PropertyOverrides overrides;
 55  
 
 56  
     /**
 57  
      * Identifies the object being rendered. The component will extract a property from the object and render its value
 58  
      * (or delegate to a {@link org.apache.tapestry5.Block} that will do so).
 59  
      */
 60  
     @Parameter(required = true)
 61  
     private Object object;
 62  
 
 63  
     /**
 64  
      * Source for property display blocks. This defaults to the default implementation of {@link
 65  
      * org.apache.tapestry5.services.BeanBlockSource}.
 66  
      */
 67  
     @Parameter(required = true, allowNull = false)
 68  
     private BeanBlockSource beanBlockSource;
 69  
 
 70  
     @Inject
 71  
     @Core
 72  
     private BeanBlockSource defaultBeanBlockSource;
 73  
 
 74  
     @Inject
 75  
     private Environment environment;
 76  
 
 77  
     private boolean mustPopEnvironment;
 78  
 
 79  
     BeanBlockSource defaultBeanBlockSource()
 80  
     {
 81  61
         return defaultBeanBlockSource;
 82  
     }
 83  
 
 84  
     protected PropertyModel getPropertyModel()
 85  
     {
 86  9788
         return model;
 87  
     }
 88  
 
 89  
     /**
 90  
      * Invoked from subclasses to do the rendering. The subclass controls the naming convention for locating an
 91  
      * overriding Block parameter (it is the name of the property possibly suffixed with a value).
 92  
      */
 93  
     protected Object renderPropertyValue(MarkupWriter writer, String overrideBlockId)
 94  
     {
 95  9788
         Block override = overrides.getOverrideBlock(overrideBlockId);
 96  
 
 97  9788
         if (override != null) return override;
 98  
 
 99  7380
         String datatype = model.getDataType();
 100  
 
 101  7380
         if (beanBlockSource.hasDisplayBlock(datatype))
 102  
         {
 103  310
             PropertyOutputContext context = new PropertyOutputContext()
 104  
             {
 105  
                 public Messages getMessages()
 106  
                 {
 107  292
                     return overrides.getOverrideMessages();
 108  
                 }
 109  
 
 110  
                 public Object getPropertyValue()
 111  
                 {
 112  310
                     return readPropertyForObject();
 113  
                 }
 114  
 
 115  
                 public String getPropertyId()
 116  
                 {
 117  0
                     return model.getId();
 118  
                 }
 119  
 
 120  310
                 public String getPropertyName()
 121  
                 {
 122  0
                     return model.getPropertyName();
 123  
                 }
 124  
             };
 125  
 
 126  310
             environment.push(PropertyOutputContext.class, context);
 127  310
             mustPopEnvironment = true;
 128  
 
 129  310
             return beanBlockSource.getDisplayBlock(datatype);
 130  
         }
 131  
 
 132  7070
         Object value = readPropertyForObject();
 133  
 
 134  7070
         String text = value == null ? "" : value.toString();
 135  
 
 136  7070
         if (InternalUtils.isNonBlank(text))
 137  
         {
 138  6884
             writer.write(text);
 139  
         }
 140  
 
 141  
         // Don't render anything else
 142  
 
 143  7070
         return false;
 144  
     }
 145  
 
 146  
     Object readPropertyForObject()
 147  
     {
 148  7382
         PropertyConduit conduit = model.getConduit();
 149  
 
 150  
         try
 151  
         {
 152  7382
             return conduit == null ? null : conduit.get(object);
 153  
         }
 154  2
         catch (NullPointerException ex)
 155  
         {
 156  2
             throw new NullPointerException(BaseMessages.nullValueInPath(model.getPropertyName()));
 157  
         }
 158  
     }
 159  
 
 160  
     /**
 161  
      * Returns false; there's no template and this prevents the body from rendering.
 162  
      */
 163  
     boolean beforeRenderTemplate()
 164  
     {
 165  2718
         return false;
 166  
     }
 167  
 
 168  
     void afterRender()
 169  
     {
 170  9788
         if (mustPopEnvironment)
 171  
         {
 172  310
             environment.pop(PropertyOutputContext.class);
 173  310
             mustPopEnvironment = false;
 174  
         }
 175  9788
     }
 176  
 
 177  
     // Used for testing.
 178  
     void inject(final PropertyModel model, final Object object)
 179  
     {
 180  2
         this.model = model;
 181  2
         this.object = object;
 182  2
     }
 183  
 }