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

org.cache2k.xmlConfig.ApplyConfiguration Maven / Gradle / Ivy

The newest version!
package org.cache2k.xmlConfig;

/*
 * #%L
 * cache2k XML configuration
 * %%
 * Copyright (C) 2000 - 2016 headissue GmbH, Munich
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import org.cache2k.core.util.Log;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Read configuration from a pull parser and apply it to the object.
 *
 * @author Jens Wilke
 */
public class ApplyConfiguration {

  private final static String _SETTER_PREFIX = "set";

  private static volatile Map, Map> settersLookupMap =
    new HashMap, Map>();
  private static Map, FieldParser> type2parser = new HashMap, FieldParser>();
  private static Log log = Log.getLog(ApplyConfiguration.class);

  private LinkedList objectStack = new LinkedList();
  private LinkedList> settersStack = new LinkedList>();
  private Object obj;
  private ConfigPullParser parser;
  private Map setters;

  public ApplyConfiguration(final Object _obj, final ConfigPullParser _parser) {
    obj = _obj;
    parser = _parser;
    setters = getSetterMap(obj.getClass());
  }

  public void parse() throws Exception {
    for (;;) {
      int _next = parser.next();
      switch (_next) {
        case ConfigPullParser.END: return;
        case ConfigPullParser.UNNEST:
          if (objectStack.isEmpty()) {
            return;
          }
          obj = objectStack.pop();
          setters = settersStack.pop();
          break;
        case ConfigPullParser.PROPERTY:
          property(parser.getPropertyName(), parser.getPropertyValue());
          break;
      }
    }
  }

  private void property(String _name, String _value) {
    Method m = setters.get(_name);
    if (m == null) {
      log.warn("Unknown configuration property: " + _name);
      return;
    }
    Class params[] = m.getParameterTypes();
    if (params.length == 1) {
      FieldParser p = type2parser.get(params[0]);
      if (p == null) {
        log.warn("Unknown property type, name=" + _name + ", type=" + params[0].getName());
        return;
      }
      try {
        m.invoke(obj, p.parse(_value));
      } catch (Exception ex) {
        log.warn("Exception setting configuration property " + _name, ex);
      }
    }
  }

  static Map getSetterMap(Class c) {
    Map _property2methodMap = settersLookupMap.get(c);
    if (_property2methodMap == null) {
      Map, Map> _copy = new HashMap, Map>(settersLookupMap);
      _copy.put(c,  _property2methodMap = generateSetterLookupMap(c));
      settersLookupMap = _copy;
    }
    return _property2methodMap;
  }

  static Map generateSetterLookupMap(Class c) {
    Map map = new HashMap();
    for (Method m : c.getMethods()) {
      if (m.getName().startsWith(_SETTER_PREFIX) && m.getReturnType() == Void.TYPE && (
          (m.getParameterTypes().length == 1 && type2parser.containsKey(m.getParameterTypes()[0])) ||
          (m.getParameterTypes().length == 2 && m.getParameterTypes()[1] == TimeUnit.class)
        )) {
        map.put(generatePropertyNameFromSetter(m.getName()), m);
      }
    }
    return map;
  }

  static String generatePropertyNameFromSetter(String s) {
    return changeFirstCharToLowerCase(s.substring(_SETTER_PREFIX.length()));
  }

  static String changeFirstCharToLowerCase(String v) {
    return Character.toLowerCase(v.charAt(0)) + v.substring(1);
  }

  private static void addParser(Class _type, FieldParser p) {
    type2parser.put(_type, p);
  }

  private static void addParser(Class _primitiveType, Class _type, FieldParser p) {
    type2parser.put(_primitiveType, p);
    type2parser.put(_type, p);
  }

  static {
    addParser(Integer.TYPE, Integer.class, new FieldParser() {
      @Override
      public Integer parse(final String v) {
        return Integer.valueOf(v);
      }
    });
    addParser(Boolean.TYPE, Boolean.class, new FieldParser() {
      @Override
      public Boolean parse(String v) {
        v = v.toLowerCase();
        return !(
          "off".equals(v) ||
          "false".equals(v) ||
          "disable".equals(v) ||
          "n".equals(v) ||
          "no".equals(v));
      }
    });
    addParser(Long.TYPE, Long.class, new FieldParser() {
      @Override
      public Long parse(final String v) {
        return Long.valueOf(v);
      }
    });
    addParser(String.class, new FieldParser() {
      @Override
      public String parse(final String v) {
        return v;
      }
    });
    addParser(Class.class, new FieldParser() {
      @Override
      public Class parse(final String v) throws Exception {
        return Class.forName(v);
      }
    });

  }

}