1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.failurehandler.value;
  25 
  26 import jdk.test.failurehandler.Utils;
  27 
  28 import java.lang.reflect.Field;
  29 import java.lang.reflect.Modifier;
  30 import java.util.Objects;
  31 import java.util.Properties;
  32 
  33 public final class ValueHandler {
  34     public static <T> void apply(T object, Properties properties,
  35                                  String prefix) throws InvalidValueException {
  36         Objects.requireNonNull(object, "object cannot be null");
  37         Objects.requireNonNull(properties, "properties cannot be null");
  38         Class<?> aClass = object.getClass();
  39         while (aClass != null) {
  40             for (Field field : aClass.getDeclaredFields()) {
  41                 Value p = field.getAnnotation(Value.class);
  42                 if (p != null) {
  43                     applyToField(p, object, field, properties, prefix);
  44                 } else {
  45                     SubValues sub
  46                             = field.getAnnotation(SubValues.class);
  47                     if (sub != null) {
  48                         getAccess(field);
  49                         try {
  50                             apply(field.get(object), properties,
  51                                     Utils.prependPrefix(prefix, sub.prefix()));
  52                         } catch (IllegalAccessException e) {
  53                             throw new InvalidValueException(String.format(
  54                                     "can't apply sub properties to %s.",
  55                                     field.getName()));
  56                         }
  57                     }
  58                 }
  59             }
  60             aClass = aClass.getSuperclass();
  61         }
  62     }
  63 
  64     private static void applyToField(Value property, Object object,
  65                 Field field, Properties properties, String prefix)
  66             throws InvalidValueException {
  67         getAccess(field);
  68         if (Modifier.isFinal(field.getModifiers())) {
  69             throw new InvalidValueException(
  70                     String.format("field '%s' is final", field));
  71         }
  72         String name = Utils.prependPrefix(prefix, property.name());
  73         String value = getProperty(properties, prefix, property.name());
  74         if (value == null) {
  75             DefaultValue defaultValue
  76                     = field.getAnnotation(DefaultValue.class);
  77             value = defaultValue == null ? null : defaultValue.value();
  78         }
  79         if (value == null) {
  80             throw new InvalidValueException(String.format(
  81                     "can't set '%s', because properties don't have '%s'.",
  82                     field.getName(), name));
  83         }
  84         String delimiter = getProperty(properties,
  85                 Utils.prependPrefix(prefix, property.name()), "delimiter");
  86         delimiter = delimiter == null ? " " : delimiter;
  87         Class<? extends ValueParser> parserClass = property.parser();
  88         try {
  89             field.set(object, parserClass.newInstance().parse(
  90                     field.getType(), value, delimiter));
  91         } catch (ReflectiveOperationException | IllegalArgumentException e) {
  92             throw new InvalidValueException(
  93                     String.format("can't set field '%s' : %s",
  94                             field.getName(), e.getMessage()), e);
  95         }
  96     }
  97 
  98     private static String getProperty(Properties properties,
  99                                       String prefix, String name) {
 100         if (prefix == null || prefix.isEmpty()) {
 101             return properties.getProperty(name);
 102         }
 103         int index = prefix.length();
 104         do {
 105             String value = properties.getProperty(
 106                     Utils.prependPrefix(prefix.substring(0, index), name));
 107             if (value != null) {
 108                 return value;
 109             }
 110             index = prefix.lastIndexOf('.', index - 1);
 111         } while (index > 0);
 112         return  properties.getProperty(name);
 113     }
 114 
 115     private static void getAccess(Field field) {
 116         int modifiers = field.getModifiers();
 117         if (!Modifier.isPublic(modifiers)) {
 118             field.setAccessible(true);
 119         }
 120     }
 121 
 122 }