Coverage Report - org.apache.tapestry5.internal.beaneditor.BeanModelImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
BeanModelImpl
100%
84/84
100%
22/22
0
 
 1  
 // Copyright 2007, 2008 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.internal.beaneditor;
 16  
 
 17  
 import org.apache.tapestry5.PropertyConduit;
 18  
 import org.apache.tapestry5.beaneditor.BeanModel;
 19  
 import org.apache.tapestry5.beaneditor.PropertyModel;
 20  
 import org.apache.tapestry5.beaneditor.RelativePosition;
 21  
 import org.apache.tapestry5.internal.services.CoercingPropertyConduitWrapper;
 22  
 import org.apache.tapestry5.ioc.Messages;
 23  
 import org.apache.tapestry5.ioc.ObjectLocator;
 24  
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 25  
 import org.apache.tapestry5.ioc.internal.util.Defense;
 26  
 import org.apache.tapestry5.ioc.services.ClassFabUtils;
 27  
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 28  
 import org.apache.tapestry5.services.PropertyConduitSource;
 29  
 
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 
 33  
 public class BeanModelImpl<T> implements BeanModel<T>
 34  
 {
 35  
     private final Class<T> beanType;
 36  
 
 37  
     private final PropertyConduitSource propertyConduitSource;
 38  
 
 39  
     private final TypeCoercer typeCoercer;
 40  
 
 41  
     private final Messages messages;
 42  
 
 43  
     private final ObjectLocator locator;
 44  
 
 45  326
     private final Map<String, PropertyModel> properties = CollectionFactory.newCaseInsensitiveMap();
 46  
 
 47  
     // The list of property names, in desired order (generally not alphabetical order).
 48  
 
 49  326
     private final List<String> propertyNames = CollectionFactory.newList();
 50  
 
 51  
     public BeanModelImpl(
 52  
             Class<T> beanType, PropertyConduitSource
 53  
             propertyConduitSource,
 54  
             TypeCoercer typeCoercer, Messages
 55  
             messages, ObjectLocator locator)
 56  
 
 57  326
     {
 58  326
         this.beanType = beanType;
 59  326
         this.propertyConduitSource = propertyConduitSource;
 60  326
         this.typeCoercer = typeCoercer;
 61  326
         this.messages = messages;
 62  326
         this.locator = locator;
 63  326
     }
 64  
 
 65  
     public Class<T> getBeanType()
 66  
     {
 67  8
         return beanType;
 68  
     }
 69  
 
 70  
     public T newInstance()
 71  
     {
 72  14
         return locator.autobuild(beanType);
 73  
     }
 74  
 
 75  
     public PropertyModel add(String propertyName)
 76  
     {
 77  1092
         PropertyConduit conduit = createConduit(propertyName);
 78  
 
 79  1090
         return add(propertyName, conduit);
 80  
     }
 81  
 
 82  
     private void validateNewPropertyName(String propertyName)
 83  
     {
 84  1158
         Defense.notBlank(propertyName, "propertyName");
 85  
 
 86  1158
         if (properties.containsKey(propertyName))
 87  2
             throw new RuntimeException(BeanEditorMessages.duplicatePropertyName(
 88  
                     beanType,
 89  
                     propertyName));
 90  1156
     }
 91  
 
 92  
     public PropertyModel add(RelativePosition position, String existingPropertyName,
 93  
                              String propertyName, PropertyConduit conduit)
 94  
     {
 95  6
         Defense.notNull(position, "position");
 96  
 
 97  6
         validateNewPropertyName(propertyName);
 98  
 
 99  
         // Locate the existing one.
 100  
 
 101  6
         PropertyModel existing = get(existingPropertyName);
 102  
 
 103  
         // Use the case normalized property name.
 104  
 
 105  6
         int pos = propertyNames.indexOf(existing.getPropertyName());
 106  
 
 107  6
         PropertyModel newModel = new PropertyModelImpl(this, propertyName, conduit, messages);
 108  
 
 109  6
         properties.put(propertyName, newModel);
 110  
 
 111  6
         int offset = position == RelativePosition.AFTER ? 1 : 0;
 112  
 
 113  6
         propertyNames.add(pos + offset, propertyName);
 114  
 
 115  6
         return newModel;
 116  
     }
 117  
 
 118  
     public PropertyModel add(RelativePosition position, String existingPropertyName,
 119  
                              String propertyName)
 120  
     {
 121  2
         PropertyConduit conduit = createConduit(propertyName);
 122  
 
 123  2
         return add(position, existingPropertyName, propertyName, conduit);
 124  
     }
 125  
 
 126  
     public PropertyModel add(String propertyName, PropertyConduit conduit)
 127  
     {
 128  1152
         validateNewPropertyName(propertyName);
 129  
 
 130  1150
         PropertyModel propertyModel = new PropertyModelImpl(this, propertyName, conduit, messages);
 131  
 
 132  1150
         properties.put(propertyName, propertyModel);
 133  
 
 134  
         // Remember the order in which the properties were added.
 135  
 
 136  1150
         propertyNames.add(propertyName);
 137  
 
 138  1150
         return propertyModel;
 139  
     }
 140  
 
 141  
     private CoercingPropertyConduitWrapper createConduit(String propertyName)
 142  
     {
 143  1094
         return new CoercingPropertyConduitWrapper(propertyConduitSource.create(beanType,
 144  
                                                                                propertyName), typeCoercer);
 145  
     }
 146  
 
 147  
     public PropertyModel get(String propertyName)
 148  
     {
 149  22074
         PropertyModel propertyModel = properties.get(propertyName);
 150  
 
 151  22074
         if (propertyModel == null)
 152  2
             throw new RuntimeException(BeanEditorMessages.unknownProperty(beanType,
 153  
                                                                           propertyName,
 154  
                                                                           properties.keySet()));
 155  
 
 156  22072
         return propertyModel;
 157  
     }
 158  
 
 159  
     public PropertyModel getById(String propertyId)
 160  
     {
 161  38
         for (PropertyModel model : properties.values())
 162  
         {
 163  134
             if (model.getId().equalsIgnoreCase(propertyId)) return model;
 164  
         }
 165  
 
 166  
         // Not found, so we throw an exception. A bit of work to set
 167  
         // up the exception however.
 168  
 
 169  2
         List<String> ids = CollectionFactory.newList();
 170  
 
 171  2
         for (PropertyModel model : properties.values())
 172  
         {
 173  8
             ids.add(model.getId());
 174  
         }
 175  
 
 176  2
         throw new RuntimeException(BeanEditorMessages.unknownPropertyId(beanType,
 177  
                                                                         propertyId, ids));
 178  
 
 179  
     }
 180  
 
 181  
     public List<String> getPropertyNames()
 182  
     {
 183  2516
         return CollectionFactory.newList(propertyNames);
 184  
     }
 185  
 
 186  
     public BeanModel exclude(String... propertyNames)
 187  
     {
 188  36
         for (String propertyName : propertyNames)
 189  
         {
 190  22
             PropertyModel model = properties.get(propertyName);
 191  
 
 192  22
             if (model == null) continue;
 193  
 
 194  
             // De-referencing from the model is needed because the name provided may not be a
 195  
             // case-exact match, so we get the normalized or canonical name from the model because
 196  
             // that's the one in propertyNames.
 197  
 
 198  20
             this.propertyNames.remove(model.getPropertyName());
 199  
 
 200  20
             properties.remove(propertyName);
 201  
         }
 202  
 
 203  14
         return this;
 204  
     }
 205  
 
 206  
     public BeanModel reorder(String... propertyNames)
 207  
     {
 208  438
         List<String> remainingPropertyNames = CollectionFactory.newList(this.propertyNames);
 209  438
         List<String> reorderedPropertyNames = CollectionFactory.newList();
 210  
 
 211  1852
         for (String name : propertyNames)
 212  
         {
 213  1414
             PropertyModel model = get(name);
 214  
 
 215  
             // Get the canonical form (which may differ from name in terms of case)
 216  1414
             String canonical = model.getPropertyName();
 217  
 
 218  1414
             reorderedPropertyNames.add(canonical);
 219  
 
 220  1414
             remainingPropertyNames.remove(canonical);
 221  
         }
 222  
 
 223  438
         this.propertyNames.clear();
 224  438
         this.propertyNames.addAll(reorderedPropertyNames);
 225  
 
 226  
         // Any unspecified names are ordered to the end. Don't want them? Remove them instead.
 227  438
         this.propertyNames.addAll(remainingPropertyNames);
 228  
 
 229  438
         return this;
 230  
     }
 231  
 
 232  
     public BeanModel include(String... propertyNames)
 233  
     {
 234  2
         List<String> reorderedPropertyNames = CollectionFactory.newList();
 235  2
         Map<String, PropertyModel> reduced = CollectionFactory.newCaseInsensitiveMap();
 236  
 
 237  
 
 238  6
         for (String name : propertyNames)
 239  
         {
 240  
 
 241  4
             PropertyModel model = get(name);
 242  
 
 243  4
             String canonical = model.getPropertyName();
 244  
 
 245  4
             reorderedPropertyNames.add(canonical);
 246  4
             reduced.put(canonical, model);
 247  
 
 248  
         }
 249  
 
 250  2
         this.propertyNames.clear();
 251  2
         this.propertyNames.addAll(reorderedPropertyNames);
 252  
 
 253  2
         properties.clear();
 254  2
         properties.putAll(reduced);
 255  
 
 256  2
         return this;
 257  
     }
 258  
 
 259  
     @Override
 260  
     public String toString()
 261  
     {
 262  2
         StringBuilder builder = new StringBuilder("BeanModel[");
 263  2
         builder.append(ClassFabUtils.toJavaClassName(beanType));
 264  
 
 265  2
         builder.append(" properties:");
 266  2
         String sep = "";
 267  
 
 268  2
         for (String name : propertyNames)
 269  
         {
 270  6
             builder.append(sep);
 271  6
             builder.append(name);
 272  
 
 273  6
             sep = ", ";
 274  
         }
 275  
 
 276  2
         builder.append("]");
 277  
 
 278  2
         return builder.toString();
 279  
     }
 280  
 }