001/** 002 * Copyright (C) 2007-2011, Jens Lehmann 003 * 004 * This file is part of DL-Learner. 005 * 006 * DL-Learner is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation; either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * DL-Learner is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019 020package org.dllearner.configuration.spring.editors; 021 022import com.google.common.collect.ObjectArrays; 023import org.dllearner.core.AnnComponentManager; 024import org.dllearner.core.Component; 025import org.dllearner.core.config.ConfigOption; 026import org.springframework.beans.BeanUtils; 027import org.springframework.beans.BeansException; 028 029import java.beans.PropertyDescriptor; 030import java.beans.PropertyEditor; 031import java.lang.reflect.Field; 032import java.lang.reflect.InvocationTargetException; 033import java.lang.reflect.Method; 034import java.util.*; 035 036public class ConfigHelper { 037 038 public final static Map<Class<?>, Class<?>> map = new HashMap<>(); 039 040 static { 041 map.put(Boolean.class, boolean.class); 042 map.put(Byte.class, byte.class); 043 map.put(Short.class, short.class); 044 map.put(Character.class, char.class); 045 map.put(Integer.class, int.class); 046 map.put(Long.class, long.class); 047 map.put(Float.class, float.class); 048 map.put(Double.class, double.class); 049 } 050 051 /** 052 * Configures the given component by setting the value for the appropriate config option. 053 * @param component the component to be configured 054 * @param configName the name of the config option 055 * @param configValue the value of the config option 056 */ 057 @Deprecated 058 public static <T> void configure(Component component, String configName, T configValue){ 059 List<Field> fields = getAllFields(component); 060 for(Field f : fields){ 061 if(f.isAnnotationPresent(ConfigOption.class)){ 062 if(AnnComponentManager.getName(f).equals(configName)){ 063 try { 064 PropertyEditor editor = PropertyEditor.class.newInstance(); 065 editor.setAsText(configValue.toString()); 066 Method method = component.getClass().getMethod("set" + Character.toUpperCase(f.getName().charAt(0)) + f.getName().substring(1), getClassForObject(editor.getValue())); 067 method.invoke(component, editor.getValue()); 068 } catch (IllegalArgumentException | NoSuchMethodException | SecurityException | InvocationTargetException | IllegalAccessException | InstantiationException e) { 069 e.printStackTrace(); 070 } 071 } 072 073 } 074 } 075 } 076 077 /** 078 * Returns all config options for the given component. 079 * @param component 080 * @return 081 */ 082 public static List<ConfigOption> getConfigOptions(Component component){ 083 return getConfigOptions(component.getClass()); 084 } 085 086 087 /** 088 * 089 * @param component The component to analyse. 090 * @return All config options of the component with their respective value. 091 */ 092 public static Map<Field,Object> getConfigOptionValues(Component component) { 093 Map<Field,Object> optionValues = new HashMap<>(); 094 List<Field> fields = getAllFields(component); 095 for(Field field : fields) { 096 if(field.isAnnotationPresent(ConfigOption.class)) { 097 try { 098 // we invoke the public getter instead of accessing a private field (may cause problem with SecurityManagers) 099 // use Spring BeanUtils TODO: might be unnecessarily slow because we already have the field? 100 PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor( 101 component.getClass(), 102 field.getName() 103 ); 104 Method readMethod = propertyDescriptor.getReadMethod(); 105 if(readMethod == null) { 106 throw new RuntimeException("Getter method is missing for field " + field + " in component " + component); 107 } 108 Object value = readMethod.invoke(component); 109 110 optionValues.put(field, value); 111 } catch (IllegalArgumentException | InvocationTargetException | BeansException | IllegalAccessException e1) { 112 e1.printStackTrace(); 113 } 114 } 115 } 116 return optionValues; 117 } 118 119 /** 120 * Returns all config options for the given component. 121 * @param component 122 * @return 123 */ 124 public static List<ConfigOption> getConfigOptions(Class<? extends Component> component){ 125 List<ConfigOption> options = new ArrayList<>(); 126 127 Field[] fields = component.getDeclaredFields(); 128 for(Field f : fields){ 129 ConfigOption option = f.getAnnotation(ConfigOption.class); 130 if(option != null){ 131 options.add(option); 132 } 133 } 134 135 return options; 136 } 137 138 /** 139 * Returns all config options for the given component. 140 * @param component 141 * @return 142 */ 143 public static Map<Field,Class<?>> getConfigOptionTypes(Class<?> component){ 144 return getConfigOptionTypes(component, true); 145 } 146 147 /** 148 * Returns all config options for the given component. 149 * @param component 150 * @return 151 */ 152 public static Map<Field,Class<?>> getConfigOptionTypes(Class<?> component, boolean useSuperTypes){ 153 Map<Field,Class<?>> optionTypes = new TreeMap<>((o1, o2) -> { 154 return AnnComponentManager.getName(o1).compareTo(AnnComponentManager.getName(o2)); 155 }); 156 Field[] fields = component.getDeclaredFields(); 157 if(useSuperTypes) { 158 if(useSuperTypes) { 159 fields = ObjectArrays.concat(fields, component.getSuperclass().getDeclaredFields(), Field.class); 160 } 161 } 162 for(Field f : fields){ 163 if(f.isAnnotationPresent(ConfigOption.class)) { 164 optionTypes.put(f, f.getType()); 165 } 166 } 167 return optionTypes; 168 } 169 170 /* 171 * returns the declared fields for the class and its superclass. 172 */ 173 private static List<Field> getAllFields(Component component){ 174 List<Field> fields = new ArrayList<>(); 175 fields.addAll(Arrays.asList(component.getClass().getDeclaredFields())); 176 //check also the fields of the super class if exists 177 if(component.getClass().getSuperclass() != null){ 178 fields.addAll(Arrays.asList(component.getClass().getSuperclass().getDeclaredFields())); 179 } 180 return fields; 181 } 182 183 private static Class<?> getClassForObject(Object obj){ 184 if(map.containsKey(obj.getClass())){ 185 return map.get(obj.getClass()); 186 } else { 187 return obj.getClass(); 188 } 189 } 190 191}