All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.scalecube.config.ObjectConfigPropertyImpl Maven / Gradle / Ivy

package io.scalecube.config;

import io.scalecube.config.source.LoadedConfigProperty;
import io.scalecube.config.utils.ThrowableUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * Implementation of {@link ObjectConfigProperty}.
 *
 * @param  type of the property value
 */
class ObjectConfigPropertyImpl extends AbstractConfigProperty
    implements ObjectConfigProperty {

  @SuppressWarnings("rawtypes")
  ObjectConfigPropertyImpl(
      Map bindingMap,
      Class cfgClass,
      Map propertyMap,
      Map> propertyCallbackMap) {

    super(cfgClass.getName(), cfgClass);

    List propertyFields = toPropertyFields(bindingMap, cfgClass);
    setPropertyCallback(computePropertyCallback(cfgClass, propertyFields, propertyCallbackMap));

    computeValue(
        propertyFields.stream()
            .map(ObjectPropertyField::getPropertyName)
            .filter(propertyMap::containsKey)
            .map(propertyMap::get)
            .collect(Collectors.toList()));
  }

  @Override
  public T value(T defaultValue) {
    return value().orElse(defaultValue);
  }

  private List toPropertyFields(
      Map bindingMap, Class cfgClass) {
    List propertyFields = new ArrayList<>(bindingMap.size());
    for (String fieldName : bindingMap.keySet()) {
      Field field;
      try {
        field = cfgClass.getDeclaredField(fieldName);
      } catch (NoSuchFieldException e) {
        throw ThrowableUtil.propagate(e);
      }
      int modifiers = field.getModifiers();
      if (!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
        propertyFields.add(new ObjectPropertyField(field, bindingMap.get(fieldName)));
      }
    }
    return propertyFields;
  }

  private PropertyCallback computePropertyCallback(
      Class cfgClass,
      List propertyFields,
      Map> propertyCallbackMap) {

    PropertyCallback propertyCallback =
        new PropertyCallback<>(
            list -> ObjectPropertyParser.parseObject(list, propertyFields, cfgClass));

    List propertyNames =
        propertyFields.stream()
            .map(ObjectPropertyField::getPropertyName)
            .collect(Collectors.toList());

    // ensure that only one propertyCallback instance will be shared among instances of the same
    // type
    synchronized (propertyCallbackMap) {
      propertyNames.forEach(
          propName -> {
            propertyCallbackMap.putIfAbsent(propName, new ConcurrentHashMap<>());
            Map callbackMap = propertyCallbackMap.get(propName);
            callbackMap.putIfAbsent(propertyClass, propertyCallback);
          });
    }

    // noinspection unchecked
    return propertyCallbackMap.entrySet().stream()
        .filter(e -> propertyNames.contains(e.getKey()))
        .map(Map.Entry::getValue)
        .filter(callbackMap -> callbackMap.containsKey(propertyClass))
        .map(callbackMap -> callbackMap.get(propertyClass))
        .collect(Collectors.toSet())
        .iterator()
        .next();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy