package com.framsticks.params; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import com.framsticks.params.annotations.AutoAppendAnnotation; import com.framsticks.params.annotations.FramsClassAnnotation; import com.framsticks.params.annotations.ParamAnnotation; import com.framsticks.parsers.FileSource; import com.framsticks.parsers.Loaders; import com.framsticks.util.lang.Strings; @FramsClassAnnotation(id = "class", name = "class") public class FramsClassBuilder { private static final Logger log = Logger.getLogger(FramsClassBuilder.class); public static String getName(FramsClassAnnotation fca, Class javaClass) { return fca.name().equals("") ? javaClass.getSimpleName() : fca.name(); } public static String getId(FramsClassAnnotation fca, Class javaClass) { return fca.id().equals("") ? javaClass.getSimpleName() : fca.id(); } public static String getParamTypeForNativeType(Type type) { if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; Type rawType = p.getRawType(); Type containedType = null; //TODO make implementation here boolean map = false; if (rawType.equals(Map.class)) { containedType = p.getActualTypeArguments()[1]; map = true; } else if (rawType.equals(List.class)) { containedType = p.getActualTypeArguments()[0]; } if (!(containedType instanceof Class)) { return null; } Class containedClass = (Class) containedType; StringBuilder b = new StringBuilder(); b.append("l "); FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class); if (fca == null) { log.error("the class is not annotated: " + containedClass); return null; } b.append(getName(fca, containedClass)); if (map) { b.append(" name"); } return b.toString(); } if (type instanceof Class) { Class cl = (Class) type; // TODO: future support for enum // if (cl.isEnum()) { // Class> enumType = (Class>) cl; // Enum[] enums = enumType.getEnumConstants(); // StringBuilder b = new StringBuilder(); // b.append("d 0 ").append(enums.length - 1).append(" 0 "); // for (Enum e : enums) { // b.append("~").append(e.name()); // } // return b.toString(); // } if (cl.equals(Integer.class) || cl.equals(int.class)) { return "d"; } if (cl.equals(String.class)) { return "s"; } if (cl.equals(Double.class) || cl.equals(double.class)) { return "f"; } if (cl.equals(Boolean.class) || cl.equals(boolean.class)) { return "d 0 1"; } if (cl.equals(Object.class)) { return "x"; } return "o " + ((Class) type).getCanonicalName(); } throw new ConstructionException().msg("failed to find framsticks for native type").arg("type", type); } public static final String GENERATE_HELP_PREFIX = "automatically generated from: "; public static FramsClass readFromStream(InputStream stream) { return Loaders.loadFramsClass(new FileSource(stream)); } // public static Class getParamType(@Nonnull Class c) { // if (c.equals(Integer.class)) { // return DecimalParam.class; // } // if (c.equals(Double.class)) { // return FloatParam.class; // } // if (c.equals(String.class)) { // return StringParam.class; // } // if (c.equals(Object.class)) { // return UniversalParam.class; // } // return null; // } public static String extractIdOf(Member member) { if (member instanceof Field) { return member.getName(); } if (member instanceof Method) { Method m = (Method) member; String n = m.getName(); int argsNum = m.getParameterTypes().length; if (argsNum == 0) { return n.startsWith("get") ? Strings.uncapitalize(n.substring(3)) : n; } if (argsNum == 1) { return n.startsWith("set") ? Strings.uncapitalize(n.substring(3)) : n; } log.error("invalid number of arguments"); return null; } log.error("invalid kind of member"); return null; } public static String getName(ParamAnnotation annotation, Member member) { return annotation.name().equals("") ? Strings.capitalize(extractIdOf(member)) : annotation.name(); } public static String getId(ParamAnnotation annotation, Member member) { return annotation.id().equals("") ? extractIdOf(member) : annotation.id(); } public static ParamBuilder fill(ParamBuilder builder, Member member, ParamAnnotation annotation) { return builder .id(getId(annotation, member)) .name(getName(annotation, member)); } public static Map, FramsClass> synchronizedCacheForBasedOnForJavaClass = Collections.synchronizedMap(new HashMap, FramsClass>()); public FramsClass forClass(Class javaClass) throws ConstructionException { FramsClass result = synchronizedCacheForBasedOnForJavaClass.get(javaClass); if (result != null) { return result; } log.info("building for class " + javaClass); FramsClassAnnotation fca = javaClass.getAnnotation(FramsClassAnnotation.class); if (fca == null) { throw new ConstructionException().msg("java class is not annotated with FramsClassAnnotation").arg("java", javaClass); } id(getId(fca, javaClass)); name(getName(fca, javaClass)); Map candidates = ParamCandidate.getAllCandidates(javaClass); for (ParamCandidate pc : candidates.values()) { param(Param.build().id(pc.getId()).name(pc.getName()).type(getParamTypeForNativeType(pc.getType())).flags(pc.getFlags())); } result = finish(); synchronizedCacheForBasedOnForJavaClass.put(javaClass, result); return result; } protected String id; protected String name; protected String description; protected final List params = new LinkedList<>(); protected List groups = new ArrayList(); @ParamAnnotation public FramsClassBuilder id(String id) { this.id = id; return this; } @ParamAnnotation public FramsClassBuilder name(String name) { this.name = name; return this; } public FramsClassBuilder idAndName(String v) { this.id = v; this.name = v; return this; } @ParamAnnotation(id = "desc") public FramsClassBuilder description(String description) { this.description = description; return this; } public FramsClassBuilder() { } public FramsClass finish() { return new FramsClass(id, name, description, params, groups); } public FramsClassBuilder append(Param param) { params.add(param); return this; } @AutoAppendAnnotation public FramsClassBuilder param(ParamBuilder builder) { return append(builder.finish()); } @AutoAppendAnnotation public FramsClassBuilder group(Group group) { groups.add(group); return this; } /** * @return the id */ @ParamAnnotation public String getId() { return id; } /** * @return the name */ @ParamAnnotation public String getName() { return name; } /** * @return the description */ @ParamAnnotation(id = "desc") public String getDescription() { return description; } public FramsClassBuilder group(String group) { return group(new Group(group)); } public ParamBuilder param(String id) { return new ParamBuilder(this).id(id); } }