Coverage Report - org.apache.tiles.BasicAttributeContext
 
Classes in this File Line Coverage Branch Coverage Complexity
BasicAttributeContext
100%
170/170
84%
116/138
3.714
 
 1  
 /*
 2  
  * $Id: BasicAttributeContext.java 943645 2010-05-12 19:33:19Z apetrelli $
 3  
  *
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 package org.apache.tiles;
 23  
 
 24  
 import static org.apache.tiles.CompareUtil.*;
 25  
 
 26  
 import java.io.Serializable;
 27  
 import java.util.HashMap;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 
 31  
 
 32  
 /**
 33  
  * Basic implementation for <code>AttributeContext</code>.
 34  
  *
 35  
  * @version $Rev: 943645 $ $Date: 2010-05-13 05:33:19 +1000 (Thu, 13 May 2010) $
 36  
  * @since 2.1.0
 37  
  */
 38  
 public class BasicAttributeContext implements AttributeContext, Serializable {
 39  
 
 40  
     /**
 41  
      * The template attribute, to render a template.
 42  
      *
 43  
      * @since 2.1.2
 44  
      */
 45  
     protected Attribute templateAttribute;
 46  
 
 47  
     /**
 48  
      * Associated ViewPreparer URL or classname, if defined.
 49  
      *
 50  
      * @since 2.1.0
 51  
      */
 52  57
     protected String preparer = null;
 53  
 
 54  
     /**
 55  
      * Template attributes.
 56  
      * @since 2.1.0
 57  
      */
 58  57
     protected Map<String, Attribute> attributes = null;
 59  
 
 60  
     /**
 61  
      * Cascaded template attributes.
 62  
      * @since 2.1.0
 63  
      */
 64  57
     protected Map<String, Attribute> cascadedAttributes = null;
 65  
 
 66  
     /**
 67  
      * Constructor.
 68  
      *
 69  
      * @since 2.1.0
 70  
      */
 71  41
     public BasicAttributeContext() {
 72  41
     }
 73  
 
 74  
     /**
 75  
      * Constructor.
 76  
      * Create a context and set specified attributes.
 77  
      *
 78  
      * @param attributes Attributes to initialize context.
 79  
      * @since 2.1.0
 80  
      */
 81  3
     public BasicAttributeContext(Map<String, Attribute> attributes) {
 82  3
         if (attributes != null) {
 83  3
             this.attributes = deepCopyAttributeMap(attributes);
 84  
         }
 85  3
     }
 86  
 
 87  
     /**
 88  
      * Copy constructor.
 89  
      *
 90  
      * @param context The constructor to copy.
 91  
      * @since 2.1.0
 92  
      */
 93  2
     public BasicAttributeContext(AttributeContext context) {
 94  2
         if (context instanceof BasicAttributeContext) {
 95  1
             copyBasicAttributeContext((BasicAttributeContext) context);
 96  
         } else {
 97  1
             Attribute parentTemplateAttribute = context.getTemplateAttribute();
 98  1
             if (parentTemplateAttribute != null) {
 99  1
                 this.templateAttribute = new Attribute(parentTemplateAttribute);
 100  
             }
 101  1
             this.preparer = context.getPreparer();
 102  1
             this.attributes = new HashMap<String, Attribute>();
 103  1
             Set<String> parentAttributeNames = context.getLocalAttributeNames();
 104  1
             if (parentAttributeNames != null) {
 105  1
                 for (String name : parentAttributeNames) {
 106  2
                     attributes.put(name, new Attribute(context.getLocalAttribute(name)));
 107  2
                 }
 108  
             }
 109  1
             inheritCascadedAttributes(context);
 110  
         }
 111  2
     }
 112  
 
 113  
     /**
 114  
      * Copy constructor.
 115  
      *
 116  
      * @param context The constructor to copy.
 117  
      * @since 2.1.0
 118  
      */
 119  11
     public BasicAttributeContext(BasicAttributeContext context) {
 120  11
         copyBasicAttributeContext(context);
 121  11
     }
 122  
 
 123  
     /** {@inheritDoc} */
 124  
     public Attribute getTemplateAttribute() {
 125  38
         return templateAttribute;
 126  
     }
 127  
 
 128  
     /** {@inheritDoc} */
 129  
     public void setTemplateAttribute(Attribute templateAttribute) {
 130  11
         this.templateAttribute = templateAttribute;
 131  11
     }
 132  
 
 133  
     /** {@inheritDoc} */
 134  
     public String getPreparer() {
 135  5
         return preparer;
 136  
     }
 137  
 
 138  
     /** {@inheritDoc} */
 139  
     public void setPreparer(String url) {
 140  7
         this.preparer = url;
 141  7
     }
 142  
 
 143  
     /** {@inheritDoc} */
 144  
     public void inheritCascadedAttributes(AttributeContext context) {
 145  2
         if (context instanceof BasicAttributeContext) {
 146  1
             copyCascadedAttributes((BasicAttributeContext) context);
 147  
         } else {
 148  1
             this.cascadedAttributes = new HashMap<String, Attribute>();
 149  1
             Set<String> parentAttributeNames = context.getCascadedAttributeNames();
 150  1
             if (parentAttributeNames != null) {
 151  1
                 for (String name : parentAttributeNames) {
 152  2
                     cascadedAttributes.put(name, new Attribute(context
 153  
                             .getCascadedAttribute(name)));
 154  2
                 }
 155  
             }
 156  
         }
 157  2
     }
 158  
 
 159  
     /** {@inheritDoc} */
 160  
     public void inherit(AttributeContext parent) {
 161  7
         if (parent instanceof BasicAttributeContext) {
 162  4
             inherit((BasicAttributeContext) parent);
 163  
         } else {
 164  
             // Inheriting template, roles and preparer.
 165  3
             Attribute parentTemplateAttribute = parent.getTemplateAttribute();
 166  3
             inheritParentTemplateAttribute(parentTemplateAttribute);
 167  3
             if (preparer == null) {
 168  3
                 preparer = parent.getPreparer();
 169  
             }
 170  
 
 171  
             // Inheriting attributes.
 172  3
             Set<String> names = parent.getCascadedAttributeNames();
 173  3
             if (names != null && !names.isEmpty()) {
 174  3
                 for (String name : names) {
 175  4
                     Attribute attribute = parent.getCascadedAttribute(name);
 176  4
                     Attribute destAttribute = getCascadedAttribute(name);
 177  4
                     if (destAttribute == null) {
 178  2
                         putAttribute(name, attribute, true);
 179  2
                     } else if (attribute instanceof ListAttribute
 180  
                             && destAttribute instanceof ListAttribute
 181  
                             && ((ListAttribute) destAttribute).isInherit()) {
 182  1
                         ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
 183  
                     }
 184  4
                 }
 185  
             }
 186  3
             names = parent.getLocalAttributeNames();
 187  3
             if (names != null && !names.isEmpty()) {
 188  3
                 for (String name : names) {
 189  4
                     Attribute attribute = parent.getLocalAttribute(name);
 190  4
                     Attribute destAttribute = getLocalAttribute(name);
 191  4
                     if (destAttribute == null) {
 192  1
                         putAttribute(name, attribute, false);
 193  3
                     } else if (attribute instanceof ListAttribute
 194  
                             && destAttribute instanceof ListAttribute
 195  
                             && ((ListAttribute) destAttribute).isInherit()) {
 196  1
                         ((ListAttribute) destAttribute).inherit((ListAttribute) attribute);
 197  
                     }
 198  4
                 }
 199  
             }
 200  
         }
 201  7
     }
 202  
 
 203  
     /**
 204  
      * Inherits the attribute context, inheriting, i.e. copying if not present,
 205  
      * the attributes.
 206  
      *
 207  
      * @param parent The attribute context to inherit.
 208  
      * @since 2.1.0
 209  
      */
 210  
     public void inherit(BasicAttributeContext parent) {
 211  
         // Set template, roles and preparer if not set.
 212  6
         inheritParentTemplateAttribute(parent.getTemplateAttribute());
 213  6
         if (preparer == null) {
 214  6
             preparer = parent.preparer;
 215  
         }
 216  
 
 217  
         // Sets attributes.
 218  6
         cascadedAttributes = addMissingAttributes(parent.cascadedAttributes,
 219  
                 cascadedAttributes);
 220  6
         attributes = addMissingAttributes(parent.attributes, attributes);
 221  6
     }
 222  
 
 223  
     /**
 224  
      * Add all attributes to this context.
 225  
      * Copies all of the mappings from the specified attribute map to this context.
 226  
      * New attribute mappings will replace any mappings that this context had for any of the keys
 227  
      * currently in the specified attribute map.
 228  
      *
 229  
      * @param newAttributes Attributes to add.
 230  
      * @since 2.1.0
 231  
      */
 232  
     public void addAll(Map<String, Attribute> newAttributes) {
 233  3
         if (newAttributes == null) {
 234  1
             return;
 235  
         }
 236  
 
 237  2
         if (attributes == null) {
 238  1
             attributes = new HashMap<String, Attribute>(newAttributes);
 239  1
             return;
 240  
         }
 241  
 
 242  1
         attributes.putAll(newAttributes);
 243  1
     }
 244  
 
 245  
     /**
 246  
      * Add all missing attributes to this context.
 247  
      * Copies all of the mappings from the specified attributes map to this context.
 248  
      * New attribute mappings will be added only if they don't already exist in
 249  
      * this context.
 250  
      *
 251  
      * @param defaultAttributes Attributes to add.
 252  
      * @since 2.1.0
 253  
      */
 254  
     public void addMissing(Map<String, Attribute> defaultAttributes) {
 255  5
         if (defaultAttributes == null) {
 256  1
             return;
 257  
         }
 258  
 
 259  4
         if (attributes == null) {
 260  3
             attributes = new HashMap<String, Attribute>();
 261  3
             if (cascadedAttributes == null || cascadedAttributes.isEmpty()) {
 262  1
                 attributes.putAll(defaultAttributes);
 263  1
                 return;
 264  
             }
 265  
         }
 266  
 
 267  3
         Set<Map.Entry<String, Attribute>> entries = defaultAttributes.entrySet();
 268  3
         for (Map.Entry<String, Attribute> entry : entries) {
 269  6
             String key = entry.getKey();
 270  6
             if (!attributes.containsKey(key)
 271  
                     && (cascadedAttributes == null || !cascadedAttributes
 272  
                             .containsKey(key))) {
 273  4
                 attributes.put(entry.getKey(), entry.getValue());
 274  
             }
 275  6
         }
 276  3
     }
 277  
 
 278  
     /** {@inheritDoc} */
 279  
     public Attribute getAttribute(String name) {
 280  39
         Attribute retValue = null;
 281  39
         if (attributes != null) {
 282  39
             retValue = attributes.get(name);
 283  
         }
 284  
 
 285  39
         if (retValue == null && cascadedAttributes != null) {
 286  4
             retValue = cascadedAttributes.get(name);
 287  
         }
 288  
 
 289  39
         return retValue;
 290  
     }
 291  
 
 292  
     /** {@inheritDoc} */
 293  
     public Attribute getLocalAttribute(String name) {
 294  22
         if (attributes == null) {
 295  1
             return null;
 296  
         }
 297  
 
 298  21
         return attributes.get(name);
 299  
     }
 300  
 
 301  
     /** {@inheritDoc} */
 302  
     public Attribute getCascadedAttribute(String name) {
 303  22
         if (cascadedAttributes == null) {
 304  2
             return null;
 305  
         }
 306  
 
 307  20
         return cascadedAttributes.get(name);
 308  
     }
 309  
 
 310  
     /** {@inheritDoc} */
 311  
     public Set<String> getLocalAttributeNames() {
 312  3
         if (attributes != null && !attributes.isEmpty()) {
 313  1
             return attributes.keySet();
 314  
         }
 315  2
         return null;
 316  
     }
 317  
 
 318  
     /** {@inheritDoc} */
 319  
     public Set<String> getCascadedAttributeNames() {
 320  3
         if (cascadedAttributes != null && !cascadedAttributes.isEmpty()) {
 321  1
             return cascadedAttributes.keySet();
 322  
         }
 323  2
         return null;
 324  
     }
 325  
 
 326  
     /** {@inheritDoc} */
 327  
     public void putAttribute(String name, Attribute value) {
 328  17
         if (attributes == null) {
 329  11
             attributes = new HashMap<String, Attribute>();
 330  
         }
 331  
 
 332  17
         attributes.put(name, value);
 333  17
     }
 334  
 
 335  
     /** {@inheritDoc} */
 336  
     public void putAttribute(String name, Attribute value, boolean cascade) {
 337  
         Map<String, Attribute> mapToUse;
 338  63
         if (cascade) {
 339  34
             if (cascadedAttributes == null) {
 340  21
                 cascadedAttributes = new HashMap<String, Attribute>();
 341  
             }
 342  34
             mapToUse = cascadedAttributes;
 343  
         } else {
 344  29
             if (attributes == null) {
 345  18
                 attributes = new HashMap<String, Attribute>();
 346  
             }
 347  29
             mapToUse = attributes;
 348  
         }
 349  63
         mapToUse.put(name, value);
 350  63
     }
 351  
 
 352  
     /** {@inheritDoc} */
 353  
     public void clear() {
 354  1
         templateAttribute = null;
 355  1
         preparer = null;
 356  1
         attributes.clear();
 357  1
         cascadedAttributes.clear();
 358  1
     }
 359  
 
 360  
     /** {@inheritDoc} */
 361  
     @Override
 362  
     public boolean equals(Object obj) {
 363  7
         BasicAttributeContext bac = (BasicAttributeContext) obj;
 364  7
         return nullSafeEquals(templateAttribute, bac.templateAttribute)
 365  
                 && nullSafeEquals(preparer, bac.preparer)
 366  
                 && nullSafeEquals(attributes, bac.attributes)
 367  
                 && nullSafeEquals(cascadedAttributes, bac.cascadedAttributes);
 368  
     }
 369  
 
 370  
     /** {@inheritDoc} */
 371  
     @Override
 372  
     public int hashCode() {
 373  3
         return nullSafeHashCode(templateAttribute) + nullSafeHashCode(preparer)
 374  
                 + nullSafeHashCode(attributes)
 375  
                 + nullSafeHashCode(cascadedAttributes);
 376  
     }
 377  
 
 378  
     /**
 379  
      * Inherits the parent template attribute.
 380  
      *
 381  
      * @param parentTemplateAttribute The parent template attribute.
 382  
      */
 383  
     private void inheritParentTemplateAttribute(
 384  
             Attribute parentTemplateAttribute) {
 385  9
         if (parentTemplateAttribute != null) {
 386  5
             if (templateAttribute == null) {
 387  4
                 templateAttribute = new Attribute(parentTemplateAttribute);
 388  
             } else {
 389  1
                 templateAttribute.inherit(parentTemplateAttribute);
 390  
             }
 391  
         }
 392  9
     }
 393  
 
 394  
     /**
 395  
      * Copies a BasicAttributeContext in an easier way.
 396  
      *
 397  
      * @param context The context to copy.
 398  
      */
 399  
     private void copyBasicAttributeContext(BasicAttributeContext context) {
 400  12
         Attribute parentTemplateAttribute = context.getTemplateAttribute();
 401  12
         if (parentTemplateAttribute != null) {
 402  7
             this.templateAttribute = new Attribute(parentTemplateAttribute);
 403  
         }
 404  12
         preparer = context.preparer;
 405  12
         if (context.attributes != null && !context.attributes.isEmpty()) {
 406  12
             attributes = deepCopyAttributeMap(context.attributes);
 407  
         }
 408  12
         copyCascadedAttributes(context);
 409  12
     }
 410  
 
 411  
     /**
 412  
      * Copies the cascaded attributes to the current context.
 413  
      *
 414  
      * @param context The context to copy from.
 415  
      */
 416  
     private void copyCascadedAttributes(BasicAttributeContext context) {
 417  13
         if (context.cascadedAttributes != null
 418  
                 && !context.cascadedAttributes.isEmpty()) {
 419  8
             cascadedAttributes = deepCopyAttributeMap(context.cascadedAttributes);
 420  
         }
 421  13
     }
 422  
 
 423  
     /**
 424  
      * Adds missing attributes to the destination map.
 425  
      *
 426  
      * @param source The source attribute map.
 427  
      * @param destination The destination attribute map.
 428  
      * @return The destination attribute map if not null, a new one otherwise.
 429  
      */
 430  
     private Map<String, Attribute> addMissingAttributes(Map<String, Attribute> source,
 431  
             Map<String, Attribute> destination) {
 432  12
         if (source != null && !source.isEmpty()) {
 433  8
             if (destination == null) {
 434  4
                 destination = new HashMap<String, Attribute>();
 435  
             }
 436  8
             for (Map.Entry<String, Attribute> entry : source.entrySet()) {
 437  14
                 String key = entry.getKey();
 438  14
                 Attribute destAttribute = destination.get(key);
 439  14
                 if (destAttribute == null) {
 440  10
                     destination.put(key, entry.getValue());
 441  4
                 } else if (destAttribute instanceof ListAttribute
 442  
                         && entry.getValue() instanceof ListAttribute
 443  
                         && ((ListAttribute) destAttribute).isInherit()) {
 444  1
                     ((ListAttribute) destAttribute)
 445  
                             .inherit((ListAttribute) entry.getValue());
 446  
                 }
 447  14
             }
 448  
         }
 449  
 
 450  12
         return destination;
 451  
     }
 452  
 
 453  
     /**
 454  
      * Deep copies the attribute map, by creating clones (using copy
 455  
      * constructors) of the attributes.
 456  
      *
 457  
      * @param attributes The attribute map to copy.
 458  
      * @return The copied map.
 459  
      */
 460  
     private Map<String, Attribute> deepCopyAttributeMap(
 461  
             Map<String, Attribute> attributes) {
 462  23
         Map<String, Attribute> retValue = new HashMap<String, Attribute>(attributes.size());
 463  23
         for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
 464  37
             Attribute toCopy = entry.getValue();
 465  37
             if (toCopy != null) {
 466  37
                 retValue.put(entry.getKey(), toCopy.clone());
 467  
             }
 468  37
         }
 469  23
         return retValue;
 470  
     }
 471  
 }