[77] | 1 | package com.framsticks.params; |
---|
| 2 | |
---|
| 3 | import com.framsticks.params.types.CompositeParam; |
---|
| 4 | import com.framsticks.params.types.DecimalParam; |
---|
| 5 | import com.framsticks.params.types.FloatParam; |
---|
| 6 | import com.framsticks.params.types.StringParam; |
---|
| 7 | import com.framsticks.util.Casting; |
---|
| 8 | import org.apache.log4j.Logger; |
---|
| 9 | |
---|
| 10 | import javax.lang.model.element.TypeElement; |
---|
| 11 | import java.lang.reflect.*; |
---|
| 12 | import java.util.*; |
---|
| 13 | import java.util.List; |
---|
| 14 | |
---|
| 15 | /** |
---|
| 16 | * The class FramsClass represents the class / schema of connected parameters |
---|
| 17 | * (such as parameters within the class). It differs from C++ version by storing |
---|
| 18 | * information about the class that parameters belong to. |
---|
| 19 | * |
---|
| 20 | * Based loosely on c++ class Param located in cpp/gdk/param.* |
---|
| 21 | * |
---|
| 22 | * @author Jarek Szymczak <name.surname@gmail.com>, Mateusz Jarus (please |
---|
| 23 | * replace name and surname with my personal data) |
---|
| 24 | * |
---|
| 25 | * @author Piotr Sniegowski |
---|
| 26 | */ |
---|
| 27 | public final class FramsClass { |
---|
| 28 | |
---|
| 29 | private final static Logger LOGGER = Logger.getLogger(FramsClass.class.getName()); |
---|
| 30 | |
---|
| 31 | /** |
---|
| 32 | * The Class which represents group. |
---|
| 33 | */ |
---|
| 34 | |
---|
| 35 | /** The offset of the parameter (applied for newly added parameter). */ |
---|
| 36 | protected int fieldsNumber; |
---|
| 37 | |
---|
| 38 | /** The groups. */ |
---|
| 39 | protected List<Group> groups = new ArrayList<Group>(); |
---|
| 40 | |
---|
| 41 | /** |
---|
| 42 | * The param entry map <parameterId, param> (for fast accessing of parameters |
---|
| 43 | * by their name) |
---|
| 44 | */ |
---|
| 45 | protected Map<String, Param> paramEntryMap = new LinkedHashMap<String, Param>(); |
---|
| 46 | |
---|
| 47 | /** The param list (for accessing parameters by offset in O(1) time. */ |
---|
| 48 | protected List<Param> paramList = new ArrayList<Param>(); |
---|
| 49 | |
---|
| 50 | /** The param getId map (for fast lookup of offset based on name */ |
---|
| 51 | protected Map<String, Integer> paramIdMap = new HashMap<String, Integer>(); |
---|
| 52 | |
---|
| 53 | protected String id; |
---|
| 54 | |
---|
| 55 | protected String name; |
---|
| 56 | |
---|
| 57 | protected String description; |
---|
| 58 | |
---|
| 59 | public Collection<Param> getParamEntries() { |
---|
| 60 | return paramEntryMap.values(); |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | public FramsClass() { |
---|
| 64 | } |
---|
| 65 | |
---|
| 66 | public FramsClass(String id, String name, String description) { |
---|
| 67 | this.setId(id); |
---|
| 68 | this.setName(name); |
---|
| 69 | this.setDescription(description); |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | /** |
---|
| 73 | * Adds new param entry. |
---|
| 74 | * |
---|
| 75 | * @param param |
---|
| 76 | * the new param entry |
---|
| 77 | */ |
---|
| 78 | public FramsClass append(Param param) { |
---|
| 79 | paramEntryMap.put(param.getId(), param); |
---|
| 80 | //paramEntryMap.put(param.getInternalId(), param); |
---|
| 81 | paramList.add(param); |
---|
| 82 | try { |
---|
| 83 | Group group = groups.get(param.getGroup()); |
---|
| 84 | if (group != null) { |
---|
| 85 | group.addProperty(param); |
---|
| 86 | } |
---|
| 87 | } catch (IndexOutOfBoundsException ignored) { |
---|
| 88 | |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | return this; |
---|
| 92 | } |
---|
| 93 | |
---|
| 94 | /** |
---|
| 95 | * Adds new group. |
---|
| 96 | */ |
---|
| 97 | public FramsClass appendGroup(Group group) { |
---|
| 98 | groups.add(group); |
---|
| 99 | return this; |
---|
| 100 | } |
---|
| 101 | |
---|
| 102 | public String getDescription() { |
---|
| 103 | return description; |
---|
| 104 | } |
---|
| 105 | |
---|
| 106 | public int getGroupCount() { |
---|
| 107 | return groups.size(); |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | /** |
---|
| 111 | * Gets the group member. |
---|
| 112 | * |
---|
| 113 | * @param gi |
---|
| 114 | * the offset of group |
---|
| 115 | * @param pi |
---|
| 116 | * the offset of member within a group |
---|
| 117 | * @return the pi-th member of group gi |
---|
| 118 | */ |
---|
| 119 | public Param getGroupMember(int gi, int pi) { |
---|
| 120 | if (gi < 0 || pi < 0 || gi >= groups.size()) { |
---|
| 121 | return null; |
---|
| 122 | } |
---|
| 123 | Group group = groups.get(gi); |
---|
| 124 | return (group != null ? group.getProperty(pi) : null); |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | /** |
---|
| 128 | * Gets the group getName. |
---|
| 129 | * |
---|
| 130 | * @param gi |
---|
| 131 | * the offset of group |
---|
| 132 | * @return the group getName |
---|
| 133 | */ |
---|
| 134 | public String getGroupName(int gi) { |
---|
| 135 | if (gi < 0 || gi >= groups.size()) |
---|
| 136 | return null; |
---|
| 137 | return groups.get(gi).name; |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | public String getId() { |
---|
| 141 | return id; |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | public String getName() { |
---|
| 145 | return name; |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | public String getNiceName() { |
---|
| 149 | return name != null ? name : id; |
---|
| 150 | } |
---|
| 151 | |
---|
| 152 | /** |
---|
| 153 | * Gets the param entry. |
---|
| 154 | * |
---|
| 155 | * @param i |
---|
| 156 | * the offset of parameter |
---|
| 157 | * @return the param entry |
---|
| 158 | */ |
---|
| 159 | public Param getParamEntry(int i) { |
---|
| 160 | if (i < 0 || i >= paramList.size()) { |
---|
| 161 | return null; |
---|
| 162 | } |
---|
| 163 | return paramList.get(i); |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | /** |
---|
| 167 | * Gets the param entry. |
---|
| 168 | * |
---|
| 169 | * @param id |
---|
| 170 | * the getId of parameter |
---|
| 171 | * @return the param entry |
---|
| 172 | */ |
---|
| 173 | public Param getParamEntry(String id) { |
---|
| 174 | return paramEntryMap.get(id); |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | public int getParamCount() { |
---|
| 178 | return paramList.size(); |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | @Override |
---|
| 182 | public String toString() { |
---|
| 183 | return id; |
---|
| 184 | } |
---|
| 185 | |
---|
| 186 | public static FramsClass getFramsClass() { |
---|
| 187 | return new FramsClass("class", "class", null) |
---|
| 188 | .append(new ParamBuilder().setId("name").setName("Name").setType(StringParam.class).build()) |
---|
| 189 | .append(new ParamBuilder().setId("id").setName("id").setType(StringParam.class).build()) |
---|
| 190 | .append(new ParamBuilder().setId("desc").setName("Description").setType(StringParam.class).build()); |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | public void setId(String id) { |
---|
| 194 | this.id = id; |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | public void setName(String name) { |
---|
| 198 | this.name = name; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | public void setDescription(String description) { |
---|
| 202 | this.description = description; |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | public static String getParamTypeForNativeType(Type type) { |
---|
| 206 | if (type instanceof ParameterizedType) { |
---|
| 207 | ParameterizedType p = (ParameterizedType) type; |
---|
| 208 | Type rawType = p.getRawType(); |
---|
| 209 | if (rawType.equals(Map.class)) { |
---|
| 210 | Type containedType = p.getActualTypeArguments()[1]; |
---|
| 211 | //TODO uid should be passed along during construction |
---|
| 212 | if (containedType instanceof Class) { |
---|
| 213 | return "l " + ((Class) containedType).getCanonicalName() + " name"; |
---|
| 214 | } |
---|
| 215 | } |
---|
| 216 | return null; |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | if (type.equals(Integer.class)) { |
---|
| 220 | return "d"; |
---|
| 221 | } |
---|
| 222 | if (type.equals(String.class)) { |
---|
| 223 | return "s"; |
---|
| 224 | } |
---|
| 225 | if (type.equals(Double.class)) { |
---|
| 226 | return "f"; |
---|
| 227 | } |
---|
| 228 | if (type instanceof Class) { |
---|
| 229 | return "o " + ((Class) type).getCanonicalName(); |
---|
| 230 | } |
---|
| 231 | return null; |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | public static final String GENERATE_HELP_PREFIX = "automatically generated from: "; |
---|
| 235 | |
---|
| 236 | |
---|
| 237 | |
---|
| 238 | public static class Constructor { |
---|
| 239 | protected final FramsClass result; |
---|
| 240 | protected Class currentClass; |
---|
| 241 | public Constructor(Class src, String name) { |
---|
| 242 | result = new FramsClass(name, name, GENERATE_HELP_PREFIX + src.toString()); |
---|
| 243 | currentClass = src; |
---|
| 244 | while (currentClass != null) { |
---|
| 245 | try { |
---|
| 246 | currentClass.getMethod("constructFramsClass", Constructor.class).invoke(null, this); |
---|
| 247 | } catch (Exception ignored) { |
---|
| 248 | } |
---|
| 249 | currentClass = currentClass.getSuperclass(); |
---|
| 250 | } |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | public final FramsClass getResult() { |
---|
| 254 | return result; |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | public Constructor method(String name, Class<?> ... arguments) { |
---|
| 258 | try { |
---|
| 259 | Method method = currentClass.getMethod(name, arguments); |
---|
| 260 | if (!Modifier.isPublic(method.getModifiers())) { |
---|
| 261 | return this; |
---|
| 262 | } |
---|
| 263 | String returnParamClass = getParamTypeForNativeType(method.getGenericReturnType()); |
---|
| 264 | if (returnParamClass == null) { |
---|
| 265 | return this; |
---|
| 266 | } |
---|
| 267 | Class[] args = method.getParameterTypes(); |
---|
| 268 | if (args.length == 0) { |
---|
| 269 | if (method.getName().startsWith("get")) { |
---|
| 270 | String fieldName = method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4); |
---|
| 271 | Param param = new ParamBuilder().setType(returnParamClass).setName(fieldName).setId(fieldName).setHelp(GENERATE_HELP_PREFIX + method.toString()).build(); |
---|
| 272 | assert param != null; |
---|
| 273 | result.append(param); |
---|
| 274 | return this; |
---|
| 275 | } |
---|
| 276 | return this; |
---|
| 277 | } |
---|
| 278 | return this; |
---|
| 279 | } catch (NoSuchMethodException e) { |
---|
| 280 | LOGGER.fatal("method " + name + " was not found in " + currentClass.toString()); |
---|
| 281 | } |
---|
| 282 | return this; |
---|
| 283 | } |
---|
| 284 | public Constructor field(String name) { |
---|
| 285 | try { |
---|
| 286 | Field field = currentClass.getField(name); |
---|
| 287 | if (!Modifier.isPublic(field.getModifiers())) { |
---|
| 288 | return this; |
---|
| 289 | } |
---|
| 290 | String paramClass = getParamTypeForNativeType(field.getGenericType()); |
---|
| 291 | if (paramClass == null) { |
---|
| 292 | return this; |
---|
| 293 | } |
---|
| 294 | Param param = new ParamBuilder().setType(paramClass).setName(field.getName()).setId(field.getName()).setHelp(GENERATE_HELP_PREFIX + field.toString()).build(); |
---|
| 295 | assert param != null; |
---|
| 296 | result.append(param); |
---|
| 297 | return this; |
---|
| 298 | } catch (NoSuchFieldException e) { |
---|
| 299 | LOGGER.fatal("field " + name + " was not found in " + currentClass.toString()); |
---|
| 300 | } |
---|
| 301 | return this; |
---|
| 302 | } |
---|
| 303 | } |
---|
| 304 | } |
---|