Coverage Report - de.smartics.properties.spi.config.proxy.PropertiesProxyInvocationHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
PropertiesProxyInvocationHandler
0%
0/51
0%
0/30
3.091
 
 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.proxy;
 17  
 
 18  
 import java.io.Serializable;
 19  
 import java.lang.reflect.Method;
 20  
 
 21  
 import de.smartics.properties.api.config.domain.SerializableConfigurationProperties;
 22  
 import de.smartics.properties.api.config.domain.UnknownPropertyException;
 23  
 import de.smartics.properties.api.core.annotations.PropertyMetaDataMethod;
 24  
 import de.smartics.properties.api.core.domain.PropertiesContext;
 25  
 import de.smartics.properties.api.core.domain.PropertyDescriptor;
 26  
 import de.smartics.properties.api.core.domain.PropertyKey;
 27  
 import de.smartics.properties.api.core.domain.PropertyValidationException;
 28  
 import de.smartics.properties.spi.core.metadata.PropertyMetaDataParser;
 29  
 import de.smartics.util.lang.Arg;
 30  
 
 31  
 /**
 32  
  * The invocation handler receives every method invocation on the proxy that is
 33  
  * wrapped over the properties interface. It analyzes the intent of this method
 34  
  * call and provides (calculates) the return value. The main task is to detect
 35  
  * whether a value, a property key or a property description has to be returned.
 36  
  * After this decision making the task to calculate the return value is
 37  
  * delegated to a specialized class.
 38  
  */
 39  
 public final class PropertiesProxyInvocationHandler implements
 40  
     java.lang.reflect.InvocationHandler, Serializable
 41  
 {
 42  
   // ********************************* Fields *********************************
 43  
 
 44  
   // --- constants ------------------------------------------------------------
 45  
 
 46  
   /**
 47  
    * The class version identifier.
 48  
    */
 49  
   private static final long serialVersionUID = 1L;
 50  
 
 51  
   // --- members --------------------------------------------------------------
 52  
 
 53  
   /**
 54  
    * To access the properties.
 55  
    *
 56  
    * @serial
 57  
    */
 58  
   private final SerializableConfigurationProperties configurationProperties;
 59  
 
 60  
   // ****************************** Initializer *******************************
 61  
 
 62  
   // ****************************** Constructors ******************************
 63  
 
 64  
   /**
 65  
    * Default constructor.
 66  
    *
 67  
    * @param configurationProperties the configuration properties on that the
 68  
    *          method calls are delegated.
 69  
    * @throws NullPointerException if {@code configurationProperties} is
 70  
    *           <code>null</code>.
 71  
    */
 72  
   public PropertiesProxyInvocationHandler(
 73  
       final SerializableConfigurationProperties configurationProperties)
 74  
     throws NullPointerException
 75  0
   {
 76  0
     this.configurationProperties =
 77  
         Arg.checkNotNull("configurationProperties", configurationProperties);
 78  0
   }
 79  
 
 80  
   // ****************************** Inner Classes *****************************
 81  
 
 82  
   // ********************************* Methods ********************************
 83  
 
 84  
   // --- init -----------------------------------------------------------------
 85  
 
 86  
   // --- get&set --------------------------------------------------------------
 87  
 
 88  
   // --- business -------------------------------------------------------------
 89  
 
 90  
   /**
 91  
    * {@inheritDoc}
 92  
    *
 93  
    * @throws InvalidArgumentsException when arguments are passed. Only no arg
 94  
    *           methods are supported.
 95  
    * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
 96  
    *      java.lang.reflect.Method, java.lang.Object[])
 97  
    */
 98  
   public Object invoke(final Object proxy, final Method method,
 99  
       final Object[] args) throws InvalidArgumentsException
 100  
   {
 101  0
     if (proxy == null)
 102  
     {
 103  0
       return null;
 104  
     }
 105  
 
 106  0
     final String methodName = method.getName();
 107  0
     if ("equals".equals(methodName))
 108  
     {
 109  0
       return handleMethodEquals(proxy, args);
 110  
     }
 111  
 
 112  0
     checkNoArgs(args);
 113  
 
 114  0
     if ("toString".equals(methodName))
 115  
     {
 116  0
       return handleMethodToString(proxy);
 117  
     }
 118  0
     else if ("hashCode".equals(methodName))
 119  
     {
 120  0
       return handleMethodHashCode(proxy);
 121  
     }
 122  
 
 123  0
     return handlePropertyMethod(method);
 124  
   }
 125  
 
 126  
   private Object handlePropertyMethod(final Method method)
 127  
     throws UnknownPropertyException, PropertyValidationException,
 128  
     InvalidArgumentsException
 129  
   {
 130  0
     final Class<?> declaringClass = method.getDeclaringClass();
 131  0
     final PropertiesContext context =
 132  
         configurationProperties.getContext(declaringClass);
 133  0
     final PropertyMetaDataParser parser =
 134  
         PropertyMetaDataParser.create(context);
 135  
 
 136  0
     if (isPropertyKeyMethod(method))
 137  
     {
 138  0
       final Method propertyMethod =
 139  
           PropertyMethodNameUtilities.fetchPropertyMethod(method);
 140  0
       return parser.readKey(propertyMethod);
 141  
     }
 142  0
     else if (isPropertyDescriptorMethod(method))
 143  
     {
 144  0
       final Method propertyMethod =
 145  
           PropertyMethodNameUtilities.fetchPropertyMethod(method);
 146  0
       return parser.readDescriptor(propertyMethod);
 147  
     }
 148  0
     else if (isPropertyMethod(method))
 149  
     {
 150  0
       final PropertyKey key = parser.readKey(method);
 151  0
         final Object propertyValue =
 152  
             configurationProperties.getPropertyValue(key);
 153  0
         return propertyValue;
 154  
     }
 155  
     else
 156  
     {
 157  0
       throw new InvalidArgumentsException(
 158  
           "The method '" + method.getName() + "' of interface '"
 159  
               + method.getDeclaringClass().getCanonicalName()
 160  
               + "' is not a property method, not a property key method and "
 161  
               + "not a property descriptor method.");
 162  
     }
 163  
   }
 164  
 
 165  
   Object handleMethodEquals(final Object proxy, final Object[] args)
 166  
   {
 167  0
     checkOneArg(args);
 168  0
     return proxy == args[0];
 169  
   }
 170  
 
 171  
   private Object handleMethodHashCode(final Object proxy)
 172  
     throws SecurityException
 173  
   {
 174  0
     final Method[] methods = proxy.getClass().getMethods();
 175  0
     int hash = proxy.getClass().getCanonicalName().hashCode();
 176  0
     for (int i = 0; i < methods.length; i++)
 177  
     {
 178  0
       hash = hash * 37 + methods[i].getName().hashCode();
 179  
     }
 180  0
     return hash;
 181  
   }
 182  
 
 183  
   private Object handleMethodToString(final Object proxy)
 184  
     throws SecurityException
 185  
   {
 186  0
     final StringBuilder toStringBuilder =
 187  
         new StringBuilder("Proxy for: ").append(proxy.getClass().getName());
 188  0
     final Method[] methods = proxy.getClass().getMethods();
 189  0
     for (int i = 0; i < methods.length; i++)
 190  
     {
 191  0
       toStringBuilder.append("::").append(methods[i].getName());
 192  
     }
 193  0
     return toStringBuilder.toString();
 194  
   }
 195  
 
 196  
   private boolean isPropertyKeyMethod(final Method m)
 197  
   {
 198  0
     final Class<?> returnType = m.getReturnType();
 199  0
     return PropertyKey.class.equals(returnType);
 200  
   }
 201  
 
 202  
   private boolean isPropertyDescriptorMethod(final Method m)
 203  
   {
 204  0
     final Class<?> returnType = m.getReturnType();
 205  0
     return PropertyDescriptor.class.equals(returnType);
 206  
   }
 207  
 
 208  
   private boolean isPropertyMethod(final Method m)
 209  
   {
 210  0
     return !PropertyMethodNameUtilities.isMethodAnnotatedWithAnnotation(
 211  
         PropertyMetaDataMethod.class, m);
 212  
   }
 213  
 
 214  
   /**
 215  
    * Check that the method called has exactly one arg.
 216  
    *
 217  
    * @param args the method args.
 218  
    */
 219  
   private void checkOneArg(final Object[] args)
 220  
   {
 221  0
     if (args == null || args.length != 1)
 222  
     {
 223  0
       throw new InvalidArgumentsException("Equals need one parameter.");
 224  
     }
 225  0
   }
 226  
 
 227  
   /**
 228  
    * Check that the method called has no args, as only noarg methods are
 229  
    * supported for property methods right now.
 230  
    *
 231  
    * @param args the method args.
 232  
    */
 233  
   private void checkNoArgs(final Object[] args)
 234  
   {
 235  0
     if (args != null && args.length > 0)
 236  
     {
 237  0
       throw new InvalidArgumentsException(
 238  
           "Only methods without arguments are supported for property methods.");
 239  
     }
 240  0
   }
 241  
 
 242  
   // --- object basics --------------------------------------------------------
 243  
 
 244  
 }