Coverage Report - com.sourceforge.jpatterns.core.configuration.model.JPatternsConfigBeansBuilderImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
JPatternsConfigBeansBuilderImpl
86% 
91% 
0
 
 1  
 package com.sourceforge.jpatterns.core.configuration.model;
 2  
 
 3  
 import com.sourceforge.jpatterns.core.JPConstants;
 4  
 import com.sourceforge.jpatterns.core.configuration.PropertiesBasedFactory;
 5  
 import com.sourceforge.jpatterns.core.configuration.PropertiesProvider;
 6  
 import com.sourceforge.jpatterns.core.configuration.exceptions.JPConfigException;
 7  
 import com.sourceforge.jpatterns.core.configuration.exceptions.JPInitializationException;
 8  
 import com.sourceforge.jpatterns.schema.CastorConfigType;
 9  
 import com.sourceforge.jpatterns.schema.CastorFactoryType;
 10  
 import com.sourceforge.jpatterns.schema.CastorGroupType;
 11  
 import com.sourceforge.jpatterns.schema.CastorGroupTypeItem;
 12  
 import com.sourceforge.jpatterns.schema.CastorNameScopePriorityType;
 13  
 import com.sourceforge.jpatterns.schema.CastorSectionType;
 14  
 import com.sourceforge.jpatterns.schema.Item;
 15  
 import com.sourceforge.jpatterns.schema.JPatternsConfig;
 16  
 import com.sourceforge.jpatterns.utils.CastorUtils;
 17  
 import com.zmicer.utils.InputArgumentUtils;
 18  
 import com.zmicer.utils.ObjectStateUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.log4j.Logger;
 21  
 
 22  
 import java.util.ArrayList;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 
 26  
 /**
 27  
  * Default, "native" implementation of the appropriate interface.
 28  
  *
 29  
  * $Author:: zmicer             $<br/>
 30  
  * $Rev:: 67                    $<br/> * $Date:: 2007-08-28 21:37:07 #$<br/>
 31  
  * $Date:: 2007-08-28 21:37:07 #$<br/>
 32  
  */
 33  975
 public class JPatternsConfigBeansBuilderImpl implements IJPatternsConfigBeansBuilder
 34  
 {
 35  
     /**
 36  
      * Logger instance.
 37  
      */
 38  5
     final public static Logger LOG = Logger.getLogger(JPatternsConfigBeansBuilderImpl.class);
 39  
 
 40  
     /**
 41  
      * value for the com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_OVERRIDING_DEPTH property
 42  
      */
 43  
     private static String OverridingDepth;
 44  
 
 45  
     /**
 46  
      * value for the
 47  
      * com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_CUSTOM_OVERRIDES_NOT_DEPENDING_ON_PRIORITY
 48  
      */
 49  
     private static boolean OverrideNotDependingOnPriority;
 50  
 
 51  
     /**
 52  
      * Initialization block.
 53  
      */
 54  
     {
 55  975
         PropertiesProvider propertiesProvider =
 56  
             PropertiesProvider.getInstance(PropertiesBasedFactory.getInstance().getPropertiesManager(), false);
 57  975
         final String depth = propertiesProvider.getStringProperty(
 58  
             com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_OVERRIDING_DEPTH);
 59  975
         setOverridingDepth((null == depth) ? PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_SECTION.toString() : depth);
 60  975
         final Boolean property = propertiesProvider.getBooleanProperty(com.sourceforge.jpatterns.core.configuration.
 61  
             PropertiesProvider.JPProperties.XML_CONFIG_CUSTOM_OVERRIDES_NOT_DEPENDING_ON_PRIORITY);
 62  975
         setOverrideNotDependingOnPriority((null != property) && property);
 63  975
     }
 64  
 
 65  
     /**
 66  
      * @see IJPatternsConfigBeansBuilder#build(com.sourceforge.jpatterns.schema.JPatternsConfig)
 67  
      * <br/>
 68  
      * <pre>
 69  
      * The algorithm is used here as follows:
 70  
      * <strong>Sections filling</strong>:
 71  
      * 1. the List of "section based" objects is formed<br/>
 72  
      *      - in the case the section has not explicit scope - the default one from the root castor object or the
 73  
      *      {@link com.sourceforge.jpatterns.core.JPConstants.DEFAULT_SCOPE_NAME} is set.
 74  
      * 2. all the "section based" objects are put to the map
 75  
      *      - in the case {@link com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_OVERRIDING_DEPTH}
 76  
      * property equals to
 77  
      * <code>com.sourceforge.jpatterns.core.configuration.PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_ITEM</code> then in the case
 78  
      * of two identical sections (scopes, section name and priority), they would be merged to the one by joining the appropriate business
 79  
      * items. If there are identical business items (scopes, name and priority) - the
 80  
      * <code>com.sourceforge.jpatterns.core.configuration.exceptions.JPInitializationException</code> exception would appear
 81  
      *      - in the case {@link com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_OVERRIDING_DEPTH}
 82  
      * property equals to
 83  
      * <code>com.sourceforge.jpatterns.core.configuration.PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_SECTION</code> then in the
 84  
      * case of two identical sections (scopes, section name and priority)
 85  
      * <code>com.sourceforge.jpatterns.core.configuration.exceptions.JPConfigException</code> exception would appear
 86  
      *      - in the case of the identical pathes but different priorities they would be taken into consideration (in this case
 87  
      * com.sourceforge.jpatterns.core.configuration.PropertiesProvider.JPProperties.XML_CONFIG_CUSTOM_OVERRIDES_NOT_DEPENDING_ON_PRIORITY
 88  
      * would be considered too).
 89  
      * <p/>
 90  
      *      <strong>Business items filling</strong>:
 91  
      *      todo [zmicer]: <<t.b.d.>>
 92  
      * <p/>
 93  
      * note [zmicer]: please be noticed the Section with the certain scope is allowed to store the business items with different scopes
 94  
      * </pre>
 95  
      */
 96  
     public JPatternsConfigBean build(final JPatternsConfig config)
 97  
     {
 98  
         // 00: check the input params on the validness.
 99  494
         InputArgumentUtils.checkObjects(config);
 100  
 
 101  489
         JPatternsConfigBean result = new JPatternsConfigBean();
 102  
         // 01: set additional info
 103  489
         result.setDefaultScope(config.getDefaultScope());
 104  489
         result.setCastorConfig(config);
 105  
 
 106  
         // 02: fill with sections/items
 107  489
         CastorUtils.validateAndNormalizeScopesPriorities(config);
 108  489
         fill(result, CastorUtils.extractCastorSectionTypeObjects(config));
 109  
 
 110  489
         return result;
 111  
     }
 112  
 
 113  
     /**
 114  
      * @see IJPatternsConfigBeansBuilder#build(com.sourceforge.jpatterns.schema.JPatternsConfig)
 115  
      */
 116  
     public JPatternsConfigsBean build(final List<JPatternsConfigBaseBean> beans)
 117  
     {
 118  698
         InputArgumentUtils.checkObjects(beans);
 119  693
         final JPatternsConfigsBean result = new JPatternsConfigsBean();
 120  
 
 121  693
         final List<CastorSectionType> sections = new ArrayList<CastorSectionType>();
 122  693
         for (JPatternsConfigBaseBean bean : beans)
 123  
         {
 124  803
             ObjectStateUtils.strongCheck(bean);
 125  803
             sections.addAll(bean.getListOfSectionItems());
 126  803
         }
 127  693
         fill(result, sections);
 128  
 
 129  693
         return result;
 130  
     }
 131  
 
 132  
     /**
 133  
      * Please review the Java Docs to the method {@link fill}
 134  
      * todo [zmicer]: adjust Java Doc
 135  
      * todo [zmicer]: think if this method could be moved to interface of the builder too
 136  
      *
 137  
      * @param initialBaseBean the initial bean to fill.
 138  
      *                        Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
 139  
      * @param sections        the List of the CastorSectionType objects. They should be normalized in the sense of scopes and priorities(for
 140  
      *                        details study
 141  
      *                        {@link com.sourceforge.jpatterns.utils.CastorUtils#validateAndNormalizeScopesPriorities(JPatternsConfig)}).
 142  
      *                        Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
 143  
      */
 144  
     protected void fill(final JPatternsConfigBaseBean initialBaseBean, final List<CastorSectionType> sections)
 145  
     {
 146  1202
         InputArgumentUtils.checkObjects(initialBaseBean, sections);
 147  1187
         ObjectStateUtils.strongCheck(initialBaseBean);
 148  
 
 149  
         // 01: working with the sections.
 150  1187
         for (final CastorSectionType section : sections)
 151  
         {
 152  2525
             if (null == section.getScope() && null == section.getName())
 153  
             {
 154  0
                 throw new JPConfigException("The scope and name of CastorSectionType can not be null.");
 155  
             }
 156  2525
             final CastorSectionType alreadySection = initialBaseBean.getSection(section.getScope(), section.getName());
 157  
             // A. section with the same path is not existed yet or the pathes are different - just put it
 158  2525
             if (null == alreadySection ||
 159  
                 (!section.getScope().equals(alreadySection.getScope()) || !section.getName().equals(alreadySection.getName())))
 160  
             {
 161  2405
                 initialBaseBean.setSection(section.getScope(), section);
 162  2405
             }
 163  
             else
 164  
             {
 165  120
                 initialBaseBean.setSection(section.getScope(),
 166  
                     (CastorSectionType) choiceOrMergeCastorNameScopePriorityTypes(section, alreadySection));
 167  
             }
 168  2525
         }
 169  
 
 170  
         // 02: working with the business items
 171  
         // A. iterate through all the sections we have at this moment
 172  1187
         Map<String, Map<String, CastorSectionType>> sectionItems = initialBaseBean.getSectionItems();
 173  1187
         for (String sectionScope : sectionItems.keySet())
 174  
         {
 175  1165
             final Map<String, CastorSectionType> sectionsMap = sectionItems.get(sectionScope);
 176  1165
             for (String sectionName : sectionsMap.keySet())
 177  
             {
 178  2405
                 final CastorSectionType section = sectionsMap.get(sectionName);
 179  2405
                 final List<CastorNameScopePriorityType> items = CastorUtils.extractCastorNameScopePriorityTypeObjects(section);
 180  2405
                 for (CastorNameScopePriorityType item : items)
 181  
                 {
 182  6485
                     if (null == item.getScope() && null == section.getName())
 183  
                     {
 184  0
                         throw new JPConfigException("The scope and name of Item can not be null.");
 185  
                     }
 186  6485
                     if (StringUtils.isBlank(section.getScope()))
 187  
                     {
 188  0
                         throw new JPInitializationException("Section should have scope set.");
 189  
                     }
 190  6485
                     final CastorNameScopePriorityType alreadyItem =
 191  
                         initialBaseBean.getBusinessItem(section.getScope(), sectionName, item.getScope(), item.getName());
 192  
                     // A. item with the same path is not existed yet
 193  6485
                     if (null == alreadyItem)
 194  
                     {
 195  6485
                         initialBaseBean.setBusinessItem(section.getScope(), sectionName, item);
 196  6485
                     }
 197  
                     else
 198  
                     {
 199  0
                         initialBaseBean.setBusinessItem(section.getScope(), sectionName,
 200  
                             choiceOrMergeCastorNameScopePriorityTypes(item, alreadyItem));
 201  
                     }
 202  6485
                 }
 203  2405
             }
 204  1165
         }
 205  1187
     }
 206  
 
 207  
     /**
 208  
      * Choice one of the given CastorNameScopePriorityType castor objects or perform the merging if it is necessary. Please review the
 209  
      * comments to the main <code>fill</code> method to understand how it works (depending on the mentioned properties etc.)
 210  
      * <br/>
 211  
      * These objects should have the equal pathes to be passed here (scope, name) - otherwise the IllegalArgumentException appear
 212  
      *
 213  
      * @param castor1 the first object, Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
 214  
      * @param castor2 the second object, Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
 215  
      *
 216  
      * @return the object is more prioritized here
 217  
      */
 218  
     protected CastorNameScopePriorityType choiceOrMergeCastorNameScopePriorityTypes(final CastorNameScopePriorityType castor1,
 219  
         final CastorNameScopePriorityType castor2)
 220  
     {
 221  220
         InputArgumentUtils.checkObjects(castor1, castor2);
 222  210
         InputArgumentUtils.checkStrings(true, castor1.getScope(), castor1.getName(), castor1.getPriority());
 223  200
         InputArgumentUtils.checkStrings(true, castor2.getScope(), castor2.getName(), castor2.getPriority());
 224  200
         if (!castor1.getScope().equals(castor2.getScope()) || !castor1.getName().equals(castor2.getName()))
 225  
         {
 226  5
             throw new IllegalArgumentException("The provided object should have the identical pathes to be checked / compared.");
 227  
         }
 228  195
         if (!castor1.getClass().equals(castor2.getClass()))
 229  
         {
 230  0
             throw new IllegalArgumentException("The classes of the provided objects should be identical.");
 231  
         }
 232  
         // 00: priorities are equals
 233  195
         if (castor1.getPriority().equals(castor2.getPriority()))
 234  
         {
 235  
             // in the case of business items - just exception.
 236  15
             if (!(castor1 instanceof CastorSectionType))
 237  
             {
 238  5
                 throw new JPConfigException("The elements with identical pathes can not be merged - scope [" +
 239  
                     castor1.getScope() + "], name [" + castor1.getName() + "], priority [" + castor1.getPriority() + "]; class name " +
 240  
                     "is [" + castor1.getClass().getName() + "]");
 241  
             }
 242  
             // we need to apply overriding depth feature to here
 243  
             else
 244  
             {
 245  
                 // 00:b exception should be thrown - two identical pathes (including priotities)
 246  10
                 if (OverridingDepth.equals(
 247  
                     com.sourceforge.jpatterns.core.configuration.PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_SECTION.toString()))
 248  
                 {
 249  5
                     throw new JPConfigException("The elements with identical pathes can not be merged - scope [" +
 250  
                         castor1.getScope() + "], name [" + castor1.getName() + "], priority [" + castor1.getPriority() + "]; class " +
 251  
                         "name is [" + castor1.getClass().getName() + "]");
 252  
                 }
 253  
                 // 00:c no exception - we should merge the two items into the one (we won't check the items here - it would be done when
 254  
                 // the items would be put to the specialized map)
 255  5
                 else if (OverridingDepth.equals(
 256  
                     com.sourceforge.jpatterns.core.configuration.PropertiesProvider.OverridingDepths.OVERRIDING_LEVEL_ITEM.toString()))
 257  
                 {
 258  5
                     final List<CastorNameScopePriorityType> items =
 259  
                         CastorUtils.extractCastorNameScopePriorityTypeObjects((CastorSectionType) castor2);
 260  5
                     for (CastorNameScopePriorityType item : items)
 261  
                     {
 262  
                         // perform add functionality through the reflexion
 263  
                         // note [zmicer]: very risky block still it is better then reflexion. Seems to be these three base classes limit
 264  
                         // the scope of root section classes
 265  5
                         if (castor1 instanceof CastorConfigType)
 266  
                         {
 267  5
                             if (!(item instanceof Item))
 268  
                             {
 269  0
                                 throw new JPConfigException("The CastorNameScopePriorityType item should be of Item type in the " +
 270  
                                     "case castor section object is of the type CastorConfigType");
 271  
                             }
 272  5
                             ((CastorConfigType) castor1).addItem((Item) item);
 273  5
                         }
 274  0
                         else if (castor1 instanceof CastorFactoryType)
 275  
                         {
 276  0
                             if (!(item instanceof Item))
 277  
                             {
 278  0
                                 throw new JPConfigException("The CastorNameScopePriorityType item should be of Item type in the " +
 279  
                                     "case castor section object is of the type CastorFactoryType");
 280  
                             }
 281  0
                             ((CastorFactoryType) castor1).addItem((Item) item);
 282  0
                         }
 283  0
                         else if (castor1 instanceof CastorGroupType)
 284  
                         {
 285  0
                             final CastorGroupTypeItem groupItem = CastorUtils.constructGroupItem(item);
 286  0
                             ((CastorGroupType) castor1).addCastorGroupTypeItem(groupItem);
 287  
                         }
 288  5
                     }
 289  5
                     return castor1;
 290  
                 }
 291  
             }
 292  
         }
 293  
         else
 294  
         {
 295  180
             int firstPriority = CastorUtils.getPriority(castor1);
 296  180
             int secondPriority = CastorUtils.getPriority(castor2);
 297  180
             boolean firstPrioritized = false;
 298  180
             boolean secondPrioritized = false;
 299  180
             if (castor1.getPriority().startsWith(JPConstants.PRIORITIZED_PRIOTITY_PREFIX))
 300  
             {
 301  30
                 firstPrioritized = true;
 302  
             }
 303  180
             if (castor2.getPriority().startsWith(JPConstants.PRIORITIZED_PRIOTITY_PREFIX))
 304  
             {
 305  30
                 secondPrioritized = true;
 306  
             }
 307  
             // 00:d both prioritized or both not prioritized - just compare the priorities
 308  180
             if (firstPrioritized && secondPrioritized || (!firstPrioritized && !secondPrioritized))
 309  
             {
 310  140
                 return (firstPriority > secondPriority) ? castor1 : castor2;
 311  
             }
 312  
             // 00:e first prioritized - check the property too
 313  40
             else if (firstPrioritized)
 314  
             {
 315  20
                 if (OverrideNotDependingOnPriority)
 316  
                 {
 317  10
                     return castor1;
 318  
                 }
 319  
                 else
 320  
                 {
 321  10
                     return (firstPriority > secondPriority) ? castor1 : castor2;
 322  
                 }
 323  
             }
 324  
             // 00:f second prioritized - check the property too
 325  
             else
 326  
             {
 327  20
                 if (OverrideNotDependingOnPriority)
 328  
                 {
 329  10
                     return castor2;
 330  
                 }
 331  
                 else
 332  
                 {
 333  10
                     return (firstPriority > secondPriority) ? castor1 : castor2;
 334  
                 }
 335  
             }
 336  
         }
 337  0
         return null;
 338  
     }
 339  
 
 340  
     /**
 341  
      * Set the overriding depth. This method is necessary for the unit testing.
 342  
      *
 343  
      * @param depth the value we ned to set, Can not be null (otherwise <code>IllegalArgumentException</code> would appear).
 344  
      */
 345  
     protected static void setOverridingDepth(final String depth)
 346  
     {
 347  1000
         InputArgumentUtils.checkStrings(true, depth);
 348  995
         OverridingDepth = depth;
 349  995
     }
 350  
 
 351  
     /**
 352  
      * @return overriding depth
 353  
      */
 354  
     protected static String getOverridingDepth()
 355  
     {
 356  15
         return OverridingDepth;
 357  
     }
 358  
 
 359  
     /**
 360  
      * Set the OverrideNotDependingOnPriority static field with the new value. This method is necessary for unit testing.
 361  
      *
 362  
      * @param value new boolean value
 363  
      */
 364  
     protected static void setOverrideNotDependingOnPriority(final boolean value)
 365  
     {
 366  1005
         OverrideNotDependingOnPriority = value;
 367  1005
     }
 368  
 
 369  
     /**
 370  
      * @return the value of OverrideNotDependingOnPriority
 371  
      */
 372  
     protected static boolean getOverrideNotDependingOnPriority()
 373  
     {
 374  15
         return OverrideNotDependingOnPriority;
 375  
     }
 376  
 }