Coverage Report - de.smartics.properties.spi.config.support.AbstractConfigurationProperties
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractConfigurationProperties
0%
0/91
0%
0/12
1,306
 
 1  
 /*
 2  
  * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package de.smartics.properties.spi.config.support;
 17  
 
 18  
 import java.beans.PropertyChangeListener;
 19  
 import java.beans.PropertyChangeSupport;
 20  
 import java.io.IOException;
 21  
 import java.io.ObjectInputStream;
 22  
 
 23  
 import javax.annotation.concurrent.ThreadSafe;
 24  
 
 25  
 import de.smartics.properties.api.config.domain.ConfigurationProperties;
 26  
 import de.smartics.properties.api.config.domain.ConfigurationValidationException;
 27  
 import de.smartics.properties.api.config.domain.Property;
 28  
 import de.smartics.properties.api.config.domain.ResolvedProperty;
 29  
 import de.smartics.properties.api.config.domain.SerializableConfigurationProperties;
 30  
 import de.smartics.properties.api.config.domain.UnknownPropertyException;
 31  
 import de.smartics.properties.api.config.domain.key.ConfigurationKey;
 32  
 import de.smartics.properties.api.core.domain.PropertiesContext;
 33  
 import de.smartics.properties.api.core.domain.PropertyContext;
 34  
 import de.smartics.properties.api.core.domain.PropertyDescriptor;
 35  
 import de.smartics.properties.api.core.domain.PropertyDescriptorRegistry;
 36  
 import de.smartics.properties.api.core.domain.PropertyExpression;
 37  
 import de.smartics.properties.api.core.domain.PropertyKey;
 38  
 import de.smartics.properties.api.core.domain.PropertyValidationException;
 39  
 import de.smartics.properties.api.core.domain.PropertyValueConversionException;
 40  
 import de.smartics.properties.api.core.domain.PropertyValueResolveException;
 41  
 import de.smartics.properties.spi.config.proxy.PropertyConfigurationObjectBuilder;
 42  
 import de.smartics.properties.spi.config.resolve.PropertyValueResolver;
 43  
 import de.smartics.properties.spi.config.resolve.ResolveConfigurationException;
 44  
 import de.smartics.properties.spi.config.resolve.SimplePropertyValueResolver;
 45  
 import de.smartics.properties.spi.core.context.MandatoryPropertyContext;
 46  
 import de.smartics.properties.spi.core.convert.BeanUtilsPropertyValueConverter;
 47  
 import de.smartics.properties.spi.core.convert.PropertyValueConverter;
 48  
 import de.smartics.properties.spi.core.validate.PropertyValidator;
 49  
 import de.smartics.util.lang.Arguments;
 50  
 import de.smartics.util.lang.BlankArgumentException;
 51  
 import de.smartics.util.lang.NullArgumentException;
 52  
 
 53  
 /**
 54  
  * Abstract implementation of the
 55  
  * {@link de.smartics.properties.api.config.domain.SerializableConfigurationProperties}
 56  
  * interface.
 57  
  */
 58  
 @ThreadSafe
 59  
 public abstract class AbstractConfigurationProperties implements
 60  
     ConfigurationProperties, ConfigurationPropertiesSpi
 61  
 { // NOPMD
 62  
   // ********************************* Fields *********************************
 63  
 
 64  
   // --- constants ------------------------------------------------------------
 65  
 
 66  
   // --- members --------------------------------------------------------------
 67  
 
 68  
   /**
 69  
    * The key that identifies the configuration.
 70  
    *
 71  
    * @serial
 72  
    */
 73  
   private final ConfigurationKey key;
 74  
 
 75  
   /**
 76  
    * The registry to resolve property descriptors.
 77  
    *
 78  
    * @serial
 79  
    */
 80  
   private final PropertyDescriptorRegistry registry;
 81  
 
 82  
   /**
 83  
    * The validator to use on values before they are returned.
 84  
    *
 85  
    * @serial
 86  
    */
 87  0
   private final PropertyValidator validator = new PropertyValidator();
 88  
 
 89  
   /**
 90  
    * The property value converter to and from Strings.
 91  
    *
 92  
    * @serial
 93  
    */
 94  0
   private final PropertyValueConverter converter =
 95  
       new BeanUtilsPropertyValueConverter();
 96  
 
 97  
   /**
 98  
    * The resolver for property value expressions.
 99  
    */
 100  
   private transient PropertyValueResolver resolver;
 101  
 
 102  
   /**
 103  
    * Helper to handle property change listeners.
 104  
    *
 105  
    * @serial
 106  
    */
 107  0
   private final PropertyChangeSupport support = new PropertyChangeSupport(this);
 108  
 
 109  
   // ****************************** Initializer *******************************
 110  
 
 111  
   // ****************************** Constructor ******************************
 112  
 
 113  
   /**
 114  
    * Constructor for serializable subclasses.
 115  
    */
 116  
   protected AbstractConfigurationProperties()
 117  0
   {
 118  0
     this.key = null;
 119  0
     this.registry = null;
 120  0
     this.resolver = null;
 121  0
   }
 122  
 
 123  
   /**
 124  
    * Default constructor.
 125  
    *
 126  
    * @param key the key that identifies the configuration.
 127  
    * @param registry the registry to resolve property descriptors.
 128  
    * @throws NullArgumentException if {@code key} or {@code registry} is
 129  
    *           <code>null</code>.
 130  
    */
 131  
   protected AbstractConfigurationProperties(final ConfigurationKey key,
 132  
       final PropertyDescriptorRegistry registry) throws NullArgumentException
 133  0
   {
 134  0
     Arguments.checkNotNull("key", key);
 135  0
     Arguments.checkNotNull("registry", registry);
 136  
 
 137  0
     this.key = key;
 138  0
     this.registry = registry;
 139  0
     this.resolver = createResolver();
 140  0
   }
 141  
 
 142  
   // ****************************** Inner Classes *****************************
 143  
 
 144  
   // ********************************* Methods ********************************
 145  
 
 146  
   // --- init -----------------------------------------------------------------
 147  
 
 148  
   private SimplePropertyValueResolver createResolver()
 149  
   {
 150  0
     return new SimplePropertyValueResolver(registry, this);
 151  
   }
 152  
 
 153  
   // --- get&set --------------------------------------------------------------
 154  
 
 155  
   @Override
 156  
   public final ConfigurationKey getKey()
 157  
   {
 158  0
     return key;
 159  
   }
 160  
 
 161  
   @Override
 162  
   public final PropertyContext getContext(final PropertyDescriptor descriptor)
 163  
     throws NullPointerException
 164  
   {
 165  0
     Arguments.checkNotNull("descriptor", descriptor);
 166  0
     return new MandatoryPropertyContext(registry.getContext(descriptor),
 167  
         descriptor);
 168  
   }
 169  
 
 170  
   @Override
 171  
   public final PropertiesContext getContext(final Class<?> declaringType)
 172  
     throws NullPointerException
 173  
   {
 174  0
     Arguments.checkNotNull("declaringType", declaringType);
 175  0
     return registry.getContext(declaringType);
 176  
   }
 177  
 
 178  
   /**
 179  
    * Returns the registry to resolve property descriptors.
 180  
    *
 181  
    * @return the registry to resolve property descriptors.
 182  
    */
 183  
   public final PropertyDescriptorRegistry getRegistry()
 184  
   {
 185  0
     return registry;
 186  
   }
 187  
 
 188  
   // --- business -------------------------------------------------------------
 189  
 
 190  
   @Override
 191  
   public final Property getProperty(final String key)
 192  
     throws IllegalArgumentException, UnknownPropertyException
 193  
   {
 194  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key);
 195  0
     return getProperty(descriptor);
 196  
   }
 197  
 
 198  
   @Override
 199  
   public Property getProperty(final String key, final Object defaultValue)
 200  
     throws IllegalArgumentException, UnknownPropertyException
 201  
   {
 202  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key);
 203  0
     return getProperty(descriptor, defaultValue);
 204  
   }
 205  
 
 206  
   @Override
 207  
   public final Property getProperty(final PropertyKey key)
 208  
     throws IllegalArgumentException, UnknownPropertyException
 209  
   {
 210  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key.toString());
 211  0
     return getProperty(descriptor);
 212  
   }
 213  
 
 214  
   @Override
 215  
   public final Property getProperty(final PropertyDescriptor descriptor)
 216  
     throws IllegalArgumentException, UnknownPropertyException
 217  
   {
 218  0
     return getProperty(descriptor, null);
 219  
   }
 220  
 
 221  
   @Override
 222  
   public final <T> T getProperties(final Class<T> propertiesInterface)
 223  
   {
 224  0
     return getProperties(propertiesInterface, toSerializable());
 225  
   }
 226  
 
 227  
   @Override
 228  
   public final <T> T getProperties(final Class<T> propertiesInterface,
 229  
       final SerializableConfigurationProperties configuration)
 230  
   {
 231  0
     final PropertyConfigurationObjectBuilder builder =
 232  
         new PropertyConfigurationObjectBuilder();
 233  0
     return builder.build(propertiesInterface, configuration);
 234  
   }
 235  
 
 236  
   @Override
 237  
   public final Object getPropertyValue(final String key)
 238  
     throws IllegalArgumentException, UnknownPropertyException,
 239  
     PropertyValidationException
 240  
   {
 241  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key);
 242  0
     return getPropertyValue(descriptor, null);
 243  
   }
 244  
 
 245  
   @Override
 246  
   public final Object getPropertyValue(final PropertyKey key)
 247  
     throws IllegalArgumentException, UnknownPropertyException,
 248  
     PropertyValidationException
 249  
   {
 250  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key.toString());
 251  0
     return getPropertyValue(descriptor, null);
 252  
   }
 253  
 
 254  
   @Override
 255  
   public final Object getPropertyValue(final String key,
 256  
       final Object defaultValue) throws NullArgumentException,
 257  
     PropertyValidationException
 258  
   {
 259  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key);
 260  0
     return getPropertyValue(descriptor, defaultValue);
 261  
   }
 262  
 
 263  
   @Override
 264  
   public final String getPropertyValueAsString(final String key)
 265  
     throws NullArgumentException, PropertyValidationException
 266  
   {
 267  0
     return getPropertyValue(key).toString();
 268  
   }
 269  
 
 270  
   @Override
 271  
   public final Object getPropertyValue(final PropertyDescriptor descriptor,
 272  
       final Object defaultValue) throws NullPointerException,
 273  
     PropertyValueConversionException, PropertyValidationException,
 274  
     UnknownPropertyException
 275  
   {
 276  0
     return getResolvedProperty(descriptor, defaultValue).getResolvedValue();
 277  
   }
 278  
 
 279  
   @Override
 280  
   public final String getPropertyValueAsString(final String key,
 281  
       final Object defaultValue) throws NullArgumentException,
 282  
     PropertyValidationException
 283  
   {
 284  0
     return getPropertyValue(key, defaultValue).toString();
 285  
   }
 286  
 
 287  
   @Override
 288  
   public final Object getPropertyValue(final PropertyDescriptor descriptor)
 289  
     throws NullArgumentException, PropertyValidationException
 290  
   {
 291  0
     return getPropertyValue(descriptor, null);
 292  
   }
 293  
 
 294  
   @Override
 295  
   public final String getPropertyValueAsString(
 296  
       final PropertyDescriptor descriptor) throws NullArgumentException,
 297  
     PropertyValidationException
 298  
   {
 299  0
     return getPropertyValue(descriptor, null).toString();
 300  
   }
 301  
 
 302  
   @Override
 303  
   public final String getPropertyValueAsString(
 304  
       final PropertyDescriptor descriptor, final Object defaultValue)
 305  
     throws NullArgumentException, PropertyValidationException
 306  
   {
 307  0
     return getPropertyValue(descriptor, defaultValue).toString();
 308  
   }
 309  
 
 310  
   @Override
 311  
   public final ResolvedProperty getResolvedProperty(final PropertyKey key,
 312  
       final Object defaultValue) throws IllegalArgumentException,
 313  
     UnknownPropertyException, PropertyValidationException
 314  
   {
 315  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key.toString());
 316  0
     return getResolvedProperty(descriptor, defaultValue);
 317  
   }
 318  
 
 319  
   @Override
 320  
   public final ResolvedProperty getResolvedProperty(final String key,
 321  
       final Object defaultValue) throws IllegalArgumentException,
 322  
     UnknownPropertyException, PropertyValidationException
 323  
   {
 324  0
     final PropertyDescriptor descriptor = getPropertyDescriptor(key);
 325  0
     return getResolvedProperty(descriptor, defaultValue);
 326  
   }
 327  
 
 328  
   /**
 329  
    * Returns the property descriptor for a given key.
 330  
    *
 331  
    * @param key the key for which the property descriptor is needed.
 332  
    * @return the property descriptor for the given key.
 333  
    * @throws BlankArgumentException when the key is blank.
 334  
    * @throws PropertyValidationException when the configuration is invalid.
 335  
    */
 336  
   protected final PropertyDescriptor getPropertyDescriptor(final String key)
 337  
     throws BlankArgumentException, PropertyValidationException
 338  
   {
 339  0
     Arguments.checkNotBlank("key", key);
 340  
 
 341  0
     final PropertyDescriptor descriptor = registry.get(key);
 342  0
     if (descriptor == null)
 343  
     {
 344  0
       throw new UnknownPropertyException(getKey(), key);
 345  
     }
 346  0
     return descriptor;
 347  
   }
 348  
 
 349  
   /**
 350  
    * Resolves and converts the given value.
 351  
    *
 352  
    * @param descriptor the property descriptor.
 353  
    * @param defaultValue the default value to use if {@code value} is
 354  
    *          <code>null</code> and there is no default expression.
 355  
    * @param value the value to resolve and convert.
 356  
    * @return the resolved and converted value.
 357  
    * @throws PropertyValueConversionException if the value cannot be converted
 358  
    *           from {@link String} to the target type.
 359  
    * @throws PropertyValidationException if at least on constraint is not met.
 360  
    */
 361  
   protected final Object resolveAndConvert(final PropertyDescriptor descriptor,
 362  
       final Object defaultValue, final Object value)
 363  
     throws PropertyValueConversionException, PropertyValidationException
 364  
   {
 365  0
     Object currentValue = value;
 366  0
     if (currentValue == null)
 367  
     {
 368  0
       currentValue = descriptor.getDefaultExpression();
 369  0
       if (currentValue == null)
 370  
       {
 371  0
         currentValue = defaultValue;
 372  
       }
 373  
     }
 374  
 
 375  0
     if (currentValue instanceof PropertyExpression)
 376  
     {
 377  0
       final PropertyExpression expression = (PropertyExpression) currentValue;
 378  0
       currentValue = expression.getExpression();
 379  
     }
 380  
 
 381  0
     if (currentValue instanceof String)
 382  
     {
 383  0
       currentValue = resolveValue(descriptor, currentValue);
 384  
     }
 385  
 
 386  0
     final Object convertedValue = convert(descriptor, currentValue);
 387  0
     validator.validate(descriptor, convertedValue);
 388  
 
 389  0
     return convertedValue;
 390  
   }
 391  
 
 392  
   private Object resolveValue(final PropertyDescriptor descriptor,
 393  
       final Object value)
 394  
   {
 395  
     try
 396  
     {
 397  0
       final Object resolvedValue = resolver.resolve((String) value);
 398  0
       return resolvedValue;
 399  
     }
 400  0
     catch (final ResolveConfigurationException e)
 401  
     {
 402  0
       throw new PropertyValueResolveException(e, descriptor, e.getExpression());
 403  
     }
 404  
   }
 405  
 
 406  
   private Object convert(final PropertyDescriptor descriptor,
 407  
       final Object currentValue)
 408  
   {
 409  0
     if (currentValue == null)
 410  
     {
 411  0
       return null;
 412  
     }
 413  
 
 414  0
     return converter.convert(descriptor, currentValue);
 415  
   }
 416  
 
 417  
   @Override
 418  
   public final void validate() throws ConfigurationValidationException
 419  
   {
 420  0
     validate(false);
 421  0
   }
 422  
 
 423  
   // ... change listener support ..............................................
 424  
 
 425  
   @Override
 426  
   public final void addPropertyChangeListener(final PropertyKey name,
 427  
       final PropertyChangeListener listener) throws NullPointerException
 428  
   {
 429  0
     support.addPropertyChangeListener(name.toString(), listener);
 430  0
   }
 431  
 
 432  
   @Override
 433  
   public final void removePropertyChangeListener(final PropertyKey name,
 434  
       final PropertyChangeListener listener) throws NullPointerException
 435  
   {
 436  0
     support.removePropertyChangeListener(name.toString(), listener);
 437  0
   }
 438  
 
 439  
   @Override
 440  
   public final void addPropertyChangeListener(
 441  
       final PropertyChangeListener listener) throws NullPointerException
 442  
   {
 443  0
     support.addPropertyChangeListener(listener);
 444  0
   }
 445  
 
 446  
   @Override
 447  
   public final void removePropertyChangeListener(
 448  
       final PropertyChangeListener listener) throws NullPointerException
 449  
   {
 450  0
     support.removePropertyChangeListener(listener);
 451  0
   }
 452  
 
 453  
   /**
 454  
    * Fires the property change event.
 455  
    *
 456  
    * @param name the name of the property.
 457  
    * @param oldValue the old value of the property that has been changed.
 458  
    * @param newValue the new and current value of the property.
 459  
    */
 460  
   protected final void firePropertyChange(final String name,
 461  
       final String oldValue, final String newValue)
 462  
   {
 463  0
     support.firePropertyChange(name, oldValue, newValue);
 464  0
   }
 465  
 
 466  
   // --- object basics --------------------------------------------------------
 467  
 
 468  
   /**
 469  
    * Reads the object from the given stream.
 470  
    *
 471  
    * @param in the stream to read from.
 472  
    * @throws IOException on read problems.
 473  
    * @throws ClassNotFoundException if a class cannot be found.
 474  
    */
 475  
   private void readObject(final ObjectInputStream in) throws IOException,
 476  
     ClassNotFoundException
 477  
   {
 478  0
     in.defaultReadObject();
 479  
 
 480  0
     this.resolver = createResolver();
 481  0
   }
 482  
 
 483  
   /**
 484  
    * Returns the string representation of the object.
 485  
    *
 486  
    * @return the string representation of the object.
 487  
    */
 488  
   @Override
 489  
   public String toString()
 490  
   {
 491  0
     final StringBuilder buffer = new StringBuilder();
 492  
 
 493  0
     buffer.append(key).append(":\n").append("Registry:\n").append(registry);
 494  
 
 495  0
     return buffer.toString();
 496  
   }
 497  
 }